From 99929de0506ca78419163476d3506fc47698afd2 Mon Sep 17 00:00:00 2001 From: Brian Tiger Chow Date: Mon, 12 Jan 2015 11:01:15 -0800 Subject: [PATCH 001/414] go-ipfs-config: refactor(repo/config) move config under repo --- config/config.go | 219 +++++++++++++++++++++++++++++++++++++++++ config/config_test.go | 24 +++++ config/serialize.go | 144 +++++++++++++++++++++++++++ config/version_test.go | 36 +++++++ 4 files changed, 423 insertions(+) create mode 100644 config/config.go create mode 100644 config/config_test.go create mode 100644 config/serialize.go create mode 100644 config/version_test.go diff --git a/config/config.go b/config/config.go new file mode 100644 index 00000000000..d33e4d36de0 --- /dev/null +++ b/config/config.go @@ -0,0 +1,219 @@ +// package config implements the ipfs config file datastructures and utilities. +package config + +import ( + "encoding/base64" + "errors" + "os" + "path/filepath" + "strings" + + ma "github.com/jbenet/go-ipfs/Godeps/_workspace/src/github.com/jbenet/go-multiaddr" + mh "github.com/jbenet/go-ipfs/Godeps/_workspace/src/github.com/jbenet/go-multihash" + + ic "github.com/jbenet/go-ipfs/p2p/crypto" + u "github.com/jbenet/go-ipfs/util" + "github.com/jbenet/go-ipfs/util/debugerror" +) + +var log = u.Logger("config") + +// Identity tracks the configuration of the local node's identity. +type Identity struct { + PeerID string + PrivKey string +} + +// Logs tracks the configuration of the event logger +type Logs struct { + Filename string + MaxSizeMB uint64 + MaxBackups uint64 + MaxAgeDays uint64 +} + +// Datastore tracks the configuration of the datastore. +type Datastore struct { + Type string + Path string +} + +// Addresses stores the (string) multiaddr addresses for the node. +type Addresses struct { + Swarm []string // addresses for the swarm network + API string // address for the local API (RPC) + Gateway string // address to listen on for IPFS HTTP object gateway +} + +// Mounts stores the (string) mount points +type Mounts struct { + IPFS string + IPNS string +} + +// BootstrapPeer is a peer used to bootstrap the network. +type BootstrapPeer struct { + Address string + PeerID string // until multiaddr supports ipfs, use another field. +} + +func (bp *BootstrapPeer) String() string { + return bp.Address + "/" + bp.PeerID +} + +func ParseBootstrapPeer(addr string) (BootstrapPeer, error) { + // to be replaced with just multiaddr parsing, once ptp is a multiaddr protocol + idx := strings.LastIndex(addr, "/") + if idx == -1 { + return BootstrapPeer{}, errors.New("invalid address") + } + addrS := addr[:idx] + peeridS := addr[idx+1:] + + // make sure addrS parses as a multiaddr. + if len(addrS) > 0 { + maddr, err := ma.NewMultiaddr(addrS) + if err != nil { + return BootstrapPeer{}, err + } + + addrS = maddr.String() + } + + // make sure idS parses as a peer.ID + _, err := mh.FromB58String(peeridS) + if err != nil { + return BootstrapPeer{}, err + } + + return BootstrapPeer{ + Address: addrS, + PeerID: peeridS, + }, nil +} + +func ParseBootstrapPeers(addrs []string) ([]BootstrapPeer, error) { + peers := make([]BootstrapPeer, len(addrs)) + var err error + for i, addr := range addrs { + peers[i], err = ParseBootstrapPeer(addr) + if err != nil { + return nil, err + } + } + return peers, nil +} + +// Tour stores the ipfs tour read-list and resume point +type Tour struct { + Last string // last tour topic read + // Done []string // all topics done so far +} + +// Config is used to load IPFS config files. +type Config struct { + Identity Identity // local node's peer identity + Datastore Datastore // local node's storage + Addresses Addresses // local node's addresses + Mounts Mounts // local node's mount points + Version Version // local node's version management + Bootstrap []BootstrapPeer // local nodes's bootstrap peers + Tour Tour // local node's tour position + Logs Logs // local node's event log configuration +} + +// DefaultPathRoot is the path to the default config dir location. +const DefaultPathRoot = "~/.go-ipfs" + +// DefaultConfigFile is the filename of the configuration file +const DefaultConfigFile = "config" + +// DefaultDataStoreDirectory is the directory to store all the local IPFS data. +const DefaultDataStoreDirectory = "datastore" + +// EnvDir is the environment variable used to change the path root. +const EnvDir = "IPFS_DIR" + +// LogsDefaultDirectory is the directory to store all IPFS event logs. +var LogsDefaultDirectory = "logs" + +// PathRoot returns the default configuration root directory +func PathRoot() (string, error) { + dir := os.Getenv(EnvDir) + var err error + if len(dir) == 0 { + dir, err = u.TildeExpansion(DefaultPathRoot) + } + return dir, err +} + +// Path returns the path `extension` relative to the configuration root. If an +// empty string is provided for `configroot`, the default root is used. +func Path(configroot, extension string) (string, error) { + if len(configroot) == 0 { + dir, err := PathRoot() + if err != nil { + return "", err + } + return filepath.Join(dir, extension), nil + + } + return filepath.Join(configroot, extension), nil +} + +// DataStorePath returns the default data store path given a configuration root +// (set an empty string to have the default configuration root) +func DataStorePath(configroot string) (string, error) { + return Path(configroot, DefaultDataStoreDirectory) +} + +// LogsPath returns the default path for event logs given a configuration root +// (set an empty string to have the default configuration root) +func LogsPath(configroot string) (string, error) { + return Path(configroot, LogsDefaultDirectory) +} + +// Filename returns the configuration file path given a configuration root +// directory. If the configuration root directory is empty, use the default one +func Filename(configroot string) (string, error) { + return Path(configroot, DefaultConfigFile) +} + +// DecodePrivateKey is a helper to decode the users PrivateKey +func (i *Identity) DecodePrivateKey(passphrase string) (ic.PrivKey, error) { + pkb, err := base64.StdEncoding.DecodeString(i.PrivKey) + if err != nil { + return nil, err + } + + // currently storing key unencrypted. in the future we need to encrypt it. + // TODO(security) + return ic.UnmarshalPrivateKey(pkb) +} + +// Load reads given file and returns the read config, or error. +func Load(filename string) (*Config, error) { + // if nothing is there, fail. User must run 'ipfs init' + if !u.FileExists(filename) { + return nil, debugerror.New("ipfs not initialized, please run 'ipfs init'") + } + + var cfg Config + err := ReadConfigFile(filename, &cfg) + if err != nil { + return nil, err + } + + // tilde expansion on datastore path + cfg.Datastore.Path, err = u.TildeExpansion(cfg.Datastore.Path) + if err != nil { + return nil, err + } + + return &cfg, err +} + +// Set sets the value of a particular config key +func Set(filename, key, value string) error { + return WriteConfigKey(filename, key, value) +} diff --git a/config/config_test.go b/config/config_test.go new file mode 100644 index 00000000000..c891d6c514b --- /dev/null +++ b/config/config_test.go @@ -0,0 +1,24 @@ +package config + +import ( + "testing" +) + +func TestConfig(t *testing.T) { + const filename = ".ipfsconfig" + const dsPath = "/path/to/datastore" + cfgWritten := new(Config) + cfgWritten.Datastore.Path = dsPath + err := WriteConfigFile(filename, cfgWritten) + if err != nil { + t.Error(err) + } + cfgRead, err := Load(filename) + if err != nil { + t.Error(err) + return + } + if cfgWritten.Datastore.Path != cfgRead.Datastore.Path { + t.Fail() + } +} diff --git a/config/serialize.go b/config/serialize.go new file mode 100644 index 00000000000..b71d945b0bb --- /dev/null +++ b/config/serialize.go @@ -0,0 +1,144 @@ +package config + +import ( + "encoding/json" + "fmt" + "io" + "os" + "path/filepath" + "strings" +) + +// ReadConfigFile reads the config from `filename` into `cfg`. +func ReadConfigFile(filename string, cfg interface{}) error { + f, err := os.Open(filename) + if err != nil { + return err + } + defer f.Close() + + if err := Decode(f, cfg); err != nil { + return fmt.Errorf("Failure to decode config: %s", err) + } + return nil +} + +// WriteConfigFile writes the config from `cfg` into `filename`. +func WriteConfigFile(filename string, cfg interface{}) error { + err := os.MkdirAll(filepath.Dir(filename), 0775) + if err != nil { + return err + } + + f, err := os.Create(filename) + if err != nil { + return err + } + defer f.Close() + + return Encode(f, cfg) +} + +// WriteFile writes the buffer at filename +func WriteFile(filename string, buf []byte) error { + err := os.MkdirAll(filepath.Dir(filename), 0775) + if err != nil { + return err + } + + f, err := os.Create(filename) + if err != nil { + return err + } + defer f.Close() + + _, err = f.Write(buf) + return err +} + +// HumanOutput gets a config value ready for printing +func HumanOutput(value interface{}) ([]byte, error) { + s, ok := value.(string) + if ok { + return []byte(strings.Trim(s, "\n")), nil + } + return Marshal(value) +} + +// Marshal configuration with JSON +func Marshal(value interface{}) ([]byte, error) { + // need to prettyprint, hence MarshalIndent, instead of Encoder + return json.MarshalIndent(value, "", " ") +} + +// Encode configuration with JSON +func Encode(w io.Writer, value interface{}) error { + // need to prettyprint, hence MarshalIndent, instead of Encoder + buf, err := Marshal(value) + if err != nil { + return err + } + + _, err = w.Write(buf) + return err +} + +// Decode configuration with JSON +func Decode(r io.Reader, value interface{}) error { + return json.NewDecoder(r).Decode(value) +} + +// ReadConfigKey retrieves only the value of a particular key +func ReadConfigKey(filename, key string) (interface{}, error) { + var cfg interface{} + if err := ReadConfigFile(filename, &cfg); err != nil { + return nil, err + } + + var ok bool + cursor := cfg + parts := strings.Split(key, ".") + for i, part := range parts { + cursor, ok = cursor.(map[string]interface{})[part] + if !ok { + sofar := strings.Join(parts[:i], ".") + return nil, fmt.Errorf("%s key has no attributes", sofar) + } + } + return cursor, nil +} + +// WriteConfigKey writes the value of a particular key +func WriteConfigKey(filename, key string, value interface{}) error { + var cfg interface{} + if err := ReadConfigFile(filename, &cfg); err != nil { + return err + } + + var ok bool + var mcursor map[string]interface{} + cursor := cfg + + parts := strings.Split(key, ".") + for i, part := range parts { + mcursor, ok = cursor.(map[string]interface{}) + if !ok { + sofar := strings.Join(parts[:i], ".") + return fmt.Errorf("%s key is not a map", sofar) + } + + // last part? set here + if i == (len(parts) - 1) { + mcursor[part] = value + break + } + + cursor, ok = mcursor[part] + if !ok { // create map if this is empty + mcursor[part] = map[string]interface{}{} + cursor = mcursor[part] + } + } + + return WriteConfigFile(filename, cfg) +} diff --git a/config/version_test.go b/config/version_test.go new file mode 100644 index 00000000000..37160c47896 --- /dev/null +++ b/config/version_test.go @@ -0,0 +1,36 @@ +package config + +import ( + "strings" + "testing" +) + +func TestAutoUpdateValues(t *testing.T) { + var tval struct { + AutoUpdate AutoUpdateSetting + } + tests := []struct { + input string + val AutoUpdateSetting + err error + }{ + {`{"hello":123}`, AutoUpdateNever, nil}, // zero value + {`{"AutoUpdate": "never"}`, AutoUpdateNever, nil}, + {`{"AutoUpdate": "patch"}`, AutoUpdatePatch, nil}, + {`{"AutoUpdate": "minor"}`, AutoUpdateMinor, nil}, + {`{"AutoUpdate": "major"}`, AutoUpdateMajor, nil}, + {`{"AutoUpdate": "blarg"}`, AutoUpdateMinor, ErrUnknownAutoUpdateSetting}, + } + + for i, tc := range tests { + err := Decode(strings.NewReader(tc.input), &tval) + if err != tc.err { + t.Fatalf("%d failed - got err %q wanted %v", i, err, tc.err) + } + + if tval.AutoUpdate != tc.val { + t.Fatalf("%d failed - got val %q where we wanted %q", i, tval.AutoUpdate, tc.val) + } + } + +} From 20cc7a451b66054dca1e5e17f5ae54ac73b5c298 Mon Sep 17 00:00:00 2001 From: Brian Tiger Chow Date: Mon, 12 Jan 2015 15:00:03 -0800 Subject: [PATCH 002/414] go-ipfs-config: refactor(config, repo): all writes go through FSRepo. next: privatize these --- config/config.go | 34 ++++------ config/config_test.go | 24 ------- config/serialize.go | 144 ----------------------------------------- config/version_test.go | 5 +- 4 files changed, 13 insertions(+), 194 deletions(-) delete mode 100644 config/config_test.go delete mode 100644 config/serialize.go diff --git a/config/config.go b/config/config.go index d33e4d36de0..939c4564c44 100644 --- a/config/config.go +++ b/config/config.go @@ -3,6 +3,7 @@ package config import ( "encoding/base64" + "encoding/json" "errors" "os" "path/filepath" @@ -13,7 +14,6 @@ import ( ic "github.com/jbenet/go-ipfs/p2p/crypto" u "github.com/jbenet/go-ipfs/util" - "github.com/jbenet/go-ipfs/util/debugerror" ) var log = u.Logger("config") @@ -191,29 +191,17 @@ func (i *Identity) DecodePrivateKey(passphrase string) (ic.PrivKey, error) { return ic.UnmarshalPrivateKey(pkb) } -// Load reads given file and returns the read config, or error. -func Load(filename string) (*Config, error) { - // if nothing is there, fail. User must run 'ipfs init' - if !u.FileExists(filename) { - return nil, debugerror.New("ipfs not initialized, please run 'ipfs init'") +// HumanOutput gets a config value ready for printing +func HumanOutput(value interface{}) ([]byte, error) { + s, ok := value.(string) + if ok { + return []byte(strings.Trim(s, "\n")), nil } - - var cfg Config - err := ReadConfigFile(filename, &cfg) - if err != nil { - return nil, err - } - - // tilde expansion on datastore path - cfg.Datastore.Path, err = u.TildeExpansion(cfg.Datastore.Path) - if err != nil { - return nil, err - } - - return &cfg, err + return Marshal(value) } -// Set sets the value of a particular config key -func Set(filename, key, value string) error { - return WriteConfigKey(filename, key, value) +// Marshal configuration with JSON +func Marshal(value interface{}) ([]byte, error) { + // need to prettyprint, hence MarshalIndent, instead of Encoder + return json.MarshalIndent(value, "", " ") } diff --git a/config/config_test.go b/config/config_test.go deleted file mode 100644 index c891d6c514b..00000000000 --- a/config/config_test.go +++ /dev/null @@ -1,24 +0,0 @@ -package config - -import ( - "testing" -) - -func TestConfig(t *testing.T) { - const filename = ".ipfsconfig" - const dsPath = "/path/to/datastore" - cfgWritten := new(Config) - cfgWritten.Datastore.Path = dsPath - err := WriteConfigFile(filename, cfgWritten) - if err != nil { - t.Error(err) - } - cfgRead, err := Load(filename) - if err != nil { - t.Error(err) - return - } - if cfgWritten.Datastore.Path != cfgRead.Datastore.Path { - t.Fail() - } -} diff --git a/config/serialize.go b/config/serialize.go deleted file mode 100644 index b71d945b0bb..00000000000 --- a/config/serialize.go +++ /dev/null @@ -1,144 +0,0 @@ -package config - -import ( - "encoding/json" - "fmt" - "io" - "os" - "path/filepath" - "strings" -) - -// ReadConfigFile reads the config from `filename` into `cfg`. -func ReadConfigFile(filename string, cfg interface{}) error { - f, err := os.Open(filename) - if err != nil { - return err - } - defer f.Close() - - if err := Decode(f, cfg); err != nil { - return fmt.Errorf("Failure to decode config: %s", err) - } - return nil -} - -// WriteConfigFile writes the config from `cfg` into `filename`. -func WriteConfigFile(filename string, cfg interface{}) error { - err := os.MkdirAll(filepath.Dir(filename), 0775) - if err != nil { - return err - } - - f, err := os.Create(filename) - if err != nil { - return err - } - defer f.Close() - - return Encode(f, cfg) -} - -// WriteFile writes the buffer at filename -func WriteFile(filename string, buf []byte) error { - err := os.MkdirAll(filepath.Dir(filename), 0775) - if err != nil { - return err - } - - f, err := os.Create(filename) - if err != nil { - return err - } - defer f.Close() - - _, err = f.Write(buf) - return err -} - -// HumanOutput gets a config value ready for printing -func HumanOutput(value interface{}) ([]byte, error) { - s, ok := value.(string) - if ok { - return []byte(strings.Trim(s, "\n")), nil - } - return Marshal(value) -} - -// Marshal configuration with JSON -func Marshal(value interface{}) ([]byte, error) { - // need to prettyprint, hence MarshalIndent, instead of Encoder - return json.MarshalIndent(value, "", " ") -} - -// Encode configuration with JSON -func Encode(w io.Writer, value interface{}) error { - // need to prettyprint, hence MarshalIndent, instead of Encoder - buf, err := Marshal(value) - if err != nil { - return err - } - - _, err = w.Write(buf) - return err -} - -// Decode configuration with JSON -func Decode(r io.Reader, value interface{}) error { - return json.NewDecoder(r).Decode(value) -} - -// ReadConfigKey retrieves only the value of a particular key -func ReadConfigKey(filename, key string) (interface{}, error) { - var cfg interface{} - if err := ReadConfigFile(filename, &cfg); err != nil { - return nil, err - } - - var ok bool - cursor := cfg - parts := strings.Split(key, ".") - for i, part := range parts { - cursor, ok = cursor.(map[string]interface{})[part] - if !ok { - sofar := strings.Join(parts[:i], ".") - return nil, fmt.Errorf("%s key has no attributes", sofar) - } - } - return cursor, nil -} - -// WriteConfigKey writes the value of a particular key -func WriteConfigKey(filename, key string, value interface{}) error { - var cfg interface{} - if err := ReadConfigFile(filename, &cfg); err != nil { - return err - } - - var ok bool - var mcursor map[string]interface{} - cursor := cfg - - parts := strings.Split(key, ".") - for i, part := range parts { - mcursor, ok = cursor.(map[string]interface{}) - if !ok { - sofar := strings.Join(parts[:i], ".") - return fmt.Errorf("%s key is not a map", sofar) - } - - // last part? set here - if i == (len(parts) - 1) { - mcursor[part] = value - break - } - - cursor, ok = mcursor[part] - if !ok { // create map if this is empty - mcursor[part] = map[string]interface{}{} - cursor = mcursor[part] - } - } - - return WriteConfigFile(filename, cfg) -} diff --git a/config/version_test.go b/config/version_test.go index 37160c47896..c4b8aeb5ac2 100644 --- a/config/version_test.go +++ b/config/version_test.go @@ -1,6 +1,7 @@ package config import ( + "encoding/json" "strings" "testing" ) @@ -23,8 +24,7 @@ func TestAutoUpdateValues(t *testing.T) { } for i, tc := range tests { - err := Decode(strings.NewReader(tc.input), &tval) - if err != tc.err { + if err := json.NewDecoder(strings.NewReader(tc.input)).Decode(&tval); err != tc.err { t.Fatalf("%d failed - got err %q wanted %v", i, err, tc.err) } @@ -32,5 +32,4 @@ func TestAutoUpdateValues(t *testing.T) { t.Fatalf("%d failed - got val %q where we wanted %q", i, tval.AutoUpdate, tc.val) } } - } From ea5243400c1e391cfd5c32c135568dcc4bb6874a Mon Sep 17 00:00:00 2001 From: Brian Tiger Chow Date: Mon, 12 Jan 2015 18:23:29 -0800 Subject: [PATCH 003/414] go-ipfs-config: move utility method --- config/config.go | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/config/config.go b/config/config.go index 939c4564c44..a0a79eebadb 100644 --- a/config/config.go +++ b/config/config.go @@ -2,9 +2,11 @@ package config import ( + "bytes" "encoding/base64" "encoding/json" "errors" + "fmt" "os" "path/filepath" "strings" @@ -205,3 +207,15 @@ func Marshal(value interface{}) ([]byte, error) { // need to prettyprint, hence MarshalIndent, instead of Encoder return json.MarshalIndent(value, "", " ") } + +func FromMap(v map[string]interface{}) (*Config, error) { + var buf bytes.Buffer + if err := json.NewEncoder(&buf).Encode(v); err != nil { + return nil, err + } + var conf Config + if err := json.NewDecoder(&buf).Decode(&conf); err != nil { + return nil, fmt.Errorf("Failure to decode config: %s", err) + } + return &conf, nil +} From 058c999ba03fd06efe56d001130848ff22f047ab Mon Sep 17 00:00:00 2001 From: Brian Tiger Chow Date: Mon, 12 Jan 2015 18:31:42 -0800 Subject: [PATCH 004/414] go-ipfs-config: fix(config): avoid clobbering user-provided key value pairs let me know if this looks off @whyrusleeping @jbenet --- config/config.go | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/config/config.go b/config/config.go index a0a79eebadb..1230cd29b79 100644 --- a/config/config.go +++ b/config/config.go @@ -219,3 +219,15 @@ func FromMap(v map[string]interface{}) (*Config, error) { } return &conf, nil } + +func ToMap(conf *Config) (map[string]interface{}, error) { + var buf bytes.Buffer + if err := json.NewEncoder(&buf).Encode(conf); err != nil { + return nil, err + } + var m map[string]interface{} + if err := json.NewDecoder(&buf).Decode(&m); err != nil { + return nil, fmt.Errorf("Failure to decode config: %s", err) + } + return m, nil +} From 7882aa98f5b221992e4821081c9cd239fe57c7da Mon Sep 17 00:00:00 2001 From: Brian Tiger Chow Date: Mon, 12 Jan 2015 19:09:10 -0800 Subject: [PATCH 005/414] go-ipfs-config: refactor(config): break it apart --- config/addresses.go | 8 +++ config/bootstrap_peers.go | 62 ++++++++++++++++ config/config.go | 144 +++----------------------------------- config/datastore.go | 16 +++++ config/identity.go | 24 +++++++ config/logs.go | 18 +++++ config/mounts.go | 7 ++ config/tour.go | 7 ++ 8 files changed, 150 insertions(+), 136 deletions(-) create mode 100644 config/addresses.go create mode 100644 config/bootstrap_peers.go create mode 100644 config/datastore.go create mode 100644 config/identity.go create mode 100644 config/logs.go create mode 100644 config/mounts.go create mode 100644 config/tour.go diff --git a/config/addresses.go b/config/addresses.go new file mode 100644 index 00000000000..ba891526196 --- /dev/null +++ b/config/addresses.go @@ -0,0 +1,8 @@ +package config + +// Addresses stores the (string) multiaddr addresses for the node. +type Addresses struct { + Swarm []string // addresses for the swarm network + API string // address for the local API (RPC) + Gateway string // address to listen on for IPFS HTTP object gateway +} diff --git a/config/bootstrap_peers.go b/config/bootstrap_peers.go new file mode 100644 index 00000000000..db59f975f96 --- /dev/null +++ b/config/bootstrap_peers.go @@ -0,0 +1,62 @@ +package config + +import ( + "errors" + "strings" + + ma "github.com/jbenet/go-ipfs/Godeps/_workspace/src/github.com/jbenet/go-multiaddr" + mh "github.com/jbenet/go-ipfs/Godeps/_workspace/src/github.com/jbenet/go-multihash" +) + +// BootstrapPeer is a peer used to bootstrap the network. +type BootstrapPeer struct { + Address string + PeerID string // until multiaddr supports ipfs, use another field. +} + +func (bp *BootstrapPeer) String() string { + return bp.Address + "/" + bp.PeerID +} + +func ParseBootstrapPeer(addr string) (BootstrapPeer, error) { + // to be replaced with just multiaddr parsing, once ptp is a multiaddr protocol + idx := strings.LastIndex(addr, "/") + if idx == -1 { + return BootstrapPeer{}, errors.New("invalid address") + } + addrS := addr[:idx] + peeridS := addr[idx+1:] + + // make sure addrS parses as a multiaddr. + if len(addrS) > 0 { + maddr, err := ma.NewMultiaddr(addrS) + if err != nil { + return BootstrapPeer{}, err + } + + addrS = maddr.String() + } + + // make sure idS parses as a peer.ID + _, err := mh.FromB58String(peeridS) + if err != nil { + return BootstrapPeer{}, err + } + + return BootstrapPeer{ + Address: addrS, + PeerID: peeridS, + }, nil +} + +func ParseBootstrapPeers(addrs []string) ([]BootstrapPeer, error) { + peers := make([]BootstrapPeer, len(addrs)) + var err error + for i, addr := range addrs { + peers[i], err = ParseBootstrapPeer(addr) + if err != nil { + return nil, err + } + } + return peers, nil +} diff --git a/config/config.go b/config/config.go index 1230cd29b79..4c1086e8bcc 100644 --- a/config/config.go +++ b/config/config.go @@ -3,115 +3,17 @@ package config import ( "bytes" - "encoding/base64" "encoding/json" - "errors" "fmt" "os" "path/filepath" "strings" - ma "github.com/jbenet/go-ipfs/Godeps/_workspace/src/github.com/jbenet/go-multiaddr" - mh "github.com/jbenet/go-ipfs/Godeps/_workspace/src/github.com/jbenet/go-multihash" - - ic "github.com/jbenet/go-ipfs/p2p/crypto" u "github.com/jbenet/go-ipfs/util" ) var log = u.Logger("config") -// Identity tracks the configuration of the local node's identity. -type Identity struct { - PeerID string - PrivKey string -} - -// Logs tracks the configuration of the event logger -type Logs struct { - Filename string - MaxSizeMB uint64 - MaxBackups uint64 - MaxAgeDays uint64 -} - -// Datastore tracks the configuration of the datastore. -type Datastore struct { - Type string - Path string -} - -// Addresses stores the (string) multiaddr addresses for the node. -type Addresses struct { - Swarm []string // addresses for the swarm network - API string // address for the local API (RPC) - Gateway string // address to listen on for IPFS HTTP object gateway -} - -// Mounts stores the (string) mount points -type Mounts struct { - IPFS string - IPNS string -} - -// BootstrapPeer is a peer used to bootstrap the network. -type BootstrapPeer struct { - Address string - PeerID string // until multiaddr supports ipfs, use another field. -} - -func (bp *BootstrapPeer) String() string { - return bp.Address + "/" + bp.PeerID -} - -func ParseBootstrapPeer(addr string) (BootstrapPeer, error) { - // to be replaced with just multiaddr parsing, once ptp is a multiaddr protocol - idx := strings.LastIndex(addr, "/") - if idx == -1 { - return BootstrapPeer{}, errors.New("invalid address") - } - addrS := addr[:idx] - peeridS := addr[idx+1:] - - // make sure addrS parses as a multiaddr. - if len(addrS) > 0 { - maddr, err := ma.NewMultiaddr(addrS) - if err != nil { - return BootstrapPeer{}, err - } - - addrS = maddr.String() - } - - // make sure idS parses as a peer.ID - _, err := mh.FromB58String(peeridS) - if err != nil { - return BootstrapPeer{}, err - } - - return BootstrapPeer{ - Address: addrS, - PeerID: peeridS, - }, nil -} - -func ParseBootstrapPeers(addrs []string) ([]BootstrapPeer, error) { - peers := make([]BootstrapPeer, len(addrs)) - var err error - for i, addr := range addrs { - peers[i], err = ParseBootstrapPeer(addr) - if err != nil { - return nil, err - } - } - return peers, nil -} - -// Tour stores the ipfs tour read-list and resume point -type Tour struct { - Last string // last tour topic read - // Done []string // all topics done so far -} - // Config is used to load IPFS config files. type Config struct { Identity Identity // local node's peer identity @@ -124,20 +26,14 @@ type Config struct { Logs Logs // local node's event log configuration } -// DefaultPathRoot is the path to the default config dir location. -const DefaultPathRoot = "~/.go-ipfs" - -// DefaultConfigFile is the filename of the configuration file -const DefaultConfigFile = "config" - -// DefaultDataStoreDirectory is the directory to store all the local IPFS data. -const DefaultDataStoreDirectory = "datastore" - -// EnvDir is the environment variable used to change the path root. -const EnvDir = "IPFS_DIR" - -// LogsDefaultDirectory is the directory to store all IPFS event logs. -var LogsDefaultDirectory = "logs" +const ( + // DefaultPathRoot is the path to the default config dir location. + DefaultPathRoot = "~/.go-ipfs" + // DefaultConfigFile is the filename of the configuration file + DefaultConfigFile = "config" + // EnvDir is the environment variable used to change the path root. + EnvDir = "IPFS_DIR" +) // PathRoot returns the default configuration root directory func PathRoot() (string, error) { @@ -163,36 +59,12 @@ func Path(configroot, extension string) (string, error) { return filepath.Join(configroot, extension), nil } -// DataStorePath returns the default data store path given a configuration root -// (set an empty string to have the default configuration root) -func DataStorePath(configroot string) (string, error) { - return Path(configroot, DefaultDataStoreDirectory) -} - -// LogsPath returns the default path for event logs given a configuration root -// (set an empty string to have the default configuration root) -func LogsPath(configroot string) (string, error) { - return Path(configroot, LogsDefaultDirectory) -} - // Filename returns the configuration file path given a configuration root // directory. If the configuration root directory is empty, use the default one func Filename(configroot string) (string, error) { return Path(configroot, DefaultConfigFile) } -// DecodePrivateKey is a helper to decode the users PrivateKey -func (i *Identity) DecodePrivateKey(passphrase string) (ic.PrivKey, error) { - pkb, err := base64.StdEncoding.DecodeString(i.PrivKey) - if err != nil { - return nil, err - } - - // currently storing key unencrypted. in the future we need to encrypt it. - // TODO(security) - return ic.UnmarshalPrivateKey(pkb) -} - // HumanOutput gets a config value ready for printing func HumanOutput(value interface{}) ([]byte, error) { s, ok := value.(string) diff --git a/config/datastore.go b/config/datastore.go new file mode 100644 index 00000000000..b615c650f25 --- /dev/null +++ b/config/datastore.go @@ -0,0 +1,16 @@ +package config + +// DefaultDataStoreDirectory is the directory to store all the local IPFS data. +const DefaultDataStoreDirectory = "datastore" + +// Datastore tracks the configuration of the datastore. +type Datastore struct { + Type string + Path string +} + +// DataStorePath returns the default data store path given a configuration root +// (set an empty string to have the default configuration root) +func DataStorePath(configroot string) (string, error) { + return Path(configroot, DefaultDataStoreDirectory) +} diff --git a/config/identity.go b/config/identity.go new file mode 100644 index 00000000000..2097e51886d --- /dev/null +++ b/config/identity.go @@ -0,0 +1,24 @@ +package config + +import ( + "encoding/base64" + ic "github.com/jbenet/go-ipfs/p2p/crypto" +) + +// Identity tracks the configuration of the local node's identity. +type Identity struct { + PeerID string + PrivKey string +} + +// DecodePrivateKey is a helper to decode the users PrivateKey +func (i *Identity) DecodePrivateKey(passphrase string) (ic.PrivKey, error) { + pkb, err := base64.StdEncoding.DecodeString(i.PrivKey) + if err != nil { + return nil, err + } + + // currently storing key unencrypted. in the future we need to encrypt it. + // TODO(security) + return ic.UnmarshalPrivateKey(pkb) +} diff --git a/config/logs.go b/config/logs.go new file mode 100644 index 00000000000..687f0832f71 --- /dev/null +++ b/config/logs.go @@ -0,0 +1,18 @@ +package config + +// LogsDefaultDirectory is the directory to store all IPFS event logs. +var LogsDefaultDirectory = "logs" + +// Logs tracks the configuration of the event logger +type Logs struct { + Filename string + MaxSizeMB uint64 + MaxBackups uint64 + MaxAgeDays uint64 +} + +// LogsPath returns the default path for event logs given a configuration root +// (set an empty string to have the default configuration root) +func LogsPath(configroot string) (string, error) { + return Path(configroot, LogsDefaultDirectory) +} diff --git a/config/mounts.go b/config/mounts.go new file mode 100644 index 00000000000..a0f42005943 --- /dev/null +++ b/config/mounts.go @@ -0,0 +1,7 @@ +package config + +// Mounts stores the (string) mount points +type Mounts struct { + IPFS string + IPNS string +} diff --git a/config/tour.go b/config/tour.go new file mode 100644 index 00000000000..cf9aef35502 --- /dev/null +++ b/config/tour.go @@ -0,0 +1,7 @@ +package config + +// Tour stores the ipfs tour read-list and resume point +type Tour struct { + Last string // last tour topic read + // Done []string // all topics done so far +} From 13ffe4fbb8db4ffcb53b38434562b5e06a75c5ab Mon Sep 17 00:00:00 2001 From: Brian Tiger Chow Date: Mon, 19 Jan 2015 00:02:43 -0800 Subject: [PATCH 006/414] go-ipfs-config: refactor: rename IPFS_DIR -> IPFS_PATH closes #394 https://github.com/jbenet/go-ipfs/issues/394 --- config/config.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/config/config.go b/config/config.go index 4c1086e8bcc..16b6a789644 100644 --- a/config/config.go +++ b/config/config.go @@ -32,7 +32,7 @@ const ( // DefaultConfigFile is the filename of the configuration file DefaultConfigFile = "config" // EnvDir is the environment variable used to change the path root. - EnvDir = "IPFS_DIR" + EnvDir = "IPFS_PATH" ) // PathRoot returns the default configuration root directory From 843cc85edec6135f40f02f91caf4285f0c1c3c49 Mon Sep 17 00:00:00 2001 From: Brian Tiger Chow Date: Sat, 24 Jan 2015 01:20:31 -0800 Subject: [PATCH 007/414] go-ipfs-config: refactor(eventlog) integrate into fsrepo now, eventlogger works wherever the fsrepo is used --- config/config.go | 1 - config/logs.go | 17 ----------------- 2 files changed, 18 deletions(-) diff --git a/config/config.go b/config/config.go index 16b6a789644..816ffcef57a 100644 --- a/config/config.go +++ b/config/config.go @@ -23,7 +23,6 @@ type Config struct { Version Version // local node's version management Bootstrap []BootstrapPeer // local nodes's bootstrap peers Tour Tour // local node's tour position - Logs Logs // local node's event log configuration } const ( diff --git a/config/logs.go b/config/logs.go index 687f0832f71..d912156bec0 100644 --- a/config/logs.go +++ b/config/logs.go @@ -1,18 +1 @@ package config - -// LogsDefaultDirectory is the directory to store all IPFS event logs. -var LogsDefaultDirectory = "logs" - -// Logs tracks the configuration of the event logger -type Logs struct { - Filename string - MaxSizeMB uint64 - MaxBackups uint64 - MaxAgeDays uint64 -} - -// LogsPath returns the default path for event logs given a configuration root -// (set an empty string to have the default configuration root) -func LogsPath(configroot string) (string, error) { - return Path(configroot, LogsDefaultDirectory) -} From 69d7848d2ed23a5491ee7c0f396650c429457f0d Mon Sep 17 00:00:00 2001 From: Brian Tiger Chow Date: Sat, 24 Jan 2015 02:50:53 -0800 Subject: [PATCH 008/414] go-ipfs-config: move config.Init into config package --- config/bootstrap_peers.go | 33 ++++++++++++- config/init.go | 99 +++++++++++++++++++++++++++++++++++++++ 2 files changed, 131 insertions(+), 1 deletion(-) create mode 100644 config/init.go diff --git a/config/bootstrap_peers.go b/config/bootstrap_peers.go index db59f975f96..2b437d185c5 100644 --- a/config/bootstrap_peers.go +++ b/config/bootstrap_peers.go @@ -1,19 +1,50 @@ package config import ( - "errors" "strings" ma "github.com/jbenet/go-ipfs/Godeps/_workspace/src/github.com/jbenet/go-multiaddr" mh "github.com/jbenet/go-ipfs/Godeps/_workspace/src/github.com/jbenet/go-multihash" + + errors "github.com/jbenet/go-ipfs/util/debugerror" ) +// DefaultBootstrapAddresses are the hardcoded bootstrap addresses +// for ipfs. they are nodes run by the ipfs team. docs on these later. +// As with all p2p networks, bootstrap is an important security concern. +// +// Note: this is here -- and not inside cmd/ipfs/init.go -- because of an +// import dependency issue. TODO: move this into a config/default/ package. +var DefaultBootstrapAddresses = []string{ + "/ip4/104.131.131.82/tcp/4001/QmaCpDMGvV2BGHeYERUEnRQAwe3N8SzbUtfsmvsqQLuvuJ", // mars.i.ipfs.io + "/ip4/104.236.176.52/tcp/4001/QmSoLnSGccFuZQJzRadHn95W2CrSFmZuTdDWP8HXaHca9z", // neptune (to be neptune.i.ipfs.io) + "/ip4/104.236.179.241/tcp/4001/QmSoLpPVmHKQ4XTPdz8tjDFgdeRFkpV8JgYq8JVJ69RrZm", // pluto (to be pluto.i.ipfs.io) + "/ip4/162.243.248.213/tcp/4001/QmSoLueR4xBeUbY9WZ9xGUUxunbKWcrNFTDAadQJmocnWm", // uranus (to be uranus.i.ipfs.io) + "/ip4/128.199.219.111/tcp/4001/QmSoLSafTMBsPKadTEgaXctDQVcqN88CNLHXMkTNwMKPnu", // saturn (to be saturn.i.ipfs.io) + "/ip4/104.236.76.40/tcp/4001/QmSoLV4Bbm51jM9C4gDYZQ9Cy3U6aXMJDAbzgu2fzaDs64", // venus (to be venus.i.ipfs.io) + "/ip4/178.62.158.247/tcp/4001/QmSoLer265NRgSp2LA3dPaeykiS1J6DifTC88f5uVQKNAd", // earth (to be earth.i.ipfs.io) + "/ip4/178.62.61.185/tcp/4001/QmSoLMeWqB7YGVLJN3pNLQpmmEk35v6wYtsMGLzSr5QBU3", // mercury (to be mercury.i.ipfs.io) + "/ip4/104.236.151.122/tcp/4001/QmSoLju6m7xTh3DuokvT3886QRYqxAzb1kShaanJgW36yx", // jupiter (to be jupiter.i.ipfs.io) +} + // BootstrapPeer is a peer used to bootstrap the network. type BootstrapPeer struct { Address string PeerID string // until multiaddr supports ipfs, use another field. } +// DefaultBootstrapPeers returns the (parsed) set of default bootstrap peers. +// if it fails, it returns a meaningful error for the user. +// This is here (and not inside cmd/ipfs/init) because of module dependency problems. +func DefaultBootstrapPeers() ([]BootstrapPeer, error) { + ps, err := ParseBootstrapPeers(DefaultBootstrapAddresses) + if err != nil { + return nil, errors.Errorf(`failed to parse hardcoded bootstrap peers: %s +This is a problem with the ipfs codebase. Please report it to the dev team.`, err) + } + return ps, nil +} + func (bp *BootstrapPeer) String() string { return bp.Address + "/" + bp.PeerID } diff --git a/config/init.go b/config/init.go new file mode 100644 index 00000000000..dade155bc94 --- /dev/null +++ b/config/init.go @@ -0,0 +1,99 @@ +package config + +import ( + "encoding/base64" + "fmt" + + ci "github.com/jbenet/go-ipfs/p2p/crypto" + peer "github.com/jbenet/go-ipfs/p2p/peer" + errors "github.com/jbenet/go-ipfs/util/debugerror" +) + +func Init(nBitsForKeypair int) (*Config, error) { + ds, err := datastoreConfig() + if err != nil { + return nil, err + } + + identity, err := identityConfig(nBitsForKeypair) + if err != nil { + return nil, err + } + + bootstrapPeers, err := DefaultBootstrapPeers() + if err != nil { + return nil, err + } + + conf := &Config{ + + // setup the node's default addresses. + // Note: two swarm listen addrs, one tcp, one utp. + Addresses: Addresses{ + Swarm: []string{ + "/ip4/0.0.0.0/tcp/4001", + // "/ip4/0.0.0.0/udp/4002/utp", // disabled for now. + }, + API: "/ip4/127.0.0.1/tcp/5001", + }, + + Bootstrap: bootstrapPeers, + Datastore: *ds, + Identity: identity, + + // setup the node mount points. + Mounts: Mounts{ + IPFS: "/ipfs", + IPNS: "/ipns", + }, + + // tracking ipfs version used to generate the init folder and adding + // update checker default setting. + Version: VersionDefaultValue(), + } + + return conf, nil +} + +func datastoreConfig() (*Datastore, error) { + dspath, err := DataStorePath("") + if err != nil { + return nil, err + } + return &Datastore{ + Path: dspath, + Type: "leveldb", + }, nil +} + +// identityConfig initializes a new identity. +func identityConfig(nbits int) (Identity, error) { + // TODO guard higher up + ident := Identity{} + if nbits < 1024 { + return ident, errors.New("Bitsize less than 1024 is considered unsafe.") + } + + fmt.Printf("generating %v-bit RSA keypair...", nbits) + sk, pk, err := ci.GenerateKeyPair(ci.RSA, nbits) + if err != nil { + return ident, err + } + fmt.Printf("done\n") + + // currently storing key unencrypted. in the future we need to encrypt it. + // TODO(security) + skbytes, err := sk.Bytes() + if err != nil { + return ident, err + } + ident.PrivKey = base64.StdEncoding.EncodeToString(skbytes) + + id, err := peer.IDFromPublicKey(pk) + if err != nil { + return ident, err + } + ident.PeerID = id.Pretty() + fmt.Printf("peer identity: %s\n", ident.PeerID) + return ident, nil +} From 2217c97632f4d20e32c72f337e1e62d268b8ff1b Mon Sep 17 00:00:00 2001 From: Matt Bell Date: Mon, 26 Jan 2015 23:17:58 -0800 Subject: [PATCH 009/414] go-ipfs-config: repo/config: Added Gateway options to config --- config/config.go | 1 + config/gateway.go | 6 ++++++ 2 files changed, 7 insertions(+) create mode 100644 config/gateway.go diff --git a/config/config.go b/config/config.go index 816ffcef57a..9159223f7cf 100644 --- a/config/config.go +++ b/config/config.go @@ -23,6 +23,7 @@ type Config struct { Version Version // local node's version management Bootstrap []BootstrapPeer // local nodes's bootstrap peers Tour Tour // local node's tour position + Gateway Gateway // local node's gateway server options } const ( diff --git a/config/gateway.go b/config/gateway.go new file mode 100644 index 00000000000..7bc3eb02044 --- /dev/null +++ b/config/gateway.go @@ -0,0 +1,6 @@ +package config + +// Gateway contains options for the HTTP gateway server. +type Gateway struct { + RootRedirect string +} From 6579236d398f38e6bd0cfd94dfc8e4ebcfe4ec72 Mon Sep 17 00:00:00 2001 From: Matt Bell Date: Mon, 26 Jan 2015 23:28:21 -0800 Subject: [PATCH 010/414] go-ipfs-config: cmd/ipfs: Add empty gateway object when initting config --- config/init.go | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/config/init.go b/config/init.go index dade155bc94..402139e41ee 100644 --- a/config/init.go +++ b/config/init.go @@ -50,6 +50,10 @@ func Init(nBitsForKeypair int) (*Config, error) { // tracking ipfs version used to generate the init folder and adding // update checker default setting. Version: VersionDefaultValue(), + + Gateway: Gateway{ + RootRedirect: "", + }, } return conf, nil From 075ae67fdd24f889513849910cdcecf3016d4284 Mon Sep 17 00:00:00 2001 From: Juan Batiz-Benet Date: Mon, 19 Jan 2015 17:26:58 -0800 Subject: [PATCH 011/414] go-ipfs-config: init docs: go generated welcome dir + files updated sharness hashes --- config/init.go | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/config/init.go b/config/init.go index 402139e41ee..aef5624ec72 100644 --- a/config/init.go +++ b/config/init.go @@ -3,19 +3,20 @@ package config import ( "encoding/base64" "fmt" + "io" ci "github.com/jbenet/go-ipfs/p2p/crypto" peer "github.com/jbenet/go-ipfs/p2p/peer" errors "github.com/jbenet/go-ipfs/util/debugerror" ) -func Init(nBitsForKeypair int) (*Config, error) { +func Init(out io.Writer, nBitsForKeypair int) (*Config, error) { ds, err := datastoreConfig() if err != nil { return nil, err } - identity, err := identityConfig(nBitsForKeypair) + identity, err := identityConfig(out, nBitsForKeypair) if err != nil { return nil, err } @@ -71,19 +72,19 @@ func datastoreConfig() (*Datastore, error) { } // identityConfig initializes a new identity. -func identityConfig(nbits int) (Identity, error) { +func identityConfig(out io.Writer, nbits int) (Identity, error) { // TODO guard higher up ident := Identity{} if nbits < 1024 { return ident, errors.New("Bitsize less than 1024 is considered unsafe.") } - fmt.Printf("generating %v-bit RSA keypair...", nbits) + out.Write([]byte(fmt.Sprintf("generating %v-bit RSA keypair...", nbits))) sk, pk, err := ci.GenerateKeyPair(ci.RSA, nbits) if err != nil { return ident, err } - fmt.Printf("done\n") + out.Write([]byte(fmt.Sprintf("done\n"))) // currently storing key unencrypted. in the future we need to encrypt it. // TODO(security) From cf854f9a2074b5ce88999b852bb46e277defb27a Mon Sep 17 00:00:00 2001 From: Mildred Ki'Lya Date: Wed, 28 Jan 2015 12:57:09 +0100 Subject: [PATCH 012/414] go-ipfs-config: Make gateway read-only by default and add option to make it writable --- config/gateway.go | 1 + config/init.go | 1 + 2 files changed, 2 insertions(+) diff --git a/config/gateway.go b/config/gateway.go index 7bc3eb02044..c0885778d57 100644 --- a/config/gateway.go +++ b/config/gateway.go @@ -3,4 +3,5 @@ package config // Gateway contains options for the HTTP gateway server. type Gateway struct { RootRedirect string + Writable bool } diff --git a/config/init.go b/config/init.go index aef5624ec72..976d266883e 100644 --- a/config/init.go +++ b/config/init.go @@ -54,6 +54,7 @@ func Init(out io.Writer, nBitsForKeypair int) (*Config, error) { Gateway: Gateway{ RootRedirect: "", + Writable: false, }, } From 9adf5bc2bfb69820ef42fb4f824678aa84af0e35 Mon Sep 17 00:00:00 2001 From: Juan Batiz-Benet Date: Tue, 20 Jan 2015 16:05:48 -0800 Subject: [PATCH 013/414] go-ipfs-config: bootstrap: use ipfsaddr for boostrap peers :warning: :warning: this commit makes your current configs unusable, as the default bootstrap peers. You may need to edit your config. Go from: ```js Bootstrap: [ { "Address": "/ip4/104.131.131.82/tcp/4001", "PeerID": "QmaCpDMGvV2BGHeYERUEnRQAwe3N8SzbUtfsmvsqQLuvuJ" } ] ``` To: ```js Bootstrap: [ "/ip4/104.131.131.82/tcp/4001/ipfs/QmaCpDMGvV2BGHeYERUEnRQAwe3N8SzbUtfsmvsqQLuvuJ" ] ``` --- config/bootstrap_peers.go | 76 ++++++++++++++++----------------------- config/config.go | 16 ++++----- config/init.go | 2 +- 3 files changed, 40 insertions(+), 54 deletions(-) diff --git a/config/bootstrap_peers.go b/config/bootstrap_peers.go index 2b437d185c5..de4935d7856 100644 --- a/config/bootstrap_peers.go +++ b/config/bootstrap_peers.go @@ -1,12 +1,9 @@ package config import ( - "strings" - - ma "github.com/jbenet/go-ipfs/Godeps/_workspace/src/github.com/jbenet/go-multiaddr" - mh "github.com/jbenet/go-ipfs/Godeps/_workspace/src/github.com/jbenet/go-multihash" - errors "github.com/jbenet/go-ipfs/util/debugerror" + + iaddr "github.com/jbenet/go-ipfs/util/ipfsaddr" ) // DefaultBootstrapAddresses are the hardcoded bootstrap addresses @@ -16,21 +13,25 @@ import ( // Note: this is here -- and not inside cmd/ipfs/init.go -- because of an // import dependency issue. TODO: move this into a config/default/ package. var DefaultBootstrapAddresses = []string{ - "/ip4/104.131.131.82/tcp/4001/QmaCpDMGvV2BGHeYERUEnRQAwe3N8SzbUtfsmvsqQLuvuJ", // mars.i.ipfs.io - "/ip4/104.236.176.52/tcp/4001/QmSoLnSGccFuZQJzRadHn95W2CrSFmZuTdDWP8HXaHca9z", // neptune (to be neptune.i.ipfs.io) - "/ip4/104.236.179.241/tcp/4001/QmSoLpPVmHKQ4XTPdz8tjDFgdeRFkpV8JgYq8JVJ69RrZm", // pluto (to be pluto.i.ipfs.io) - "/ip4/162.243.248.213/tcp/4001/QmSoLueR4xBeUbY9WZ9xGUUxunbKWcrNFTDAadQJmocnWm", // uranus (to be uranus.i.ipfs.io) - "/ip4/128.199.219.111/tcp/4001/QmSoLSafTMBsPKadTEgaXctDQVcqN88CNLHXMkTNwMKPnu", // saturn (to be saturn.i.ipfs.io) - "/ip4/104.236.76.40/tcp/4001/QmSoLV4Bbm51jM9C4gDYZQ9Cy3U6aXMJDAbzgu2fzaDs64", // venus (to be venus.i.ipfs.io) - "/ip4/178.62.158.247/tcp/4001/QmSoLer265NRgSp2LA3dPaeykiS1J6DifTC88f5uVQKNAd", // earth (to be earth.i.ipfs.io) - "/ip4/178.62.61.185/tcp/4001/QmSoLMeWqB7YGVLJN3pNLQpmmEk35v6wYtsMGLzSr5QBU3", // mercury (to be mercury.i.ipfs.io) - "/ip4/104.236.151.122/tcp/4001/QmSoLju6m7xTh3DuokvT3886QRYqxAzb1kShaanJgW36yx", // jupiter (to be jupiter.i.ipfs.io) + "/ip4/104.131.131.82/tcp/4001/ipfs/QmaCpDMGvV2BGHeYERUEnRQAwe3N8SzbUtfsmvsqQLuvuJ", // mars.i.ipfs.io + "/ip4/104.236.176.52/tcp/4001/ipfs/QmSoLnSGccFuZQJzRadHn95W2CrSFmZuTdDWP8HXaHca9z", // neptune (to be neptune.i.ipfs.io) + "/ip4/104.236.179.241/tcp/4001/ipfs/QmSoLpPVmHKQ4XTPdz8tjDFgdeRFkpV8JgYq8JVJ69RrZm", // pluto (to be pluto.i.ipfs.io) + "/ip4/162.243.248.213/tcp/4001/ipfs/QmSoLueR4xBeUbY9WZ9xGUUxunbKWcrNFTDAadQJmocnWm", // uranus (to be uranus.i.ipfs.io) + "/ip4/128.199.219.111/tcp/4001/ipfs/QmSoLSafTMBsPKadTEgaXctDQVcqN88CNLHXMkTNwMKPnu", // saturn (to be saturn.i.ipfs.io) + "/ip4/104.236.76.40/tcp/4001/ipfs/QmSoLV4Bbm51jM9C4gDYZQ9Cy3U6aXMJDAbzgu2fzaDs64", // venus (to be venus.i.ipfs.io) + "/ip4/178.62.158.247/tcp/4001/ipfs/QmSoLer265NRgSp2LA3dPaeykiS1J6DifTC88f5uVQKNAd", // earth (to be earth.i.ipfs.io) + "/ip4/178.62.61.185/tcp/4001/ipfs/QmSoLMeWqB7YGVLJN3pNLQpmmEk35v6wYtsMGLzSr5QBU3", // mercury (to be mercury.i.ipfs.io) + "/ip4/104.236.151.122/tcp/4001/ipfs/QmSoLju6m7xTh3DuokvT3886QRYqxAzb1kShaanJgW36yx", // jupiter (to be jupiter.i.ipfs.io) } // BootstrapPeer is a peer used to bootstrap the network. -type BootstrapPeer struct { - Address string - PeerID string // until multiaddr supports ipfs, use another field. +type BootstrapPeer iaddr.IPFSAddr + +// ErrInvalidPeerAddr signals an address is not a valid peer address. +var ErrInvalidPeerAddr = errors.New("invalid peer address") + +func (c *Config) BootstrapPeers() ([]BootstrapPeer, error) { + return ParseBootstrapPeers(c.Bootstrap) } // DefaultBootstrapPeers returns the (parsed) set of default bootstrap peers. @@ -45,39 +46,16 @@ This is a problem with the ipfs codebase. Please report it to the dev team.`, er return ps, nil } -func (bp *BootstrapPeer) String() string { - return bp.Address + "/" + bp.PeerID +func (c *Config) SetBootstrapPeers(bps []BootstrapPeer) { + c.Bootstrap = BootstrapPeerStrings(bps) } func ParseBootstrapPeer(addr string) (BootstrapPeer, error) { - // to be replaced with just multiaddr parsing, once ptp is a multiaddr protocol - idx := strings.LastIndex(addr, "/") - if idx == -1 { - return BootstrapPeer{}, errors.New("invalid address") - } - addrS := addr[:idx] - peeridS := addr[idx+1:] - - // make sure addrS parses as a multiaddr. - if len(addrS) > 0 { - maddr, err := ma.NewMultiaddr(addrS) - if err != nil { - return BootstrapPeer{}, err - } - - addrS = maddr.String() - } - - // make sure idS parses as a peer.ID - _, err := mh.FromB58String(peeridS) + ia, err := iaddr.ParseString(addr) if err != nil { - return BootstrapPeer{}, err + return nil, err } - - return BootstrapPeer{ - Address: addrS, - PeerID: peeridS, - }, nil + return BootstrapPeer(ia), err } func ParseBootstrapPeers(addrs []string) ([]BootstrapPeer, error) { @@ -91,3 +69,11 @@ func ParseBootstrapPeers(addrs []string) ([]BootstrapPeer, error) { } return peers, nil } + +func BootstrapPeerStrings(bps []BootstrapPeer) []string { + bpss := make([]string, len(bps)) + for i, p := range bps { + bpss[i] = p.String() + } + return bpss +} diff --git a/config/config.go b/config/config.go index 9159223f7cf..e912429cd89 100644 --- a/config/config.go +++ b/config/config.go @@ -16,14 +16,14 @@ var log = u.Logger("config") // Config is used to load IPFS config files. type Config struct { - Identity Identity // local node's peer identity - Datastore Datastore // local node's storage - Addresses Addresses // local node's addresses - Mounts Mounts // local node's mount points - Version Version // local node's version management - Bootstrap []BootstrapPeer // local nodes's bootstrap peers - Tour Tour // local node's tour position - Gateway Gateway // local node's gateway server options + Identity Identity // local node's peer identity + Datastore Datastore // local node's storage + Addresses Addresses // local node's addresses + Mounts Mounts // local node's mount points + Version Version // local node's version management + Bootstrap []string // local nodes's bootstrap peer addresses + Tour Tour // local node's tour position + Gateway Gateway // local node's gateway server options } const ( diff --git a/config/init.go b/config/init.go index 976d266883e..6d1c529e7ef 100644 --- a/config/init.go +++ b/config/init.go @@ -38,7 +38,7 @@ func Init(out io.Writer, nBitsForKeypair int) (*Config, error) { API: "/ip4/127.0.0.1/tcp/5001", }, - Bootstrap: bootstrapPeers, + Bootstrap: BootstrapPeerStrings(bootstrapPeers), Datastore: *ds, Identity: identity, From 2cca094aa8b73f0f4e48deeefa0145dc361904c0 Mon Sep 17 00:00:00 2001 From: Brian Tiger Chow Date: Mon, 2 Feb 2015 17:42:54 -0800 Subject: [PATCH 014/414] go-ipfs-config: feat(fsrepo) add eventlog config to repo/config struct --- config/config.go | 1 + config/log.go | 8 ++++++++ 2 files changed, 9 insertions(+) create mode 100644 config/log.go diff --git a/config/config.go b/config/config.go index e912429cd89..f214b513b58 100644 --- a/config/config.go +++ b/config/config.go @@ -24,6 +24,7 @@ type Config struct { Bootstrap []string // local nodes's bootstrap peer addresses Tour Tour // local node's tour position Gateway Gateway // local node's gateway server options + Log Log } const ( diff --git a/config/log.go b/config/log.go new file mode 100644 index 00000000000..50e7243d45b --- /dev/null +++ b/config/log.go @@ -0,0 +1,8 @@ +package config + + +type Log struct { + MaxSizeMB uint64 + MaxBackups uint64 + MaxAgeDays uint64 +} From 4309541e87f6786d0fa2c4d8f33696c56e555c21 Mon Sep 17 00:00:00 2001 From: Brian Tiger Chow Date: Mon, 2 Feb 2015 18:26:47 -0800 Subject: [PATCH 015/414] go-ipfs-config: feat(config) default Log.MaxSizeMB = 500 --- config/init.go | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/config/init.go b/config/init.go index 6d1c529e7ef..76a70cdd65a 100644 --- a/config/init.go +++ b/config/init.go @@ -41,6 +41,9 @@ func Init(out io.Writer, nBitsForKeypair int) (*Config, error) { Bootstrap: BootstrapPeerStrings(bootstrapPeers), Datastore: *ds, Identity: identity, + Log: Log{ + MaxSizeMB: 500, + }, // setup the node mount points. Mounts: Mounts{ @@ -54,7 +57,7 @@ func Init(out io.Writer, nBitsForKeypair int) (*Config, error) { Gateway: Gateway{ RootRedirect: "", - Writable: false, + Writable: false, }, } From b8d85948012f464f77de5a5f58af9c910ece1cc3 Mon Sep 17 00:00:00 2001 From: Juan Batiz-Benet Date: Tue, 3 Feb 2015 02:27:24 -0800 Subject: [PATCH 016/414] go-ipfs-config: fsrepo: fix output to writer --- config/init.go | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/config/init.go b/config/init.go index 76a70cdd65a..737f174f2f5 100644 --- a/config/init.go +++ b/config/init.go @@ -83,12 +83,12 @@ func identityConfig(out io.Writer, nbits int) (Identity, error) { return ident, errors.New("Bitsize less than 1024 is considered unsafe.") } - out.Write([]byte(fmt.Sprintf("generating %v-bit RSA keypair...", nbits))) + fmt.Fprintf(out, "generating %v-bit RSA keypair...", nbits) sk, pk, err := ci.GenerateKeyPair(ci.RSA, nbits) if err != nil { return ident, err } - out.Write([]byte(fmt.Sprintf("done\n"))) + fmt.Fprintf(out, "done\n") // currently storing key unencrypted. in the future we need to encrypt it. // TODO(security) @@ -103,6 +103,6 @@ func identityConfig(out io.Writer, nbits int) (Identity, error) { return ident, err } ident.PeerID = id.Pretty() - fmt.Printf("peer identity: %s\n", ident.PeerID) + fmt.Fprintf(out, "peer identity: %s\n", ident.PeerID) return ident, nil } From 8c84f214f68da2fe768c484e0051b5291cadc84e Mon Sep 17 00:00:00 2001 From: Brian Tiger Chow Date: Tue, 3 Feb 2015 17:19:05 -0800 Subject: [PATCH 017/414] go-ipfs-config: fix(config, eventlog) use int. it plays nicely with everyone else --- config/log.go | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/config/log.go b/config/log.go index 50e7243d45b..abaa5c7cbd9 100644 --- a/config/log.go +++ b/config/log.go @@ -2,7 +2,7 @@ package config type Log struct { - MaxSizeMB uint64 - MaxBackups uint64 - MaxAgeDays uint64 + MaxSizeMB int + MaxBackups int + MaxAgeDays int } From 58445c282471d61486a5169d9ca45c5586d51987 Mon Sep 17 00:00:00 2001 From: Brian Tiger Chow Date: Tue, 3 Feb 2015 17:13:58 -0800 Subject: [PATCH 018/414] go-ipfs-config: fix(config) use max backups to limit number of backups --- config/init.go | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/config/init.go b/config/init.go index 737f174f2f5..0efcf629ab9 100644 --- a/config/init.go +++ b/config/init.go @@ -42,7 +42,8 @@ func Init(out io.Writer, nBitsForKeypair int) (*Config, error) { Datastore: *ds, Identity: identity, Log: Log{ - MaxSizeMB: 500, + MaxSizeMB: 250, + MaxBackups: 1, }, // setup the node mount points. From 57814a36bfcc20204c6c6c5182c44100c8977c4b Mon Sep 17 00:00:00 2001 From: Matt Bell Date: Mon, 2 Feb 2015 17:45:16 -0800 Subject: [PATCH 019/414] go-ipfs-config: repo/config: Added default gateway address to initial config --- config/init.go | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/config/init.go b/config/init.go index 0efcf629ab9..49d80c78156 100644 --- a/config/init.go +++ b/config/init.go @@ -35,7 +35,8 @@ func Init(out io.Writer, nBitsForKeypair int) (*Config, error) { "/ip4/0.0.0.0/tcp/4001", // "/ip4/0.0.0.0/udp/4002/utp", // disabled for now. }, - API: "/ip4/127.0.0.1/tcp/5001", + API: "/ip4/127.0.0.1/tcp/5001", + Gateway: "/ip4/127.0.0.1/tcp/8080", }, Bootstrap: BootstrapPeerStrings(bootstrapPeers), From df1e24d846a3ac8a32a646b1856698a6d0f725dd Mon Sep 17 00:00:00 2001 From: Brian Tiger Chow Date: Mon, 2 Feb 2015 01:39:03 -0800 Subject: [PATCH 020/414] go-ipfs-config: feat(config) add GCR config section --- config/config.go | 1 + config/gcr_servers.go | 33 +++++++++++++++++++++++++++++++++ config/init.go | 6 ++++++ 3 files changed, 40 insertions(+) create mode 100644 config/gcr_servers.go diff --git a/config/config.go b/config/config.go index f214b513b58..54473df1075 100644 --- a/config/config.go +++ b/config/config.go @@ -24,6 +24,7 @@ type Config struct { Bootstrap []string // local nodes's bootstrap peer addresses Tour Tour // local node's tour position Gateway Gateway // local node's gateway server options + GCR GCR // local node's routing servers (if GCR enabled) Log Log } diff --git a/config/gcr_servers.go b/config/gcr_servers.go new file mode 100644 index 00000000000..0f9ae962875 --- /dev/null +++ b/config/gcr_servers.go @@ -0,0 +1,33 @@ +package config + +import "github.com/jbenet/go-ipfs/util/ipfsaddr" + +// TODO replace with final servers before merge + +type GCR struct { + Servers []string +} + +var DefaultGCRServers = []string{ + "/ip4/104.236.70.34/tcp/4001/QmaWJw5mcWkCThPtC7hVq28e3WbwLHnWF8HbMNJrRDybE4", + "/ip4/128.199.72.111/tcp/4001/Qmd2cSiZUt7vhiuTmqBB7XWbkuFR8KMLiEuQssjyNXyaZT", +} + +func initGCR() (*GCR, error) { + // TODO perform validation + return &GCR{ + Servers: DefaultGCRServers, + }, nil +} + +func (gcr *GCR) ServerIPFSAddrs() ([]ipfsaddr.IPFSAddr, error) { + var addrs []ipfsaddr.IPFSAddr + for _, server := range gcr.Servers { + addr, err := ipfsaddr.ParseString(server) + if err != nil { + return nil, err + } + addrs = append(addrs, addr) + } + return addrs, nil +} diff --git a/config/init.go b/config/init.go index 49d80c78156..bbd82c44864 100644 --- a/config/init.go +++ b/config/init.go @@ -26,6 +26,11 @@ func Init(out io.Writer, nBitsForKeypair int) (*Config, error) { return nil, err } + gcr, err := initGCR() + if err != nil { + return nil, err + } + conf := &Config{ // setup the node's default addresses. @@ -40,6 +45,7 @@ func Init(out io.Writer, nBitsForKeypair int) (*Config, error) { }, Bootstrap: BootstrapPeerStrings(bootstrapPeers), + GCR: *gcr, Datastore: *ds, Identity: identity, Log: Log{ From 67f8655f18c581fc4629b084111a444a1e2c0e89 Mon Sep 17 00:00:00 2001 From: Brian Tiger Chow Date: Mon, 2 Feb 2015 05:47:36 -0800 Subject: [PATCH 021/414] go-ipfs-config: fix(config/gcr) include protocol --- config/gcr_servers.go | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/config/gcr_servers.go b/config/gcr_servers.go index 0f9ae962875..40f217e1db8 100644 --- a/config/gcr_servers.go +++ b/config/gcr_servers.go @@ -9,8 +9,8 @@ type GCR struct { } var DefaultGCRServers = []string{ - "/ip4/104.236.70.34/tcp/4001/QmaWJw5mcWkCThPtC7hVq28e3WbwLHnWF8HbMNJrRDybE4", - "/ip4/128.199.72.111/tcp/4001/Qmd2cSiZUt7vhiuTmqBB7XWbkuFR8KMLiEuQssjyNXyaZT", + "/ip4/104.236.70.34/tcp/4001/ipfs/QmaWJw5mcWkCThPtC7hVq28e3WbwLHnWF8HbMNJrRDybE4", + "/ip4/128.199.72.111/tcp/4001/ipfs/Qmd2cSiZUt7vhiuTmqBB7XWbkuFR8KMLiEuQssjyNXyaZT", } func initGCR() (*GCR, error) { From b4bc6482c89a560d3d39897502290f5b40ea6d09 Mon Sep 17 00:00:00 2001 From: Brian Tiger Chow Date: Fri, 6 Feb 2015 10:44:54 -0700 Subject: [PATCH 022/414] go-ipfs-config: fix(routingd) update port and servers --- config/gcr_servers.go | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/config/gcr_servers.go b/config/gcr_servers.go index 40f217e1db8..e1faa25d6a1 100644 --- a/config/gcr_servers.go +++ b/config/gcr_servers.go @@ -9,8 +9,8 @@ type GCR struct { } var DefaultGCRServers = []string{ - "/ip4/104.236.70.34/tcp/4001/ipfs/QmaWJw5mcWkCThPtC7hVq28e3WbwLHnWF8HbMNJrRDybE4", - "/ip4/128.199.72.111/tcp/4001/ipfs/Qmd2cSiZUt7vhiuTmqBB7XWbkuFR8KMLiEuQssjyNXyaZT", + "/ip4/107.170.212.195/tcp/4001/ipfs/QmVy5xh7sYKyQxHG4ZatHj9cCu1H5PR1LySKeTfLdJxp1b", + "/ip4/107.170.215.87/tcp/4001/ipfs/QmZDYP9GBjkAmZrS5usSzPnLf41haq6jJhJDmWgnSM4zvW", } func initGCR() (*GCR, error) { From 4b98e19165db0935ca38ac6403bacb20fefebb4f Mon Sep 17 00:00:00 2001 From: Brian Tiger Chow Date: Fri, 6 Feb 2015 11:08:11 -0700 Subject: [PATCH 023/414] go-ipfs-config: fix(repo/config) Update gcr_servers.go TODO rename --- config/gcr_servers.go | 1 + 1 file changed, 1 insertion(+) diff --git a/config/gcr_servers.go b/config/gcr_servers.go index e1faa25d6a1..a6aae090ab1 100644 --- a/config/gcr_servers.go +++ b/config/gcr_servers.go @@ -4,6 +4,7 @@ import "github.com/jbenet/go-ipfs/util/ipfsaddr" // TODO replace with final servers before merge +// TODO rename type GCR struct { Servers []string } From fd2fcf0879c97cec0eee162b935842c5fe4b543a Mon Sep 17 00:00:00 2001 From: Brian Tiger Chow Date: Fri, 6 Feb 2015 13:49:48 -0700 Subject: [PATCH 024/414] go-ipfs-config: fix(corerouting) pass transport addr --- config/config.go | 20 ++++++++++---------- config/init.go | 4 ++-- config/{gcr_servers.go => supernode.go} | 8 ++++---- 3 files changed, 16 insertions(+), 16 deletions(-) rename config/{gcr_servers.go => supernode.go} (75%) diff --git a/config/config.go b/config/config.go index 54473df1075..eec25d8cd85 100644 --- a/config/config.go +++ b/config/config.go @@ -16,16 +16,16 @@ var log = u.Logger("config") // Config is used to load IPFS config files. type Config struct { - Identity Identity // local node's peer identity - Datastore Datastore // local node's storage - Addresses Addresses // local node's addresses - Mounts Mounts // local node's mount points - Version Version // local node's version management - Bootstrap []string // local nodes's bootstrap peer addresses - Tour Tour // local node's tour position - Gateway Gateway // local node's gateway server options - GCR GCR // local node's routing servers (if GCR enabled) - Log Log + Identity Identity // local node's peer identity + Datastore Datastore // local node's storage + Addresses Addresses // local node's addresses + Mounts Mounts // local node's mount points + Version Version // local node's version management + Bootstrap []string // local nodes's bootstrap peer addresses + Tour Tour // local node's tour position + Gateway Gateway // local node's gateway server options + SupernodeRouting SupernodeClientConfig // local node's routing servers (if SupernodeRouting enabled) + Log Log } const ( diff --git a/config/init.go b/config/init.go index bbd82c44864..34ebcebef4a 100644 --- a/config/init.go +++ b/config/init.go @@ -26,7 +26,7 @@ func Init(out io.Writer, nBitsForKeypair int) (*Config, error) { return nil, err } - gcr, err := initGCR() + snr, err := initSNRConfig() if err != nil { return nil, err } @@ -45,7 +45,7 @@ func Init(out io.Writer, nBitsForKeypair int) (*Config, error) { }, Bootstrap: BootstrapPeerStrings(bootstrapPeers), - GCR: *gcr, + SupernodeRouting: *snr, Datastore: *ds, Identity: identity, Log: Log{ diff --git a/config/gcr_servers.go b/config/supernode.go similarity index 75% rename from config/gcr_servers.go rename to config/supernode.go index a6aae090ab1..a812b7a5e07 100644 --- a/config/gcr_servers.go +++ b/config/supernode.go @@ -5,7 +5,7 @@ import "github.com/jbenet/go-ipfs/util/ipfsaddr" // TODO replace with final servers before merge // TODO rename -type GCR struct { +type SupernodeClientConfig struct { Servers []string } @@ -14,14 +14,14 @@ var DefaultGCRServers = []string{ "/ip4/107.170.215.87/tcp/4001/ipfs/QmZDYP9GBjkAmZrS5usSzPnLf41haq6jJhJDmWgnSM4zvW", } -func initGCR() (*GCR, error) { +func initSNRConfig() (*SupernodeClientConfig, error) { // TODO perform validation - return &GCR{ + return &SupernodeClientConfig{ Servers: DefaultGCRServers, }, nil } -func (gcr *GCR) ServerIPFSAddrs() ([]ipfsaddr.IPFSAddr, error) { +func (gcr *SupernodeClientConfig) ServerIPFSAddrs() ([]ipfsaddr.IPFSAddr, error) { var addrs []ipfsaddr.IPFSAddr for _, server := range gcr.Servers { addr, err := ipfsaddr.ParseString(server) From 46a4b1a4087e0380e224e069151b8079f1f5686c Mon Sep 17 00:00:00 2001 From: Brian Tiger Chow Date: Fri, 6 Feb 2015 14:02:34 -0700 Subject: [PATCH 025/414] go-ipfs-config: feat(config/supernode) add 5 supernodes --- config/supernode.go | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/config/supernode.go b/config/supernode.go index a812b7a5e07..dbad8c11dcc 100644 --- a/config/supernode.go +++ b/config/supernode.go @@ -10,8 +10,11 @@ type SupernodeClientConfig struct { } var DefaultGCRServers = []string{ - "/ip4/107.170.212.195/tcp/4001/ipfs/QmVy5xh7sYKyQxHG4ZatHj9cCu1H5PR1LySKeTfLdJxp1b", - "/ip4/107.170.215.87/tcp/4001/ipfs/QmZDYP9GBjkAmZrS5usSzPnLf41haq6jJhJDmWgnSM4zvW", + "/ip4/104.236.176.52/tcp/4002/ipfs/QmXdb7tWTxdFEQEFgWBqkuYSrZd3mXrC7HxkD4krGNYx2U", + "/ip4/104.236.179.241/tcp/4002/ipfs/QmVRqViDByUxjUMoPnjurjKvZhaEMFDtK35FJXHAM4Lkj6", + "/ip4/104.236.151.122/tcp/4002/ipfs/QmSZwGx8Tn8tmcM4PtDJaMeUQNRhNFdBLVGPzRiNaRJtFH", + "/ip4/162.243.248.213/tcp/4002/ipfs/QmbHVEEepCi7rn7VL7Exxpd2Ci9NNB6ifvqwhsrbRMgQFP", + "/ip4/128.199.219.111/tcp/4002/ipfs/Qmb3brdCYmKG1ycwqCbo6LUwWxTuo3FisnJV2yir7oN92R", } func initSNRConfig() (*SupernodeClientConfig, error) { From 0ca9469bf37cdfcc457502233ac0f47d94fa27d2 Mon Sep 17 00:00:00 2001 From: Brian Tiger Chow Date: Thu, 12 Feb 2015 14:37:22 -0800 Subject: [PATCH 026/414] go-ipfs-config: add three more supernode routers --- config/supernode.go | 3 +++ 1 file changed, 3 insertions(+) diff --git a/config/supernode.go b/config/supernode.go index dbad8c11dcc..6d301dc1528 100644 --- a/config/supernode.go +++ b/config/supernode.go @@ -15,6 +15,9 @@ var DefaultGCRServers = []string{ "/ip4/104.236.151.122/tcp/4002/ipfs/QmSZwGx8Tn8tmcM4PtDJaMeUQNRhNFdBLVGPzRiNaRJtFH", "/ip4/162.243.248.213/tcp/4002/ipfs/QmbHVEEepCi7rn7VL7Exxpd2Ci9NNB6ifvqwhsrbRMgQFP", "/ip4/128.199.219.111/tcp/4002/ipfs/Qmb3brdCYmKG1ycwqCbo6LUwWxTuo3FisnJV2yir7oN92R", + "/ip4/104.236.76.40/tcp/4002/ipfs/QmdRBCV8Cz2dGhoKLkD3YjPwVFECmqADQkx5ZteF2c6Fy4", + "/ip4/178.62.158.247/tcp/4002/ipfs/QmUdiMPci7YoEUBkyFZAh2pAbjqcPr7LezyiPD2artLw3v", + "/ip4/178.62.61.185/tcp/4002/ipfs/QmVw6fGNqBixZE4bewRLT2VXX7fAHUHs8JyidDiJ1P7RUN", } func initSNRConfig() (*SupernodeClientConfig, error) { From 44ef2bab38d01a9b43616014cbcc0c584197e14c Mon Sep 17 00:00:00 2001 From: Brian Tiger Chow Date: Sun, 15 Feb 2015 06:28:03 -0800 Subject: [PATCH 027/414] go-ipfs-config: fix(config) rename variable GCR -> SNR --- config/supernode.go | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/config/supernode.go b/config/supernode.go index 6d301dc1528..ccc5be3dd0f 100644 --- a/config/supernode.go +++ b/config/supernode.go @@ -9,7 +9,7 @@ type SupernodeClientConfig struct { Servers []string } -var DefaultGCRServers = []string{ +var DefaultSNRServers = []string{ "/ip4/104.236.176.52/tcp/4002/ipfs/QmXdb7tWTxdFEQEFgWBqkuYSrZd3mXrC7HxkD4krGNYx2U", "/ip4/104.236.179.241/tcp/4002/ipfs/QmVRqViDByUxjUMoPnjurjKvZhaEMFDtK35FJXHAM4Lkj6", "/ip4/104.236.151.122/tcp/4002/ipfs/QmSZwGx8Tn8tmcM4PtDJaMeUQNRhNFdBLVGPzRiNaRJtFH", @@ -23,7 +23,7 @@ var DefaultGCRServers = []string{ func initSNRConfig() (*SupernodeClientConfig, error) { // TODO perform validation return &SupernodeClientConfig{ - Servers: DefaultGCRServers, + Servers: DefaultSNRServers, }, nil } From 25c4d28de9a55615eb276a57016e220d6449b0ea Mon Sep 17 00:00:00 2001 From: Ho-Sheng Hsiao Date: Mon, 30 Mar 2015 20:04:32 -0700 Subject: [PATCH 028/414] go-ipfs-config: Reorged imports from jbenet/go-ipfs to ipfs/go-ipfs - Modified Godeps/Godeps.json by hand - [TEST] Updated welcome docs hash to sharness - [TEST] Updated contact doc - [TEST] disabled breaking test (t0080-repo refs local) --- config/bootstrap_peers.go | 4 ++-- config/config.go | 2 +- config/identity.go | 2 +- config/init.go | 6 +++--- config/supernode.go | 2 +- 5 files changed, 8 insertions(+), 8 deletions(-) diff --git a/config/bootstrap_peers.go b/config/bootstrap_peers.go index de4935d7856..af18ab17baf 100644 --- a/config/bootstrap_peers.go +++ b/config/bootstrap_peers.go @@ -1,9 +1,9 @@ package config import ( - errors "github.com/jbenet/go-ipfs/util/debugerror" + errors "github.com/ipfs/go-ipfs/util/debugerror" - iaddr "github.com/jbenet/go-ipfs/util/ipfsaddr" + iaddr "github.com/ipfs/go-ipfs/util/ipfsaddr" ) // DefaultBootstrapAddresses are the hardcoded bootstrap addresses diff --git a/config/config.go b/config/config.go index eec25d8cd85..6876f9603f5 100644 --- a/config/config.go +++ b/config/config.go @@ -9,7 +9,7 @@ import ( "path/filepath" "strings" - u "github.com/jbenet/go-ipfs/util" + u "github.com/ipfs/go-ipfs/util" ) var log = u.Logger("config") diff --git a/config/identity.go b/config/identity.go index 2097e51886d..d2298fbcd86 100644 --- a/config/identity.go +++ b/config/identity.go @@ -2,7 +2,7 @@ package config import ( "encoding/base64" - ic "github.com/jbenet/go-ipfs/p2p/crypto" + ic "github.com/ipfs/go-ipfs/p2p/crypto" ) // Identity tracks the configuration of the local node's identity. diff --git a/config/init.go b/config/init.go index 34ebcebef4a..8f456f690c9 100644 --- a/config/init.go +++ b/config/init.go @@ -5,9 +5,9 @@ import ( "fmt" "io" - ci "github.com/jbenet/go-ipfs/p2p/crypto" - peer "github.com/jbenet/go-ipfs/p2p/peer" - errors "github.com/jbenet/go-ipfs/util/debugerror" + ci "github.com/ipfs/go-ipfs/p2p/crypto" + peer "github.com/ipfs/go-ipfs/p2p/peer" + errors "github.com/ipfs/go-ipfs/util/debugerror" ) func Init(out io.Writer, nBitsForKeypair int) (*Config, error) { diff --git a/config/supernode.go b/config/supernode.go index ccc5be3dd0f..30ee6f22e55 100644 --- a/config/supernode.go +++ b/config/supernode.go @@ -1,6 +1,6 @@ package config -import "github.com/jbenet/go-ipfs/util/ipfsaddr" +import "github.com/ipfs/go-ipfs/util/ipfsaddr" // TODO replace with final servers before merge From 154216d34d48d00a4af1c70ea6f6d0ce5550225d Mon Sep 17 00:00:00 2001 From: Ho-Sheng Hsiao Date: Tue, 31 Mar 2015 17:13:28 -0700 Subject: [PATCH 029/414] go-ipfs-config: Added fuse allow_other option ipfs config Mounts.FuseAllowOther --bool true ipfs daemon --mount --- config/mounts.go | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/config/mounts.go b/config/mounts.go index a0f42005943..b23d30b2ef3 100644 --- a/config/mounts.go +++ b/config/mounts.go @@ -2,6 +2,7 @@ package config // Mounts stores the (string) mount points type Mounts struct { - IPFS string - IPNS string + IPFS string + IPNS string + FuseAllowOther bool } From ffacc10342daa4778ebe90a3d64df06173c578c3 Mon Sep 17 00:00:00 2001 From: Baptiste Jonglez Date: Tue, 14 Apr 2015 14:26:51 +0200 Subject: [PATCH 030/414] go-ipfs-config: Default config: listen on IPv6 for the swarm address --- config/init.go | 1 + 1 file changed, 1 insertion(+) diff --git a/config/init.go b/config/init.go index 8f456f690c9..05e6eb107b8 100644 --- a/config/init.go +++ b/config/init.go @@ -39,6 +39,7 @@ func Init(out io.Writer, nBitsForKeypair int) (*Config, error) { Swarm: []string{ "/ip4/0.0.0.0/tcp/4001", // "/ip4/0.0.0.0/udp/4002/utp", // disabled for now. + "/ip6/::/tcp/4001", }, API: "/ip4/127.0.0.1/tcp/5001", Gateway: "/ip4/127.0.0.1/tcp/8080", From 6457cc5ab8ec020f24c7b4cc883ebf4254a0124d Mon Sep 17 00:00:00 2001 From: Juan Batiz-Benet Date: Mon, 20 Apr 2015 00:15:34 -0700 Subject: [PATCH 031/414] go-ipfs-config: remove debugerrors We now consider debugerrors harmful: we've run into cases where debugerror.Wrap() hid valuable error information (err == io.EOF?). I've removed them from the main code, but left them in some tests. Go errors are lacking, but unfortunately, this isn't the solution. It is possible that debugerros.New or debugerrors.Errorf should remain still (i.e. only remove debugerrors.Wrap) but we don't use these errors often enough to keep. --- config/bootstrap_peers.go | 5 +++-- config/gateway.go | 2 +- config/init.go | 10 +++++----- config/log.go | 1 - 4 files changed, 9 insertions(+), 9 deletions(-) diff --git a/config/bootstrap_peers.go b/config/bootstrap_peers.go index af18ab17baf..5fefae92f36 100644 --- a/config/bootstrap_peers.go +++ b/config/bootstrap_peers.go @@ -1,7 +1,8 @@ package config import ( - errors "github.com/ipfs/go-ipfs/util/debugerror" + "errors" + "fmt" iaddr "github.com/ipfs/go-ipfs/util/ipfsaddr" ) @@ -40,7 +41,7 @@ func (c *Config) BootstrapPeers() ([]BootstrapPeer, error) { func DefaultBootstrapPeers() ([]BootstrapPeer, error) { ps, err := ParseBootstrapPeers(DefaultBootstrapAddresses) if err != nil { - return nil, errors.Errorf(`failed to parse hardcoded bootstrap peers: %s + return nil, fmt.Errorf(`failed to parse hardcoded bootstrap peers: %s This is a problem with the ipfs codebase. Please report it to the dev team.`, err) } return ps, nil diff --git a/config/gateway.go b/config/gateway.go index c0885778d57..dfb72880c60 100644 --- a/config/gateway.go +++ b/config/gateway.go @@ -3,5 +3,5 @@ package config // Gateway contains options for the HTTP gateway server. type Gateway struct { RootRedirect string - Writable bool + Writable bool } diff --git a/config/init.go b/config/init.go index 8f456f690c9..2b4bf2a0880 100644 --- a/config/init.go +++ b/config/init.go @@ -2,12 +2,12 @@ package config import ( "encoding/base64" + "errors" "fmt" "io" ci "github.com/ipfs/go-ipfs/p2p/crypto" peer "github.com/ipfs/go-ipfs/p2p/peer" - errors "github.com/ipfs/go-ipfs/util/debugerror" ) func Init(out io.Writer, nBitsForKeypair int) (*Config, error) { @@ -44,10 +44,10 @@ func Init(out io.Writer, nBitsForKeypair int) (*Config, error) { Gateway: "/ip4/127.0.0.1/tcp/8080", }, - Bootstrap: BootstrapPeerStrings(bootstrapPeers), - SupernodeRouting: *snr, - Datastore: *ds, - Identity: identity, + Bootstrap: BootstrapPeerStrings(bootstrapPeers), + SupernodeRouting: *snr, + Datastore: *ds, + Identity: identity, Log: Log{ MaxSizeMB: 250, MaxBackups: 1, diff --git a/config/log.go b/config/log.go index abaa5c7cbd9..81aebf05979 100644 --- a/config/log.go +++ b/config/log.go @@ -1,6 +1,5 @@ package config - type Log struct { MaxSizeMB int MaxBackups int From c685f571eab02b397b76a528b55472fc6a2222b8 Mon Sep 17 00:00:00 2001 From: Christian Couder Date: Sun, 29 Mar 2015 13:25:01 +0200 Subject: [PATCH 032/414] go-ipfs-config: config: change default config dir name to .ipfs This changes .go-ipfs to .ipfs everywhere. And by the way this defines a DefaultPathName const for this name. License: MIT Signed-off-by: Christian Couder --- config/config.go | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/config/config.go b/config/config.go index 6876f9603f5..83cd2abb9db 100644 --- a/config/config.go +++ b/config/config.go @@ -29,8 +29,10 @@ type Config struct { } const ( + // DefaultPathName is the default config dir name + DefaultPathName = ".ipfs" // DefaultPathRoot is the path to the default config dir location. - DefaultPathRoot = "~/.go-ipfs" + DefaultPathRoot = "~/" + DefaultPathName // DefaultConfigFile is the filename of the configuration file DefaultConfigFile = "config" // EnvDir is the environment variable used to change the path root. From d5503594e3cb1388a822d4a5d836ed4c6e266930 Mon Sep 17 00:00:00 2001 From: Jeromy Date: Wed, 22 Apr 2015 00:55:31 -0700 Subject: [PATCH 033/414] go-ipfs-config: implement a config option for mdns --- config/config.go | 1 + config/discovery.go | 12 ++++++++++++ config/init.go | 4 ++++ 3 files changed, 17 insertions(+) create mode 100644 config/discovery.go diff --git a/config/config.go b/config/config.go index 83cd2abb9db..1d2fa87ad7c 100644 --- a/config/config.go +++ b/config/config.go @@ -21,6 +21,7 @@ type Config struct { Addresses Addresses // local node's addresses Mounts Mounts // local node's mount points Version Version // local node's version management + Discovery Discovery // local node's discovery mechanisms Bootstrap []string // local nodes's bootstrap peer addresses Tour Tour // local node's tour position Gateway Gateway // local node's gateway server options diff --git a/config/discovery.go b/config/discovery.go new file mode 100644 index 00000000000..4fb8508f00a --- /dev/null +++ b/config/discovery.go @@ -0,0 +1,12 @@ +package config + +type Discovery struct { + MDNS MDNS +} + +type MDNS struct { + Enabled bool + + // Time in seconds between discovery rounds + Interval int +} diff --git a/config/init.go b/config/init.go index 2b4bf2a0880..76ee1fdc144 100644 --- a/config/init.go +++ b/config/init.go @@ -48,6 +48,10 @@ func Init(out io.Writer, nBitsForKeypair int) (*Config, error) { SupernodeRouting: *snr, Datastore: *ds, Identity: identity, + Discovery: Discovery{MDNS{ + Enabled: true, + Interval: 10, + }}, Log: Log{ MaxSizeMB: 250, MaxBackups: 1, From 316b2d1de9a60888c479871a40c92c538c567c6e Mon Sep 17 00:00:00 2001 From: rht Date: Tue, 26 May 2015 23:18:04 +0700 Subject: [PATCH 034/414] go-ipfs-config: Replace 'var * bytes.Buffer' with '\1 := new(bytes.Buffer)' --- config/config.go | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/config/config.go b/config/config.go index 1d2fa87ad7c..c9a8aabec68 100644 --- a/config/config.go +++ b/config/config.go @@ -86,24 +86,24 @@ func Marshal(value interface{}) ([]byte, error) { } func FromMap(v map[string]interface{}) (*Config, error) { - var buf bytes.Buffer - if err := json.NewEncoder(&buf).Encode(v); err != nil { + buf := new(bytes.Buffer) + if err := json.NewEncoder(buf).Encode(v); err != nil { return nil, err } var conf Config - if err := json.NewDecoder(&buf).Decode(&conf); err != nil { + if err := json.NewDecoder(buf).Decode(&conf); err != nil { return nil, fmt.Errorf("Failure to decode config: %s", err) } return &conf, nil } func ToMap(conf *Config) (map[string]interface{}, error) { - var buf bytes.Buffer - if err := json.NewEncoder(&buf).Encode(conf); err != nil { + buf := new(bytes.Buffer) + if err := json.NewEncoder(buf).Encode(conf); err != nil { return nil, err } var m map[string]interface{} - if err := json.NewDecoder(&buf).Decode(&m); err != nil { + if err := json.NewDecoder(buf).Decode(&m); err != nil { return nil, fmt.Errorf("Failure to decode config: %s", err) } return m, nil From eb6a0a5d89c5a5ff4ce1d15cf03cb74e88962f9a Mon Sep 17 00:00:00 2001 From: Jeromy Date: Tue, 16 Jun 2015 11:06:04 -0700 Subject: [PATCH 035/414] go-ipfs-config: add in basic address dial filtering License: MIT Signed-off-by: Jeromy --- config/config.go | 1 + 1 file changed, 1 insertion(+) diff --git a/config/config.go b/config/config.go index c9a8aabec68..e7474cf7e09 100644 --- a/config/config.go +++ b/config/config.go @@ -26,6 +26,7 @@ type Config struct { Tour Tour // local node's tour position Gateway Gateway // local node's gateway server options SupernodeRouting SupernodeClientConfig // local node's routing servers (if SupernodeRouting enabled) + DialBlocklist []string Log Log } From 3861ff304e1d52060ed165b842bb5845827b63cd Mon Sep 17 00:00:00 2001 From: Juan Batiz-Benet Date: Thu, 2 Jul 2015 16:11:46 -0700 Subject: [PATCH 036/414] go-ipfs-config: config: DialBlocklist -> Swarm.AddrFilters This commit changes the DialBlocklist key to be under the key Swarm.AddrFilters instead. License: MIT Signed-off-by: Juan Batiz-Benet --- config/config.go | 2 +- config/swarm.go | 5 +++++ 2 files changed, 6 insertions(+), 1 deletion(-) create mode 100644 config/swarm.go diff --git a/config/config.go b/config/config.go index e7474cf7e09..ad493a18995 100644 --- a/config/config.go +++ b/config/config.go @@ -26,7 +26,7 @@ type Config struct { Tour Tour // local node's tour position Gateway Gateway // local node's gateway server options SupernodeRouting SupernodeClientConfig // local node's routing servers (if SupernodeRouting enabled) - DialBlocklist []string + Swarm SwarmConfig Log Log } diff --git a/config/swarm.go b/config/swarm.go new file mode 100644 index 00000000000..d398b3d80af --- /dev/null +++ b/config/swarm.go @@ -0,0 +1,5 @@ +package config + +type SwarmConfig struct { + AddrFilters []string +} From b73f2d531d1d0159fd4790c562b71cd16578d993 Mon Sep 17 00:00:00 2001 From: Juan Batiz-Benet Date: Thu, 23 Jul 2015 18:44:46 -0700 Subject: [PATCH 037/414] go-ipfs-config: Added API + Gateway support for arbitrary HTTP headers This commit fixes + improves CORS support License: MIT Signed-off-by: Juan Batiz-Benet --- config/api.go | 5 +++++ config/config.go | 1 + config/gateway.go | 1 + 3 files changed, 7 insertions(+) create mode 100644 config/api.go diff --git a/config/api.go b/config/api.go new file mode 100644 index 00000000000..b36b1080304 --- /dev/null +++ b/config/api.go @@ -0,0 +1,5 @@ +package config + +type API struct { + HTTPHeaders map[string][]string // HTTP headers to return with the API. +} diff --git a/config/config.go b/config/config.go index ad493a18995..42b56550c9e 100644 --- a/config/config.go +++ b/config/config.go @@ -26,6 +26,7 @@ type Config struct { Tour Tour // local node's tour position Gateway Gateway // local node's gateway server options SupernodeRouting SupernodeClientConfig // local node's routing servers (if SupernodeRouting enabled) + API API // local node's API settings Swarm SwarmConfig Log Log } diff --git a/config/gateway.go b/config/gateway.go index dfb72880c60..07bc9aad2cb 100644 --- a/config/gateway.go +++ b/config/gateway.go @@ -2,6 +2,7 @@ package config // Gateway contains options for the HTTP gateway server. type Gateway struct { + HTTPHeaders map[string][]string // HTTP headers to return with the gateway RootRedirect string Writable bool } From 809269399ecd49cc509d86c40144a84bc1ebbc3c Mon Sep 17 00:00:00 2001 From: Jeromy Date: Mon, 14 Sep 2015 17:33:03 -0700 Subject: [PATCH 038/414] go-ipfs-config: extract logging License: MIT Signed-off-by: Jeromy --- config/config.go | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/config/config.go b/config/config.go index 42b56550c9e..77573e9145d 100644 --- a/config/config.go +++ b/config/config.go @@ -10,9 +10,10 @@ import ( "strings" u "github.com/ipfs/go-ipfs/util" + logging "github.com/ipfs/go-ipfs/vendor/go-log-v1.0.0" ) -var log = u.Logger("config") +var log = logging.Logger("config") // Config is used to load IPFS config files. type Config struct { From 4f6eb40056dd948423b449952c31a67157dd950b Mon Sep 17 00:00:00 2001 From: Jeromy Date: Mon, 21 Sep 2015 16:35:33 -0700 Subject: [PATCH 039/414] go-ipfs-config: Implement ipns republisher This commit adds a very basic process that will periodically go through a list of given ids and republish the values for their ipns entries. License: MIT Signed-off-by: Jeromy --- config/config.go | 1 + config/ipns.go | 5 +++++ 2 files changed, 6 insertions(+) create mode 100644 config/ipns.go diff --git a/config/config.go b/config/config.go index 77573e9145d..3430bb1b129 100644 --- a/config/config.go +++ b/config/config.go @@ -23,6 +23,7 @@ type Config struct { Mounts Mounts // local node's mount points Version Version // local node's version management Discovery Discovery // local node's discovery mechanisms + Ipns Ipns // Ipns settings Bootstrap []string // local nodes's bootstrap peer addresses Tour Tour // local node's tour position Gateway Gateway // local node's gateway server options diff --git a/config/ipns.go b/config/ipns.go new file mode 100644 index 00000000000..feb77be10ba --- /dev/null +++ b/config/ipns.go @@ -0,0 +1,5 @@ +package config + +type Ipns struct { + RepublishPeriod string +} From a28d610d804be028408d027163d717efd8977bf3 Mon Sep 17 00:00:00 2001 From: Jeromy Date: Wed, 30 Sep 2015 11:03:44 -0700 Subject: [PATCH 040/414] go-ipfs-config: make publish more configurable and add test for repub License: MIT Signed-off-by: Jeromy --- config/ipns.go | 1 + 1 file changed, 1 insertion(+) diff --git a/config/ipns.go b/config/ipns.go index feb77be10ba..feab6f044f7 100644 --- a/config/ipns.go +++ b/config/ipns.go @@ -2,4 +2,5 @@ package config type Ipns struct { RepublishPeriod string + RecordLifetime string } From f6c74ee68bf8fe74cc2c05200a5a8f96f9344601 Mon Sep 17 00:00:00 2001 From: Jeromy Date: Thu, 1 Oct 2015 11:22:28 -0700 Subject: [PATCH 041/414] go-ipfs-config: replace imports with absolute path instead of using symlink License: MIT Signed-off-by: Jeromy --- config/config.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/config/config.go b/config/config.go index 3430bb1b129..09c11d31428 100644 --- a/config/config.go +++ b/config/config.go @@ -10,7 +10,7 @@ import ( "strings" u "github.com/ipfs/go-ipfs/util" - logging "github.com/ipfs/go-ipfs/vendor/go-log-v1.0.0" + logging "github.com/ipfs/go-ipfs/vendor/QmXJkcEXB6C9h6Ytb6rrUTFU56Ro62zxgrbxTT3dgjQGA8/go-log" ) var log = logging.Logger("config") From bdee8cb3ad2f562f17274d93ea3f7e228727aaeb Mon Sep 17 00:00:00 2001 From: Lars Gierth Date: Thu, 24 Sep 2015 22:11:12 +0200 Subject: [PATCH 042/414] go-ipfs-config: config: update bootstrap list hostname License: MIT Signed-off-by: Lars Gierth --- config/bootstrap_peers.go | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/config/bootstrap_peers.go b/config/bootstrap_peers.go index 5fefae92f36..25153f7f373 100644 --- a/config/bootstrap_peers.go +++ b/config/bootstrap_peers.go @@ -15,14 +15,14 @@ import ( // import dependency issue. TODO: move this into a config/default/ package. var DefaultBootstrapAddresses = []string{ "/ip4/104.131.131.82/tcp/4001/ipfs/QmaCpDMGvV2BGHeYERUEnRQAwe3N8SzbUtfsmvsqQLuvuJ", // mars.i.ipfs.io - "/ip4/104.236.176.52/tcp/4001/ipfs/QmSoLnSGccFuZQJzRadHn95W2CrSFmZuTdDWP8HXaHca9z", // neptune (to be neptune.i.ipfs.io) - "/ip4/104.236.179.241/tcp/4001/ipfs/QmSoLpPVmHKQ4XTPdz8tjDFgdeRFkpV8JgYq8JVJ69RrZm", // pluto (to be pluto.i.ipfs.io) - "/ip4/162.243.248.213/tcp/4001/ipfs/QmSoLueR4xBeUbY9WZ9xGUUxunbKWcrNFTDAadQJmocnWm", // uranus (to be uranus.i.ipfs.io) - "/ip4/128.199.219.111/tcp/4001/ipfs/QmSoLSafTMBsPKadTEgaXctDQVcqN88CNLHXMkTNwMKPnu", // saturn (to be saturn.i.ipfs.io) - "/ip4/104.236.76.40/tcp/4001/ipfs/QmSoLV4Bbm51jM9C4gDYZQ9Cy3U6aXMJDAbzgu2fzaDs64", // venus (to be venus.i.ipfs.io) - "/ip4/178.62.158.247/tcp/4001/ipfs/QmSoLer265NRgSp2LA3dPaeykiS1J6DifTC88f5uVQKNAd", // earth (to be earth.i.ipfs.io) - "/ip4/178.62.61.185/tcp/4001/ipfs/QmSoLMeWqB7YGVLJN3pNLQpmmEk35v6wYtsMGLzSr5QBU3", // mercury (to be mercury.i.ipfs.io) - "/ip4/104.236.151.122/tcp/4001/ipfs/QmSoLju6m7xTh3DuokvT3886QRYqxAzb1kShaanJgW36yx", // jupiter (to be jupiter.i.ipfs.io) + "/ip4/104.236.176.52/tcp/4001/ipfs/QmSoLnSGccFuZQJzRadHn95W2CrSFmZuTdDWP8HXaHca9z", // neptune.i.ipfs.io + "/ip4/104.236.179.241/tcp/4001/ipfs/QmSoLpPVmHKQ4XTPdz8tjDFgdeRFkpV8JgYq8JVJ69RrZm", // pluto.i.ipfs.io + "/ip4/162.243.248.213/tcp/4001/ipfs/QmSoLueR4xBeUbY9WZ9xGUUxunbKWcrNFTDAadQJmocnWm", // uranus.i.ipfs.io + "/ip4/128.199.219.111/tcp/4001/ipfs/QmSoLSafTMBsPKadTEgaXctDQVcqN88CNLHXMkTNwMKPnu", // saturn.i.ipfs.io + "/ip4/104.236.76.40/tcp/4001/ipfs/QmSoLV4Bbm51jM9C4gDYZQ9Cy3U6aXMJDAbzgu2fzaDs64", // venus.i.ipfs.io + "/ip4/178.62.158.247/tcp/4001/ipfs/QmSoLer265NRgSp2LA3dPaeykiS1J6DifTC88f5uVQKNAd", // earth.i.ipfs.io + "/ip4/178.62.61.185/tcp/4001/ipfs/QmSoLMeWqB7YGVLJN3pNLQpmmEk35v6wYtsMGLzSr5QBU3", // mercury.i.ipfs.io + "/ip4/104.236.151.122/tcp/4001/ipfs/QmSoLju6m7xTh3DuokvT3886QRYqxAzb1kShaanJgW36yx", // jupiter.i.ipfs.io } // BootstrapPeer is a peer used to bootstrap the network. From bf8e4ab52c7944f9c305765be266bffc2097ca89 Mon Sep 17 00:00:00 2001 From: Lars Gierth Date: Sun, 4 Oct 2015 23:16:35 +0200 Subject: [PATCH 043/414] go-ipfs-config: config: update pluto's peerID We lost its private key a while ago... License: MIT Signed-off-by: Lars Gierth --- config/bootstrap_peers.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/config/bootstrap_peers.go b/config/bootstrap_peers.go index 25153f7f373..fa607c84252 100644 --- a/config/bootstrap_peers.go +++ b/config/bootstrap_peers.go @@ -16,7 +16,7 @@ import ( var DefaultBootstrapAddresses = []string{ "/ip4/104.131.131.82/tcp/4001/ipfs/QmaCpDMGvV2BGHeYERUEnRQAwe3N8SzbUtfsmvsqQLuvuJ", // mars.i.ipfs.io "/ip4/104.236.176.52/tcp/4001/ipfs/QmSoLnSGccFuZQJzRadHn95W2CrSFmZuTdDWP8HXaHca9z", // neptune.i.ipfs.io - "/ip4/104.236.179.241/tcp/4001/ipfs/QmSoLpPVmHKQ4XTPdz8tjDFgdeRFkpV8JgYq8JVJ69RrZm", // pluto.i.ipfs.io + "/ip4/104.236.179.241/tcp/4001/ipfs/QmSoLPppuBtQSGwKDZT2M73ULpjvfd3aZ6ha4oFGL1KrGM", // pluto.i.ipfs.io "/ip4/162.243.248.213/tcp/4001/ipfs/QmSoLueR4xBeUbY9WZ9xGUUxunbKWcrNFTDAadQJmocnWm", // uranus.i.ipfs.io "/ip4/128.199.219.111/tcp/4001/ipfs/QmSoLSafTMBsPKadTEgaXctDQVcqN88CNLHXMkTNwMKPnu", // saturn.i.ipfs.io "/ip4/104.236.76.40/tcp/4001/ipfs/QmSoLV4Bbm51jM9C4gDYZQ9Cy3U6aXMJDAbzgu2fzaDs64", // venus.i.ipfs.io From b6d1a3f6ee43aececb8e7a051b965f32ff49389b Mon Sep 17 00:00:00 2001 From: Jeromy Date: Tue, 27 Oct 2015 10:47:32 -0700 Subject: [PATCH 044/414] go-ipfs-config: update code to use new logging changes License: MIT Signed-off-by: Jeromy --- config/config.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/config/config.go b/config/config.go index 09c11d31428..ce96f594ebf 100644 --- a/config/config.go +++ b/config/config.go @@ -10,7 +10,7 @@ import ( "strings" u "github.com/ipfs/go-ipfs/util" - logging "github.com/ipfs/go-ipfs/vendor/QmXJkcEXB6C9h6Ytb6rrUTFU56Ro62zxgrbxTT3dgjQGA8/go-log" + logging "github.com/ipfs/go-ipfs/vendor/QmTBXYb6y2ZcJmoXVKk3pf9rzSEjbCg7tQaJW7RSuH14nv/go-log" ) var log = logging.Logger("config") From d84895e0d953e40493b13413cc217b97ae9f3f54 Mon Sep 17 00:00:00 2001 From: Jeromy Date: Thu, 22 Oct 2015 16:27:31 -0700 Subject: [PATCH 045/414] go-ipfs-config: cache ipns entries to speed things up a little License: MIT Signed-off-by: Jeromy --- config/init.go | 4 ++++ config/ipns.go | 2 ++ 2 files changed, 6 insertions(+) diff --git a/config/init.go b/config/init.go index 49d0a1ecb08..970597a65cd 100644 --- a/config/init.go +++ b/config/init.go @@ -64,6 +64,10 @@ func Init(out io.Writer, nBitsForKeypair int) (*Config, error) { IPNS: "/ipns", }, + Ipns: Ipns{ + ResolveCacheSize: 128, + }, + // tracking ipfs version used to generate the init folder and adding // update checker default setting. Version: VersionDefaultValue(), diff --git a/config/ipns.go b/config/ipns.go index feab6f044f7..44a95b0990c 100644 --- a/config/ipns.go +++ b/config/ipns.go @@ -3,4 +3,6 @@ package config type Ipns struct { RepublishPeriod string RecordLifetime string + + ResolveCacheSize int } From 1e4bd881172a8d523f00b45fe6af34c67e77e2e7 Mon Sep 17 00:00:00 2001 From: Jeromy Date: Thu, 29 Oct 2015 21:22:53 -0700 Subject: [PATCH 046/414] go-ipfs-config: vendor logging lib update License: MIT Signed-off-by: Jeromy --- config/config.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/config/config.go b/config/config.go index ce96f594ebf..0b8b721ee0d 100644 --- a/config/config.go +++ b/config/config.go @@ -10,7 +10,7 @@ import ( "strings" u "github.com/ipfs/go-ipfs/util" - logging "github.com/ipfs/go-ipfs/vendor/QmTBXYb6y2ZcJmoXVKk3pf9rzSEjbCg7tQaJW7RSuH14nv/go-log" + logging "github.com/ipfs/go-ipfs/vendor/QmQg1J6vikuXF9oDvm4wpdeAUvvkVEKW1EYDw9HhTMnP2b/go-log" ) var log = logging.Logger("config") From 14cf564b3a1a7d7956677c60448b724c45a3b2f7 Mon Sep 17 00:00:00 2001 From: rht Date: Tue, 20 Oct 2015 10:56:41 +0700 Subject: [PATCH 047/414] go-ipfs-config: Add fixed period repo GC + test License: MIT Signed-off-by: rht --- config/datastore.go | 7 +++++-- config/init.go | 7 +++++-- 2 files changed, 10 insertions(+), 4 deletions(-) diff --git a/config/datastore.go b/config/datastore.go index b615c650f25..6749a4c39a0 100644 --- a/config/datastore.go +++ b/config/datastore.go @@ -5,8 +5,11 @@ const DefaultDataStoreDirectory = "datastore" // Datastore tracks the configuration of the datastore. type Datastore struct { - Type string - Path string + Type string + Path string + StorageMax string // in B, kB, kiB, MB, ... + StorageGCWatermark int64 // in percentage to multiply on StorageMax + GCPeriod string // in ns, us, ms, s, m, h } // DataStorePath returns the default data store path given a configuration root diff --git a/config/init.go b/config/init.go index 970597a65cd..4d50ac6611f 100644 --- a/config/init.go +++ b/config/init.go @@ -87,8 +87,11 @@ func datastoreConfig() (*Datastore, error) { return nil, err } return &Datastore{ - Path: dspath, - Type: "leveldb", + Path: dspath, + Type: "leveldb", + StorageMax: "10GB", + StorageGCWatermark: 90, // 90% + GCPeriod: "1h", }, nil } From 5ed0af64381f1983874997f21221136d62ff861e Mon Sep 17 00:00:00 2001 From: Lars Gierth Date: Wed, 11 Nov 2015 18:32:24 +0100 Subject: [PATCH 048/414] go-ipfs-config: repo: remove Log config We stopped logging to files in a676b5a8ac2848a57318283f4b2b52d7d8686323 and this config section was missed. License: MIT Signed-off-by: Lars Gierth --- config/config.go | 1 - config/init.go | 4 ---- config/log.go | 7 ------- config/logs.go | 1 - 4 files changed, 13 deletions(-) delete mode 100644 config/log.go delete mode 100644 config/logs.go diff --git a/config/config.go b/config/config.go index ce96f594ebf..e40d0d7dca9 100644 --- a/config/config.go +++ b/config/config.go @@ -30,7 +30,6 @@ type Config struct { SupernodeRouting SupernodeClientConfig // local node's routing servers (if SupernodeRouting enabled) API API // local node's API settings Swarm SwarmConfig - Log Log } const ( diff --git a/config/init.go b/config/init.go index 970597a65cd..ab1cea0e8d1 100644 --- a/config/init.go +++ b/config/init.go @@ -53,10 +53,6 @@ func Init(out io.Writer, nBitsForKeypair int) (*Config, error) { Enabled: true, Interval: 10, }}, - Log: Log{ - MaxSizeMB: 250, - MaxBackups: 1, - }, // setup the node mount points. Mounts: Mounts{ diff --git a/config/log.go b/config/log.go deleted file mode 100644 index 81aebf05979..00000000000 --- a/config/log.go +++ /dev/null @@ -1,7 +0,0 @@ -package config - -type Log struct { - MaxSizeMB int - MaxBackups int - MaxAgeDays int -} diff --git a/config/logs.go b/config/logs.go deleted file mode 100644 index d912156bec0..00000000000 --- a/config/logs.go +++ /dev/null @@ -1 +0,0 @@ -package config From e7989f12148dad4799c6afe33e7d4344e21871c6 Mon Sep 17 00:00:00 2001 From: dignifiedquire Date: Fri, 20 Nov 2015 00:28:07 +0100 Subject: [PATCH 049/414] go-ipfs-config: Add correct access control headers to the default api config License: MIT Signed-off-by: Friedel Ziegelmayer --- config/init.go | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/config/init.go b/config/init.go index eaa23d28528..0119d734d3f 100644 --- a/config/init.go +++ b/config/init.go @@ -44,6 +44,16 @@ func Init(out io.Writer, nBitsForKeypair int) (*Config, error) { API: "/ip4/127.0.0.1/tcp/5001", Gateway: "/ip4/127.0.0.1/tcp/8080", }, + API: API{ + HTTPHeaders: map[string][]string{ + "Access-Control-Allow-Headers": []string{ + "X-Stream-Output, X-Chunked-Output", + }, + "Access-Control-Expose-Headers": []string{ + "X-Stream-Output, X-Chunked-Output", + }, + }, + }, Bootstrap: BootstrapPeerStrings(bootstrapPeers), SupernodeRouting: *snr, From 511fb7e96e33f52fac94274240ce65bce2612343 Mon Sep 17 00:00:00 2001 From: dignifiedquire Date: Fri, 20 Nov 2015 20:25:25 +0100 Subject: [PATCH 050/414] go-ipfs-config: Add access-control-headers to gateway config License: MIT Signed-off-by: Friedel Ziegelmayer --- config/init.go | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/config/init.go b/config/init.go index 0119d734d3f..a59423b4c08 100644 --- a/config/init.go +++ b/config/init.go @@ -81,6 +81,14 @@ func Init(out io.Writer, nBitsForKeypair int) (*Config, error) { Gateway: Gateway{ RootRedirect: "", Writable: false, + HTTPHeaders: map[string][]string{ + "Access-Control-Allow-Headers": []string{ + "X-Stream-Output, X-Chunked-Output", + }, + "Access-Control-Expose-Headers": []string{ + "X-Stream-Output, X-Chunked-Output", + }, + }, }, } From 8c25058225ff72b5fc88728cd5c091af11a603aa Mon Sep 17 00:00:00 2001 From: Jeromy Date: Mon, 30 Nov 2015 14:43:37 -0800 Subject: [PATCH 051/414] go-ipfs-config: hard code things License: MIT Signed-off-by: Jeromy --- config/init.go | 18 ------------------ 1 file changed, 18 deletions(-) diff --git a/config/init.go b/config/init.go index a59423b4c08..eaa23d28528 100644 --- a/config/init.go +++ b/config/init.go @@ -44,16 +44,6 @@ func Init(out io.Writer, nBitsForKeypair int) (*Config, error) { API: "/ip4/127.0.0.1/tcp/5001", Gateway: "/ip4/127.0.0.1/tcp/8080", }, - API: API{ - HTTPHeaders: map[string][]string{ - "Access-Control-Allow-Headers": []string{ - "X-Stream-Output, X-Chunked-Output", - }, - "Access-Control-Expose-Headers": []string{ - "X-Stream-Output, X-Chunked-Output", - }, - }, - }, Bootstrap: BootstrapPeerStrings(bootstrapPeers), SupernodeRouting: *snr, @@ -81,14 +71,6 @@ func Init(out io.Writer, nBitsForKeypair int) (*Config, error) { Gateway: Gateway{ RootRedirect: "", Writable: false, - HTTPHeaders: map[string][]string{ - "Access-Control-Allow-Headers": []string{ - "X-Stream-Output, X-Chunked-Output", - }, - "Access-Control-Expose-Headers": []string{ - "X-Stream-Output, X-Chunked-Output", - }, - }, }, } From 1f3ad375416edbda4ab255e3b2a373bf62a25853 Mon Sep 17 00:00:00 2001 From: Tommi Virtanen Date: Tue, 19 May 2015 15:32:41 -0700 Subject: [PATCH 052/414] go-ipfs-config: Remove Config file section "Datastore", it's not used This gives us a clean slate for the new code, avoiding leftovers. License: MIT Signed-off-by: Tommi Virtanen --- config/config.go | 3 ++- config/init.go | 6 ------ 2 files changed, 2 insertions(+), 7 deletions(-) diff --git a/config/config.go b/config/config.go index d8f5720e58d..8c834b4158b 100644 --- a/config/config.go +++ b/config/config.go @@ -18,7 +18,6 @@ var log = logging.Logger("config") // Config is used to load IPFS config files. type Config struct { Identity Identity // local node's peer identity - Datastore Datastore // local node's storage Addresses Addresses // local node's addresses Mounts Mounts // local node's mount points Version Version // local node's version management @@ -30,6 +29,8 @@ type Config struct { SupernodeRouting SupernodeClientConfig // local node's routing servers (if SupernodeRouting enabled) API API // local node's API settings Swarm SwarmConfig + + Datastore Datastore } const ( diff --git a/config/init.go b/config/init.go index eaa23d28528..1835833c568 100644 --- a/config/init.go +++ b/config/init.go @@ -11,11 +11,6 @@ import ( ) func Init(out io.Writer, nBitsForKeypair int) (*Config, error) { - ds, err := datastoreConfig() - if err != nil { - return nil, err - } - identity, err := identityConfig(out, nBitsForKeypair) if err != nil { return nil, err @@ -47,7 +42,6 @@ func Init(out io.Writer, nBitsForKeypair int) (*Config, error) { Bootstrap: BootstrapPeerStrings(bootstrapPeers), SupernodeRouting: *snr, - Datastore: *ds, Identity: identity, Discovery: Discovery{MDNS{ Enabled: true, From 3f419cc59902eaafd6bf650ca4971e61b14866d4 Mon Sep 17 00:00:00 2001 From: Tommi Virtanen Date: Wed, 20 May 2015 10:17:38 -0700 Subject: [PATCH 053/414] go-ipfs-config: Implement pluggable Datastore types, with nothing implemented yet License: MIT Signed-off-by: Tommi Virtanen --- config/config.go | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/config/config.go b/config/config.go index 8c834b4158b..d8f5720e58d 100644 --- a/config/config.go +++ b/config/config.go @@ -18,6 +18,7 @@ var log = logging.Logger("config") // Config is used to load IPFS config files. type Config struct { Identity Identity // local node's peer identity + Datastore Datastore // local node's storage Addresses Addresses // local node's addresses Mounts Mounts // local node's mount points Version Version // local node's version management @@ -29,8 +30,6 @@ type Config struct { SupernodeRouting SupernodeClientConfig // local node's routing servers (if SupernodeRouting enabled) API API // local node's API settings Swarm SwarmConfig - - Datastore Datastore } const ( From 45deffe50ea5823bd59c1d3ef412a4aac7c93402 Mon Sep 17 00:00:00 2001 From: Tommi Virtanen Date: Wed, 20 May 2015 14:32:23 -0700 Subject: [PATCH 054/414] go-ipfs-config: S3 datastore support To test it, set up an S3 bucket (in an AWS region that is not US Standard, for read-after-write consistency), run `ipfs init`, then edit `~/.ipfs/config` to say "Datastore": { "Type": "s3", "Region": "us-west-1", "Bucket": "mahbukkit", "ACL": "private" }, with the right values. Set `AWS_ACCESS_KEY_ID` and `AWS_SECRET_ACCESS_KEY` in the environment and you should be able to run `ipfs add` and `ipfs cat` and see the bucket be populated. No automated tests exist, unfortunately. S3 is thorny to simulate. License: MIT Signed-off-by: Tommi Virtanen --- config/datastore.go | 20 ++++++++++++++++++++ 1 file changed, 20 insertions(+) diff --git a/config/datastore.go b/config/datastore.go index 6749a4c39a0..89ded36f1a2 100644 --- a/config/datastore.go +++ b/config/datastore.go @@ -1,5 +1,9 @@ package config +import ( + "encoding/json" +) + // DefaultDataStoreDirectory is the directory to store all the local IPFS data. const DefaultDataStoreDirectory = "datastore" @@ -10,6 +14,22 @@ type Datastore struct { StorageMax string // in B, kB, kiB, MB, ... StorageGCWatermark int64 // in percentage to multiply on StorageMax GCPeriod string // in ns, us, ms, s, m, h + + Params *json.RawMessage +} + +func (d *Datastore) ParamData() []byte { + if d.Params == nil { + return nil + } + + return []byte(*d.Params) +} + +type S3Datastore struct { + Region string `json:"region"` + Bucket string `json:"bucket"` + ACL string `json:"acl"` } // DataStorePath returns the default data store path given a configuration root From b94954635fcfa56766afa2e7e223b6db96f0fcfb Mon Sep 17 00:00:00 2001 From: rht Date: Thu, 12 Nov 2015 22:28:04 +0700 Subject: [PATCH 055/414] go-ipfs-config: Add config option for flatfs no-sync License: MIT Signed-off-by: rht --- config/datastore.go | 1 + 1 file changed, 1 insertion(+) diff --git a/config/datastore.go b/config/datastore.go index 89ded36f1a2..52582bd5cb5 100644 --- a/config/datastore.go +++ b/config/datastore.go @@ -16,6 +16,7 @@ type Datastore struct { GCPeriod string // in ns, us, ms, s, m, h Params *json.RawMessage + NoSync bool } func (d *Datastore) ParamData() []byte { From ac586580bac16082f5cfaa4e33b783977f963097 Mon Sep 17 00:00:00 2001 From: Jeromy Date: Wed, 27 Jan 2016 14:28:34 -0800 Subject: [PATCH 056/414] go-ipfs-config: initial vendoring of libp2p outside of the repo with gx License: MIT Signed-off-by: Jeromy --- config/config.go | 2 +- config/identity.go | 2 +- config/init.go | 4 ++-- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/config/config.go b/config/config.go index d8f5720e58d..8ea2dbd28a9 100644 --- a/config/config.go +++ b/config/config.go @@ -10,7 +10,7 @@ import ( "strings" u "github.com/ipfs/go-ipfs/util" - logging "github.com/ipfs/go-ipfs/vendor/QmQg1J6vikuXF9oDvm4wpdeAUvvkVEKW1EYDw9HhTMnP2b/go-log" + logging "gx/ipfs/QmaPaGNE2GqnfJjRRpQuQuFHuJn4FZvsrGxdik4kgxCkBi/go-log" ) var log = logging.Logger("config") diff --git a/config/identity.go b/config/identity.go index d2298fbcd86..f938efc3346 100644 --- a/config/identity.go +++ b/config/identity.go @@ -2,7 +2,7 @@ package config import ( "encoding/base64" - ic "github.com/ipfs/go-ipfs/p2p/crypto" + ic "gx/ipfs/QmY3NAw959vbE1oJooP9HchcRdBsbxhgQsEZTRhKgvoSuC/go-libp2p/p2p/crypto" ) // Identity tracks the configuration of the local node's identity. diff --git a/config/init.go b/config/init.go index 1835833c568..74ff3ec6916 100644 --- a/config/init.go +++ b/config/init.go @@ -6,8 +6,8 @@ import ( "fmt" "io" - ci "github.com/ipfs/go-ipfs/p2p/crypto" - peer "github.com/ipfs/go-ipfs/p2p/peer" + ci "gx/ipfs/QmY3NAw959vbE1oJooP9HchcRdBsbxhgQsEZTRhKgvoSuC/go-libp2p/p2p/crypto" + peer "gx/ipfs/QmY3NAw959vbE1oJooP9HchcRdBsbxhgQsEZTRhKgvoSuC/go-libp2p/p2p/peer" ) func Init(out io.Writer, nBitsForKeypair int) (*Config, error) { From 8ff4f93d942e0a7619acea377b2b8f9d7c587303 Mon Sep 17 00:00:00 2001 From: Jeromy Date: Thu, 28 Jan 2016 09:43:06 -0800 Subject: [PATCH 057/414] go-ipfs-config: go-keyspace dep from libp2p added License: MIT Signed-off-by: Jeromy --- config/identity.go | 2 +- config/init.go | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/config/identity.go b/config/identity.go index f938efc3346..a1b944de7ac 100644 --- a/config/identity.go +++ b/config/identity.go @@ -2,7 +2,7 @@ package config import ( "encoding/base64" - ic "gx/ipfs/QmY3NAw959vbE1oJooP9HchcRdBsbxhgQsEZTRhKgvoSuC/go-libp2p/p2p/crypto" + ic "gx/ipfs/QmZxtCsPRgCnCXwVPUjcBiFckkG5NMYM4Pthwe6X4C8uQq/go-libp2p/p2p/crypto" ) // Identity tracks the configuration of the local node's identity. diff --git a/config/init.go b/config/init.go index 74ff3ec6916..e667067986f 100644 --- a/config/init.go +++ b/config/init.go @@ -6,8 +6,8 @@ import ( "fmt" "io" - ci "gx/ipfs/QmY3NAw959vbE1oJooP9HchcRdBsbxhgQsEZTRhKgvoSuC/go-libp2p/p2p/crypto" - peer "gx/ipfs/QmY3NAw959vbE1oJooP9HchcRdBsbxhgQsEZTRhKgvoSuC/go-libp2p/p2p/peer" + ci "gx/ipfs/QmZxtCsPRgCnCXwVPUjcBiFckkG5NMYM4Pthwe6X4C8uQq/go-libp2p/p2p/crypto" + peer "gx/ipfs/QmZxtCsPRgCnCXwVPUjcBiFckkG5NMYM4Pthwe6X4C8uQq/go-libp2p/p2p/peer" ) func Init(out io.Writer, nBitsForKeypair int) (*Config, error) { From 389545c7508b308856223751b31e4653c729a355 Mon Sep 17 00:00:00 2001 From: Jeromy Date: Thu, 28 Jan 2016 10:07:26 -0800 Subject: [PATCH 058/414] go-ipfs-config: correct go-log dep License: MIT Signed-off-by: Jeromy --- config/config.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/config/config.go b/config/config.go index 8ea2dbd28a9..76280256164 100644 --- a/config/config.go +++ b/config/config.go @@ -10,7 +10,7 @@ import ( "strings" u "github.com/ipfs/go-ipfs/util" - logging "gx/ipfs/QmaPaGNE2GqnfJjRRpQuQuFHuJn4FZvsrGxdik4kgxCkBi/go-log" + logging "gx/ipfs/Qmazh5oNUVsDZTs2g59rq8aYQqwpss8tcUWQzor5sCCEuH/go-log" ) var log = logging.Logger("config") From 5bad15f8ee76a02b470d95640d851fb6eae4d408 Mon Sep 17 00:00:00 2001 From: Jeromy Date: Sun, 31 Jan 2016 10:19:50 -0800 Subject: [PATCH 059/414] go-ipfs-config: update libp2p dep License: MIT Signed-off-by: Jeromy --- config/identity.go | 2 +- config/init.go | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/config/identity.go b/config/identity.go index a1b944de7ac..6e75abadb1e 100644 --- a/config/identity.go +++ b/config/identity.go @@ -2,7 +2,7 @@ package config import ( "encoding/base64" - ic "gx/ipfs/QmZxtCsPRgCnCXwVPUjcBiFckkG5NMYM4Pthwe6X4C8uQq/go-libp2p/p2p/crypto" + ic "gx/ipfs/QmQQCBoWhMZtStYuAAo2uDNNLit9n7yX5ANBecfjKq4XBn/go-libp2p/p2p/crypto" ) // Identity tracks the configuration of the local node's identity. diff --git a/config/init.go b/config/init.go index e667067986f..7c9c593e5cb 100644 --- a/config/init.go +++ b/config/init.go @@ -6,8 +6,8 @@ import ( "fmt" "io" - ci "gx/ipfs/QmZxtCsPRgCnCXwVPUjcBiFckkG5NMYM4Pthwe6X4C8uQq/go-libp2p/p2p/crypto" - peer "gx/ipfs/QmZxtCsPRgCnCXwVPUjcBiFckkG5NMYM4Pthwe6X4C8uQq/go-libp2p/p2p/peer" + ci "gx/ipfs/QmQQCBoWhMZtStYuAAo2uDNNLit9n7yX5ANBecfjKq4XBn/go-libp2p/p2p/crypto" + peer "gx/ipfs/QmQQCBoWhMZtStYuAAo2uDNNLit9n7yX5ANBecfjKq4XBn/go-libp2p/p2p/peer" ) func Init(out io.Writer, nBitsForKeypair int) (*Config, error) { From 8a262c832aa41855c1424314d8e80bed6ced6626 Mon Sep 17 00:00:00 2001 From: Jeromy Date: Sun, 31 Jan 2016 15:37:39 -0800 Subject: [PATCH 060/414] go-ipfs-config: do that last thing again License: MIT Signed-off-by: Jeromy --- config/identity.go | 2 +- config/init.go | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/config/identity.go b/config/identity.go index 6e75abadb1e..e09bedcdf80 100644 --- a/config/identity.go +++ b/config/identity.go @@ -2,7 +2,7 @@ package config import ( "encoding/base64" - ic "gx/ipfs/QmQQCBoWhMZtStYuAAo2uDNNLit9n7yX5ANBecfjKq4XBn/go-libp2p/p2p/crypto" + ic "gx/ipfs/QmUBogf4nUefBjmYjn6jfsfPJRkmDGSeMhNj4usRKq69f4/go-libp2p/p2p/crypto" ) // Identity tracks the configuration of the local node's identity. diff --git a/config/init.go b/config/init.go index 7c9c593e5cb..9bb7b4e0556 100644 --- a/config/init.go +++ b/config/init.go @@ -6,8 +6,8 @@ import ( "fmt" "io" - ci "gx/ipfs/QmQQCBoWhMZtStYuAAo2uDNNLit9n7yX5ANBecfjKq4XBn/go-libp2p/p2p/crypto" - peer "gx/ipfs/QmQQCBoWhMZtStYuAAo2uDNNLit9n7yX5ANBecfjKq4XBn/go-libp2p/p2p/peer" + ci "gx/ipfs/QmUBogf4nUefBjmYjn6jfsfPJRkmDGSeMhNj4usRKq69f4/go-libp2p/p2p/crypto" + peer "gx/ipfs/QmUBogf4nUefBjmYjn6jfsfPJRkmDGSeMhNj4usRKq69f4/go-libp2p/p2p/peer" ) func Init(out io.Writer, nBitsForKeypair int) (*Config, error) { From a7c4694354fd5d71f715a5fb36731e0f53cb112f Mon Sep 17 00:00:00 2001 From: Jeromy Date: Tue, 9 Feb 2016 10:56:19 -0800 Subject: [PATCH 061/414] go-ipfs-config: Use gx vendored go-ipfs-utils where possible For the rest of the packages in util, move them to thirdparty and update the references. util is gone! License: MIT Signed-off-by: Jeromy --- config/bootstrap_peers.go | 2 +- config/config.go | 4 ++-- config/supernode.go | 2 +- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/config/bootstrap_peers.go b/config/bootstrap_peers.go index fa607c84252..c880913a170 100644 --- a/config/bootstrap_peers.go +++ b/config/bootstrap_peers.go @@ -4,7 +4,7 @@ import ( "errors" "fmt" - iaddr "github.com/ipfs/go-ipfs/util/ipfsaddr" + iaddr "github.com/ipfs/go-ipfs/thirdparty/ipfsaddr" ) // DefaultBootstrapAddresses are the hardcoded bootstrap addresses diff --git a/config/config.go b/config/config.go index 76280256164..bfe9be1de64 100644 --- a/config/config.go +++ b/config/config.go @@ -9,7 +9,7 @@ import ( "path/filepath" "strings" - u "github.com/ipfs/go-ipfs/util" + "github.com/ipfs/go-ipfs/Godeps/_workspace/src/github.com/mitchellh/go-homedir" logging "gx/ipfs/Qmazh5oNUVsDZTs2g59rq8aYQqwpss8tcUWQzor5sCCEuH/go-log" ) @@ -48,7 +48,7 @@ func PathRoot() (string, error) { dir := os.Getenv(EnvDir) var err error if len(dir) == 0 { - dir, err = u.TildeExpansion(DefaultPathRoot) + dir, err = homedir.Expand(DefaultPathRoot) } return dir, err } diff --git a/config/supernode.go b/config/supernode.go index 30ee6f22e55..de403fadd7d 100644 --- a/config/supernode.go +++ b/config/supernode.go @@ -1,6 +1,6 @@ package config -import "github.com/ipfs/go-ipfs/util/ipfsaddr" +import "github.com/ipfs/go-ipfs/thirdparty/ipfsaddr" // TODO replace with final servers before merge From 37118595eec54eb184c036f0b2976c622a509d42 Mon Sep 17 00:00:00 2001 From: Jeromy Date: Wed, 9 Mar 2016 09:53:19 -0800 Subject: [PATCH 062/414] go-ipfs-config: update libp2p dep License: MIT Signed-off-by: Jeromy --- config/identity.go | 2 +- config/init.go | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/config/identity.go b/config/identity.go index e09bedcdf80..f54586ad3d5 100644 --- a/config/identity.go +++ b/config/identity.go @@ -2,7 +2,7 @@ package config import ( "encoding/base64" - ic "gx/ipfs/QmUBogf4nUefBjmYjn6jfsfPJRkmDGSeMhNj4usRKq69f4/go-libp2p/p2p/crypto" + ic "gx/ipfs/QmNefBbWHR9JEiP3KDVqZsBLQVRmH3GBG2D2Ke24SsFqfW/go-libp2p/p2p/crypto" ) // Identity tracks the configuration of the local node's identity. diff --git a/config/init.go b/config/init.go index 9bb7b4e0556..50ebbfa3a0b 100644 --- a/config/init.go +++ b/config/init.go @@ -6,8 +6,8 @@ import ( "fmt" "io" - ci "gx/ipfs/QmUBogf4nUefBjmYjn6jfsfPJRkmDGSeMhNj4usRKq69f4/go-libp2p/p2p/crypto" - peer "gx/ipfs/QmUBogf4nUefBjmYjn6jfsfPJRkmDGSeMhNj4usRKq69f4/go-libp2p/p2p/peer" + ci "gx/ipfs/QmNefBbWHR9JEiP3KDVqZsBLQVRmH3GBG2D2Ke24SsFqfW/go-libp2p/p2p/crypto" + peer "gx/ipfs/QmNefBbWHR9JEiP3KDVqZsBLQVRmH3GBG2D2Ke24SsFqfW/go-libp2p/p2p/peer" ) func Init(out io.Writer, nBitsForKeypair int) (*Config, error) { From 7beb8be675148bfe9a2c0619fda44b8924050c8e Mon Sep 17 00:00:00 2001 From: Jeromy Date: Tue, 29 Mar 2016 19:18:14 -0700 Subject: [PATCH 063/414] go-ipfs-config: update utp and cleanup more godeps along the way License: MIT Signed-off-by: Jeromy --- config/identity.go | 2 +- config/init.go | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/config/identity.go b/config/identity.go index f54586ad3d5..f70b6fe03c8 100644 --- a/config/identity.go +++ b/config/identity.go @@ -2,7 +2,7 @@ package config import ( "encoding/base64" - ic "gx/ipfs/QmNefBbWHR9JEiP3KDVqZsBLQVRmH3GBG2D2Ke24SsFqfW/go-libp2p/p2p/crypto" + ic "gx/ipfs/QmSN2ELGRp4T9kjqiSsSNJRUeR9JKXzQEgwe1HH3tdSGbC/go-libp2p/p2p/crypto" ) // Identity tracks the configuration of the local node's identity. diff --git a/config/init.go b/config/init.go index 50ebbfa3a0b..1cbc9f4956a 100644 --- a/config/init.go +++ b/config/init.go @@ -6,8 +6,8 @@ import ( "fmt" "io" - ci "gx/ipfs/QmNefBbWHR9JEiP3KDVqZsBLQVRmH3GBG2D2Ke24SsFqfW/go-libp2p/p2p/crypto" - peer "gx/ipfs/QmNefBbWHR9JEiP3KDVqZsBLQVRmH3GBG2D2Ke24SsFqfW/go-libp2p/p2p/peer" + ci "gx/ipfs/QmSN2ELGRp4T9kjqiSsSNJRUeR9JKXzQEgwe1HH3tdSGbC/go-libp2p/p2p/crypto" + peer "gx/ipfs/QmSN2ELGRp4T9kjqiSsSNJRUeR9JKXzQEgwe1HH3tdSGbC/go-libp2p/p2p/peer" ) func Init(out io.Writer, nBitsForKeypair int) (*Config, error) { From 0747b9cecdc6b498fa7ef7f70c6e58e3e0546d2c Mon Sep 17 00:00:00 2001 From: Lars Gierth Date: Mon, 28 Mar 2016 19:21:48 -0400 Subject: [PATCH 064/414] go-ipfs-config: gateway: enforce allowlist for path prefixes The gateway accepts an X-Ipfs-Path-Prefix header, and assumes that it is mounted in a reverse proxy like nginx, at this path. Links in directory listings, as well as trailing-slash redirects need to be rewritten with that prefix in mind. We don't want a potential attacker to be able to pass in arbitrary path prefixes, which would end up in redirects and directory listings, which is why every prefix has to be explicitly allowed in the config. Previously, we'd accept *any* X-Ipfs-Path-Prefix header. Example: We mount blog.ipfs.io (a dnslink page) at ipfs.io/blog. nginx_ipfs.conf: location /blog/ { rewrite "^/blog(/.*)$" $1 break; proxy_set_header Host blog.ipfs.io; proxy_set_header X-Ipfs-Gateway-Prefix /blog; proxy_pass http://127.0.0.1:8080; } .ipfs/config: "Gateway": { "PathPrefixes": ["/blog"], // ... }, dnslink: > dig TXT _dnslink.blog.ipfs.io dnslink=/ipfs/QmWcBjXPAEdhXDATV4ghUpkAonNBbiyFx1VmmHcQe9HEGd License: MIT Signed-off-by: Lars Gierth --- config/gateway.go | 1 + config/init.go | 1 + 2 files changed, 2 insertions(+) diff --git a/config/gateway.go b/config/gateway.go index 07bc9aad2cb..a8ba7059071 100644 --- a/config/gateway.go +++ b/config/gateway.go @@ -5,4 +5,5 @@ type Gateway struct { HTTPHeaders map[string][]string // HTTP headers to return with the gateway RootRedirect string Writable bool + PathPrefixes []string } diff --git a/config/init.go b/config/init.go index 1cbc9f4956a..3dbc1b3f522 100644 --- a/config/init.go +++ b/config/init.go @@ -65,6 +65,7 @@ func Init(out io.Writer, nBitsForKeypair int) (*Config, error) { Gateway: Gateway{ RootRedirect: "", Writable: false, + PathPrefixes: []string{}, }, } From 1868295693e225f4b2884d80a83e568a0aeab2ea Mon Sep 17 00:00:00 2001 From: Jeromy Date: Wed, 6 Apr 2016 15:42:06 -0700 Subject: [PATCH 065/414] go-ipfs-config: switch to new libp2p with mss crypto License: MIT Signed-off-by: Jeromy --- config/identity.go | 2 +- config/init.go | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/config/identity.go b/config/identity.go index f70b6fe03c8..3a2f39d40c4 100644 --- a/config/identity.go +++ b/config/identity.go @@ -2,7 +2,7 @@ package config import ( "encoding/base64" - ic "gx/ipfs/QmSN2ELGRp4T9kjqiSsSNJRUeR9JKXzQEgwe1HH3tdSGbC/go-libp2p/p2p/crypto" + ic "gx/ipfs/QmZMehXD2w81qeVJP6r1mmocxwsD7kqAvuzGm2QWDw1H88/go-libp2p/p2p/crypto" ) // Identity tracks the configuration of the local node's identity. diff --git a/config/init.go b/config/init.go index 3dbc1b3f522..810cc99982c 100644 --- a/config/init.go +++ b/config/init.go @@ -6,8 +6,8 @@ import ( "fmt" "io" - ci "gx/ipfs/QmSN2ELGRp4T9kjqiSsSNJRUeR9JKXzQEgwe1HH3tdSGbC/go-libp2p/p2p/crypto" - peer "gx/ipfs/QmSN2ELGRp4T9kjqiSsSNJRUeR9JKXzQEgwe1HH3tdSGbC/go-libp2p/p2p/peer" + ci "gx/ipfs/QmZMehXD2w81qeVJP6r1mmocxwsD7kqAvuzGm2QWDw1H88/go-libp2p/p2p/crypto" + peer "gx/ipfs/QmZMehXD2w81qeVJP6r1mmocxwsD7kqAvuzGm2QWDw1H88/go-libp2p/p2p/peer" ) func Init(out io.Writer, nBitsForKeypair int) (*Config, error) { From 46e32373f0647b956c3122fc7c1467b2249ac066 Mon Sep 17 00:00:00 2001 From: Jeromy Date: Fri, 8 Apr 2016 13:11:30 -0700 Subject: [PATCH 066/414] go-ipfs-config: clean up dead code and config fields License: MIT Signed-off-by: Jeromy --- config/config.go | 1 - config/init.go | 14 ++------------ 2 files changed, 2 insertions(+), 13 deletions(-) diff --git a/config/config.go b/config/config.go index bfe9be1de64..8c8d2ec1ebf 100644 --- a/config/config.go +++ b/config/config.go @@ -21,7 +21,6 @@ type Config struct { Datastore Datastore // local node's storage Addresses Addresses // local node's addresses Mounts Mounts // local node's mount points - Version Version // local node's version management Discovery Discovery // local node's discovery mechanisms Ipns Ipns // Ipns settings Bootstrap []string // local nodes's bootstrap peer addresses diff --git a/config/init.go b/config/init.go index 810cc99982c..886aaac7567 100644 --- a/config/init.go +++ b/config/init.go @@ -21,11 +21,6 @@ func Init(out io.Writer, nBitsForKeypair int) (*Config, error) { return nil, err } - snr, err := initSNRConfig() - if err != nil { - return nil, err - } - conf := &Config{ // setup the node's default addresses. @@ -40,9 +35,8 @@ func Init(out io.Writer, nBitsForKeypair int) (*Config, error) { Gateway: "/ip4/127.0.0.1/tcp/8080", }, - Bootstrap: BootstrapPeerStrings(bootstrapPeers), - SupernodeRouting: *snr, - Identity: identity, + Bootstrap: BootstrapPeerStrings(bootstrapPeers), + Identity: identity, Discovery: Discovery{MDNS{ Enabled: true, Interval: 10, @@ -58,10 +52,6 @@ func Init(out io.Writer, nBitsForKeypair int) (*Config, error) { ResolveCacheSize: 128, }, - // tracking ipfs version used to generate the init folder and adding - // update checker default setting. - Version: VersionDefaultValue(), - Gateway: Gateway{ RootRedirect: "", Writable: false, From 0d2853dbaa4d87ffed3d5611524ff7c400a2f396 Mon Sep 17 00:00:00 2001 From: Jeromy Date: Fri, 8 Apr 2016 13:54:12 -0700 Subject: [PATCH 067/414] go-ipfs-config: remove test for removed dead config version fields License: MIT Signed-off-by: Jeromy --- config/version_test.go | 35 ----------------------------------- 1 file changed, 35 deletions(-) delete mode 100644 config/version_test.go diff --git a/config/version_test.go b/config/version_test.go deleted file mode 100644 index c4b8aeb5ac2..00000000000 --- a/config/version_test.go +++ /dev/null @@ -1,35 +0,0 @@ -package config - -import ( - "encoding/json" - "strings" - "testing" -) - -func TestAutoUpdateValues(t *testing.T) { - var tval struct { - AutoUpdate AutoUpdateSetting - } - tests := []struct { - input string - val AutoUpdateSetting - err error - }{ - {`{"hello":123}`, AutoUpdateNever, nil}, // zero value - {`{"AutoUpdate": "never"}`, AutoUpdateNever, nil}, - {`{"AutoUpdate": "patch"}`, AutoUpdatePatch, nil}, - {`{"AutoUpdate": "minor"}`, AutoUpdateMinor, nil}, - {`{"AutoUpdate": "major"}`, AutoUpdateMajor, nil}, - {`{"AutoUpdate": "blarg"}`, AutoUpdateMinor, ErrUnknownAutoUpdateSetting}, - } - - for i, tc := range tests { - if err := json.NewDecoder(strings.NewReader(tc.input)).Decode(&tval); err != tc.err { - t.Fatalf("%d failed - got err %q wanted %v", i, err, tc.err) - } - - if tval.AutoUpdate != tc.val { - t.Fatalf("%d failed - got val %q where we wanted %q", i, tval.AutoUpdate, tc.val) - } - } -} From 713fe1cdbd157f744cc4695cf29461bd313fac55 Mon Sep 17 00:00:00 2001 From: Jeromy Date: Mon, 11 Apr 2016 12:52:54 -0700 Subject: [PATCH 068/414] go-ipfs-config: update libp2p dep to fix hanging listeners problem License: MIT Signed-off-by: Jeromy --- config/identity.go | 2 +- config/init.go | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/config/identity.go b/config/identity.go index 3a2f39d40c4..b09bb0317c9 100644 --- a/config/identity.go +++ b/config/identity.go @@ -2,7 +2,7 @@ package config import ( "encoding/base64" - ic "gx/ipfs/QmZMehXD2w81qeVJP6r1mmocxwsD7kqAvuzGm2QWDw1H88/go-libp2p/p2p/crypto" + ic "gx/ipfs/QmccGfZs3rzku8Bv6sTPH3bMUKD1EVod8srgRjt5csdmva/go-libp2p/p2p/crypto" ) // Identity tracks the configuration of the local node's identity. diff --git a/config/init.go b/config/init.go index 886aaac7567..6d1f185fd46 100644 --- a/config/init.go +++ b/config/init.go @@ -6,8 +6,8 @@ import ( "fmt" "io" - ci "gx/ipfs/QmZMehXD2w81qeVJP6r1mmocxwsD7kqAvuzGm2QWDw1H88/go-libp2p/p2p/crypto" - peer "gx/ipfs/QmZMehXD2w81qeVJP6r1mmocxwsD7kqAvuzGm2QWDw1H88/go-libp2p/p2p/peer" + ci "gx/ipfs/QmccGfZs3rzku8Bv6sTPH3bMUKD1EVod8srgRjt5csdmva/go-libp2p/p2p/crypto" + peer "gx/ipfs/QmccGfZs3rzku8Bv6sTPH3bMUKD1EVod8srgRjt5csdmva/go-libp2p/p2p/peer" ) func Init(out io.Writer, nBitsForKeypair int) (*Config, error) { From 21887fac8bb04ae0f0ad34daf0cac2ad3c37e40a Mon Sep 17 00:00:00 2001 From: Lars Gierth Date: Thu, 7 Apr 2016 17:01:23 -0400 Subject: [PATCH 069/414] go-ipfs-config: repo: properly init Datastore config, and leave it be We didn't previously initialize the Datastore config section. The respective function exists, but was dead code up until now. This lead to weird decisions like the GC code deciding on defaults, and writing these to the config file. Don't want GC to touch the config. License: MIT Signed-off-by: Lars Gierth --- config/init.go | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) diff --git a/config/init.go b/config/init.go index 6d1f185fd46..01a360bd94c 100644 --- a/config/init.go +++ b/config/init.go @@ -21,6 +21,11 @@ func Init(out io.Writer, nBitsForKeypair int) (*Config, error) { return nil, err } + datastore, err := datastoreConfig() + if err != nil { + return nil, err + } + conf := &Config{ // setup the node's default addresses. @@ -35,6 +40,7 @@ func Init(out io.Writer, nBitsForKeypair int) (*Config, error) { Gateway: "/ip4/127.0.0.1/tcp/8080", }, + Datastore: datastore, Bootstrap: BootstrapPeerStrings(bootstrapPeers), Identity: identity, Discovery: Discovery{MDNS{ @@ -62,12 +68,12 @@ func Init(out io.Writer, nBitsForKeypair int) (*Config, error) { return conf, nil } -func datastoreConfig() (*Datastore, error) { +func datastoreConfig() (Datastore, error) { dspath, err := DataStorePath("") if err != nil { - return nil, err + return Datastore{}, err } - return &Datastore{ + return Datastore{ Path: dspath, Type: "leveldb", StorageMax: "10GB", From 1244da163c9e47bdaa17afe170616d4f6e695460 Mon Sep 17 00:00:00 2001 From: Lars Gierth Date: Sat, 16 Apr 2016 21:23:47 -0700 Subject: [PATCH 070/414] go-ipfs-config: Update go-libp2p License: MIT Signed-off-by: Lars Gierth --- config/identity.go | 2 +- config/init.go | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/config/identity.go b/config/identity.go index b09bb0317c9..74d5c681bf4 100644 --- a/config/identity.go +++ b/config/identity.go @@ -2,7 +2,7 @@ package config import ( "encoding/base64" - ic "gx/ipfs/QmccGfZs3rzku8Bv6sTPH3bMUKD1EVod8srgRjt5csdmva/go-libp2p/p2p/crypto" + ic "gx/ipfs/QmYgaiNVVL7f2nydijAwpDRunRkmxfu3PoK87Y3pH84uAW/go-libp2p/p2p/crypto" ) // Identity tracks the configuration of the local node's identity. diff --git a/config/init.go b/config/init.go index 01a360bd94c..f3887178242 100644 --- a/config/init.go +++ b/config/init.go @@ -6,8 +6,8 @@ import ( "fmt" "io" - ci "gx/ipfs/QmccGfZs3rzku8Bv6sTPH3bMUKD1EVod8srgRjt5csdmva/go-libp2p/p2p/crypto" - peer "gx/ipfs/QmccGfZs3rzku8Bv6sTPH3bMUKD1EVod8srgRjt5csdmva/go-libp2p/p2p/peer" + ci "gx/ipfs/QmYgaiNVVL7f2nydijAwpDRunRkmxfu3PoK87Y3pH84uAW/go-libp2p/p2p/crypto" + peer "gx/ipfs/QmYgaiNVVL7f2nydijAwpDRunRkmxfu3PoK87Y3pH84uAW/go-libp2p/p2p/peer" ) func Init(out io.Writer, nBitsForKeypair int) (*Config, error) { From 7c3d8a108f4a9bba312f762eb3897d7b17795963 Mon Sep 17 00:00:00 2001 From: Lars Gierth Date: Sat, 16 Apr 2016 21:38:22 -0700 Subject: [PATCH 071/414] go-ipfs-config: Use extracted go-libp2p-crypto, -secio, -peer packages License: MIT Signed-off-by: Lars Gierth --- config/identity.go | 2 +- config/init.go | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/config/identity.go b/config/identity.go index 74d5c681bf4..05a44dc4860 100644 --- a/config/identity.go +++ b/config/identity.go @@ -2,7 +2,7 @@ package config import ( "encoding/base64" - ic "gx/ipfs/QmYgaiNVVL7f2nydijAwpDRunRkmxfu3PoK87Y3pH84uAW/go-libp2p/p2p/crypto" + ic "gx/ipfs/QmUEUu1CM8bxBJxc3ZLojAi8evhTr4byQogWstABet79oY/go-libp2p-crypto" ) // Identity tracks the configuration of the local node's identity. diff --git a/config/init.go b/config/init.go index f3887178242..22bf8e26c44 100644 --- a/config/init.go +++ b/config/init.go @@ -6,8 +6,8 @@ import ( "fmt" "io" - ci "gx/ipfs/QmYgaiNVVL7f2nydijAwpDRunRkmxfu3PoK87Y3pH84uAW/go-libp2p/p2p/crypto" - peer "gx/ipfs/QmYgaiNVVL7f2nydijAwpDRunRkmxfu3PoK87Y3pH84uAW/go-libp2p/p2p/peer" + ci "gx/ipfs/QmUEUu1CM8bxBJxc3ZLojAi8evhTr4byQogWstABet79oY/go-libp2p-crypto" + peer "gx/ipfs/QmZwZjMVGss5rqYsJVGy18gNbkTJffFyq2x1uJ4e4p3ZAt/go-libp2p-peer" ) func Init(out io.Writer, nBitsForKeypair int) (*Config, error) { From ef1a5c04a852cf3b0e5fa031ac3514059985e1da Mon Sep 17 00:00:00 2001 From: Richard Littauer Date: Fri, 29 Apr 2016 16:57:19 -0400 Subject: [PATCH 072/414] go-ipfs-config: Capitalized `NOTE`, first letter of following word License: MIT Signed-off-by: Richard Littauer --- config/bootstrap_peers.go | 2 +- config/init.go | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/config/bootstrap_peers.go b/config/bootstrap_peers.go index c880913a170..db6bad2e662 100644 --- a/config/bootstrap_peers.go +++ b/config/bootstrap_peers.go @@ -11,7 +11,7 @@ import ( // for ipfs. they are nodes run by the ipfs team. docs on these later. // As with all p2p networks, bootstrap is an important security concern. // -// Note: this is here -- and not inside cmd/ipfs/init.go -- because of an +// NOTE: This is here -- and not inside cmd/ipfs/init.go -- because of an // import dependency issue. TODO: move this into a config/default/ package. var DefaultBootstrapAddresses = []string{ "/ip4/104.131.131.82/tcp/4001/ipfs/QmaCpDMGvV2BGHeYERUEnRQAwe3N8SzbUtfsmvsqQLuvuJ", // mars.i.ipfs.io diff --git a/config/init.go b/config/init.go index 22bf8e26c44..79751994771 100644 --- a/config/init.go +++ b/config/init.go @@ -29,7 +29,7 @@ func Init(out io.Writer, nBitsForKeypair int) (*Config, error) { conf := &Config{ // setup the node's default addresses. - // Note: two swarm listen addrs, one tcp, one utp. + // NOTE: two swarm listen addrs, one tcp, one utp. Addresses: Addresses{ Swarm: []string{ "/ip4/0.0.0.0/tcp/4001", From 641003089befac001dd3deb4b134fae6c68883e2 Mon Sep 17 00:00:00 2001 From: Hector Sanjuan Date: Wed, 4 May 2016 22:56:39 +0200 Subject: [PATCH 073/414] go-ipfs-config: Update go-log to 1.1.0 and fix calls to go-log.Uuid License: MIT Signed-off-by: Hector Sanjuan --- config/config.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/config/config.go b/config/config.go index 8c8d2ec1ebf..d910ccf65cd 100644 --- a/config/config.go +++ b/config/config.go @@ -10,7 +10,7 @@ import ( "strings" "github.com/ipfs/go-ipfs/Godeps/_workspace/src/github.com/mitchellh/go-homedir" - logging "gx/ipfs/Qmazh5oNUVsDZTs2g59rq8aYQqwpss8tcUWQzor5sCCEuH/go-log" + logging "gx/ipfs/QmaDNZ4QMdBdku1YZWBysufYyoQt1negQGNav6PLYarbY8/go-log" ) var log = logging.Logger("config") From b5c55cf2a1019707bd2e528e9c061030ecefd0fc Mon Sep 17 00:00:00 2001 From: Jeromy Date: Tue, 10 May 2016 16:06:28 -0700 Subject: [PATCH 074/414] go-ipfs-config: update libp2p with go-multiaddr and go-stream-muxer updates License: MIT Signed-off-by: Jeromy --- config/init.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/config/init.go b/config/init.go index 79751994771..67179d2e091 100644 --- a/config/init.go +++ b/config/init.go @@ -7,7 +7,7 @@ import ( "io" ci "gx/ipfs/QmUEUu1CM8bxBJxc3ZLojAi8evhTr4byQogWstABet79oY/go-libp2p-crypto" - peer "gx/ipfs/QmZwZjMVGss5rqYsJVGy18gNbkTJffFyq2x1uJ4e4p3ZAt/go-libp2p-peer" + peer "gx/ipfs/QmZpD74pUj6vuxTp1o6LhA3JavC2Bvh9fsWPPVvHnD9sE7/go-libp2p-peer" ) func Init(out io.Writer, nBitsForKeypair int) (*Config, error) { From e36dc46a632e9ecd8821499ae6a6cdc423e41d6c Mon Sep 17 00:00:00 2001 From: Jeromy Date: Tue, 17 May 2016 10:23:10 -0700 Subject: [PATCH 075/414] go-ipfs-config: update go-libp2p 3.2.2, nil maddr fixes License: MIT Signed-off-by: Jeromy --- config/init.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/config/init.go b/config/init.go index 67179d2e091..f8f4a4890ea 100644 --- a/config/init.go +++ b/config/init.go @@ -7,7 +7,7 @@ import ( "io" ci "gx/ipfs/QmUEUu1CM8bxBJxc3ZLojAi8evhTr4byQogWstABet79oY/go-libp2p-crypto" - peer "gx/ipfs/QmZpD74pUj6vuxTp1o6LhA3JavC2Bvh9fsWPPVvHnD9sE7/go-libp2p-peer" + peer "gx/ipfs/QmbyvM8zRFDkbFdYyt1MnevUMJ62SiSGbfDFZ3Z8nkrzr4/go-libp2p-peer" ) func Init(out io.Writer, nBitsForKeypair int) (*Config, error) { From 705652ea637081daf7118227fc80e78d8ba0aac7 Mon Sep 17 00:00:00 2001 From: Jakub Sztandera Date: Tue, 17 May 2016 20:42:35 +0200 Subject: [PATCH 076/414] go-ipfs-config: Add CORS headers to Read Only Gateway Default config License: MIT Signed-off-by: Jakub Sztandera --- config/init.go | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/config/init.go b/config/init.go index f8f4a4890ea..35ccda36b55 100644 --- a/config/init.go +++ b/config/init.go @@ -62,6 +62,11 @@ func Init(out io.Writer, nBitsForKeypair int) (*Config, error) { RootRedirect: "", Writable: false, PathPrefixes: []string{}, + HTTPHeaders: map[string][]string{ + "Access-Control-Allow-Origin": []string{"*"}, + "Access-Control-Allow-Methods": []string{"GET"}, + "Access-Control-Allow-Headers": []string{"X-Requested-With"}, + }, }, } From f48cecdd37cf35cb6e5698b7190d774e38f8b80b Mon Sep 17 00:00:00 2001 From: Jeromy Date: Wed, 1 Jun 2016 15:51:39 -0700 Subject: [PATCH 077/414] go-ipfs-config: update libp2p to v3.3.1 License: MIT Signed-off-by: Jeromy --- config/init.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/config/init.go b/config/init.go index f8f4a4890ea..de467fe084c 100644 --- a/config/init.go +++ b/config/init.go @@ -6,8 +6,8 @@ import ( "fmt" "io" + peer "gx/ipfs/QmQGwpJy9P4yXZySmqkZEXCmbBpJUb8xntCv8Ca4taZwDC/go-libp2p-peer" ci "gx/ipfs/QmUEUu1CM8bxBJxc3ZLojAi8evhTr4byQogWstABet79oY/go-libp2p-crypto" - peer "gx/ipfs/QmbyvM8zRFDkbFdYyt1MnevUMJ62SiSGbfDFZ3Z8nkrzr4/go-libp2p-peer" ) func Init(out io.Writer, nBitsForKeypair int) (*Config, error) { From c82b5816501c10dece6159656c7dfb454b94bedf Mon Sep 17 00:00:00 2001 From: Jakub Sztandera Date: Thu, 9 Jun 2016 22:12:52 +0200 Subject: [PATCH 078/414] go-ipfs-config: Update go-log https://github.com/ipfs/go-log/pull/3 License: MIT Signed-off-by: Jakub Sztandera --- config/config.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/config/config.go b/config/config.go index d910ccf65cd..b2f1fae4e62 100644 --- a/config/config.go +++ b/config/config.go @@ -10,7 +10,7 @@ import ( "strings" "github.com/ipfs/go-ipfs/Godeps/_workspace/src/github.com/mitchellh/go-homedir" - logging "gx/ipfs/QmaDNZ4QMdBdku1YZWBysufYyoQt1negQGNav6PLYarbY8/go-log" + logging "gx/ipfs/QmYtB7Qge8cJpXc4irsEp8zRqfnZMBeB7aTrMEkPk67DRv/go-log" ) var log = logging.Logger("config") From c36294a933e693ec2297ee6558670033a01e9139 Mon Sep 17 00:00:00 2001 From: Jakub Sztandera Date: Fri, 24 Jun 2016 18:38:07 +0200 Subject: [PATCH 079/414] go-ipfs-config: Update go-log in whole dependency tree (#2898) * Update golog in go-ipfs License: MIT Signed-off-by: Jakub Sztandera * Update go-libp2p for go-log License: MIT Signed-off-by: Jakub Sztandera * Update go-libp2p-secio for go-log License: MIT Signed-off-by: Jakub Sztandera * Update go-libp2p-crypto for go-log License: MIT Signed-off-by: Jakub Sztandera * Update go-libp2p-peer for go-log License: MIT Signed-off-by: Jakub Sztandera * Import peersore, it wasn't imported License: MIT Signed-off-by: Jakub Sztandera * Update peerstore License: MIT Signed-off-by: Jakub Sztandera * Update peer License: MIT Signed-off-by: Jakub Sztandera * Update secio License: MIT Signed-off-by: Jakub Sztandera * Update go-libp2p License: MIT Signed-off-by: Jakub Sztandera --- config/config.go | 2 +- config/identity.go | 2 +- config/init.go | 4 ++-- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/config/config.go b/config/config.go index b2f1fae4e62..4488bba083d 100644 --- a/config/config.go +++ b/config/config.go @@ -10,7 +10,7 @@ import ( "strings" "github.com/ipfs/go-ipfs/Godeps/_workspace/src/github.com/mitchellh/go-homedir" - logging "gx/ipfs/QmYtB7Qge8cJpXc4irsEp8zRqfnZMBeB7aTrMEkPk67DRv/go-log" + logging "gx/ipfs/QmNQynaz7qfriSUJkiEZUrm2Wen1u3Kj9goZzWtrPyu7XR/go-log" ) var log = logging.Logger("config") diff --git a/config/identity.go b/config/identity.go index 05a44dc4860..fe88a34b0d7 100644 --- a/config/identity.go +++ b/config/identity.go @@ -2,7 +2,7 @@ package config import ( "encoding/base64" - ic "gx/ipfs/QmUEUu1CM8bxBJxc3ZLojAi8evhTr4byQogWstABet79oY/go-libp2p-crypto" + ic "gx/ipfs/QmUWER4r4qMvaCnX5zREcfyiWN7cXN9g3a7fkRqNz8qWPP/go-libp2p-crypto" ) // Identity tracks the configuration of the local node's identity. diff --git a/config/init.go b/config/init.go index 8e248c12902..ae5c813b7a3 100644 --- a/config/init.go +++ b/config/init.go @@ -6,8 +6,8 @@ import ( "fmt" "io" - peer "gx/ipfs/QmQGwpJy9P4yXZySmqkZEXCmbBpJUb8xntCv8Ca4taZwDC/go-libp2p-peer" - ci "gx/ipfs/QmUEUu1CM8bxBJxc3ZLojAi8evhTr4byQogWstABet79oY/go-libp2p-crypto" + peer "gx/ipfs/QmRBqJF7hb8ZSpRcMwUt8hNhydWcxGEhtk81HKq6oUwKvs/go-libp2p-peer" + ci "gx/ipfs/QmUWER4r4qMvaCnX5zREcfyiWN7cXN9g3a7fkRqNz8qWPP/go-libp2p-crypto" ) func Init(out io.Writer, nBitsForKeypair int) (*Config, error) { From 6135edf075f54b019b6cf04b79d84d6200a81e4a Mon Sep 17 00:00:00 2001 From: Jakub Sztandera Date: Fri, 24 Jun 2016 22:10:31 +0200 Subject: [PATCH 080/414] go-ipfs-config: core: Add config option for datastore read rehashing License: MIT Signed-off-by: Jakub Sztandera --- config/datastore.go | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/config/datastore.go b/config/datastore.go index 52582bd5cb5..2b9bf600df2 100644 --- a/config/datastore.go +++ b/config/datastore.go @@ -15,8 +15,9 @@ type Datastore struct { StorageGCWatermark int64 // in percentage to multiply on StorageMax GCPeriod string // in ns, us, ms, s, m, h - Params *json.RawMessage - NoSync bool + Params *json.RawMessage + NoSync bool + HashOnRead bool } func (d *Datastore) ParamData() []byte { From 35108597dd505719e2f85c150bb942fa4f88ecee Mon Sep 17 00:00:00 2001 From: Jakub Sztandera Date: Fri, 24 Jun 2016 22:22:38 +0200 Subject: [PATCH 081/414] go-ipfs-config: config: Add explicit default value for HashOnRead License: MIT Signed-off-by: Jakub Sztandera --- config/init.go | 1 + 1 file changed, 1 insertion(+) diff --git a/config/init.go b/config/init.go index ae5c813b7a3..8a6c72222ce 100644 --- a/config/init.go +++ b/config/init.go @@ -84,6 +84,7 @@ func datastoreConfig() (Datastore, error) { StorageMax: "10GB", StorageGCWatermark: 90, // 90% GCPeriod: "1h", + HashOnRead: false, }, nil } From e8912c13ea2a5ee95b422cf1b18b00ec38d3e7ea Mon Sep 17 00:00:00 2001 From: Jakub Sztandera Date: Fri, 8 Jul 2016 23:21:08 +0200 Subject: [PATCH 082/414] go-ipfs-config: core/commands: do not show PrivKey in config if it is null License: MIT Signed-off-by: Jakub Sztandera --- config/identity.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/config/identity.go b/config/identity.go index fe88a34b0d7..d997bc2b632 100644 --- a/config/identity.go +++ b/config/identity.go @@ -8,7 +8,7 @@ import ( // Identity tracks the configuration of the local node's identity. type Identity struct { PeerID string - PrivKey string + PrivKey string `json:",omitempty"` } // DecodePrivateKey is a helper to decode the users PrivateKey From 30b5a1f28c2aae0169ca052d203583a81e15a548 Mon Sep 17 00:00:00 2001 From: Jakub Sztandera Date: Fri, 15 Jul 2016 21:38:46 +0100 Subject: [PATCH 083/414] go-ipfs-config: config: add config option for bloom filter License: MIT Signed-off-by: Jakub Sztandera --- config/datastore.go | 7 ++++--- config/init.go | 1 + 2 files changed, 5 insertions(+), 3 deletions(-) diff --git a/config/datastore.go b/config/datastore.go index 2b9bf600df2..2b861a113cf 100644 --- a/config/datastore.go +++ b/config/datastore.go @@ -15,9 +15,10 @@ type Datastore struct { StorageGCWatermark int64 // in percentage to multiply on StorageMax GCPeriod string // in ns, us, ms, s, m, h - Params *json.RawMessage - NoSync bool - HashOnRead bool + Params *json.RawMessage + NoSync bool + HashOnRead bool + BloomFilterSize int } func (d *Datastore) ParamData() []byte { diff --git a/config/init.go b/config/init.go index 8a6c72222ce..5123e39e9e4 100644 --- a/config/init.go +++ b/config/init.go @@ -85,6 +85,7 @@ func datastoreConfig() (Datastore, error) { StorageGCWatermark: 90, // 90% GCPeriod: "1h", HashOnRead: false, + BloomFilterSize: 0, }, nil } From f5e4f1861c83b2e24a421b877b7f7c84d5b22a99 Mon Sep 17 00:00:00 2001 From: Jeromy Date: Fri, 19 Aug 2016 16:47:29 -0700 Subject: [PATCH 084/414] go-ipfs-config: reprovider: add config option to set reprovide interval License: MIT Signed-off-by: Jeromy --- config/config.go | 2 ++ config/init.go | 3 +++ config/reprovider.go | 5 +++++ 3 files changed, 10 insertions(+) create mode 100644 config/reprovider.go diff --git a/config/config.go b/config/config.go index 4488bba083d..4a3995a9993 100644 --- a/config/config.go +++ b/config/config.go @@ -29,6 +29,8 @@ type Config struct { SupernodeRouting SupernodeClientConfig // local node's routing servers (if SupernodeRouting enabled) API API // local node's API settings Swarm SwarmConfig + + Reprovider Reprovider } const ( diff --git a/config/init.go b/config/init.go index 5123e39e9e4..ac0c8f23bb3 100644 --- a/config/init.go +++ b/config/init.go @@ -68,6 +68,9 @@ func Init(out io.Writer, nBitsForKeypair int) (*Config, error) { "Access-Control-Allow-Headers": []string{"X-Requested-With"}, }, }, + Reprovider: Reprovider{ + Interval: "12h", + }, } return conf, nil diff --git a/config/reprovider.go b/config/reprovider.go new file mode 100644 index 00000000000..53cf293ab61 --- /dev/null +++ b/config/reprovider.go @@ -0,0 +1,5 @@ +package config + +type Reprovider struct { + Interval string // Time period to reprovide locally stored objects to the network +} From 16dd9472bdbcdec945e05bf8ba9a66ba5715b6b1 Mon Sep 17 00:00:00 2001 From: Jeromy Date: Mon, 22 Aug 2016 22:29:25 -0700 Subject: [PATCH 085/414] go-ipfs-config: update deps for libp2p 3.4.0 License: MIT Signed-off-by: Jeromy --- config/config.go | 2 +- config/identity.go | 2 +- config/init.go | 4 ++-- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/config/config.go b/config/config.go index 4a3995a9993..d367ac30421 100644 --- a/config/config.go +++ b/config/config.go @@ -10,7 +10,7 @@ import ( "strings" "github.com/ipfs/go-ipfs/Godeps/_workspace/src/github.com/mitchellh/go-homedir" - logging "gx/ipfs/QmNQynaz7qfriSUJkiEZUrm2Wen1u3Kj9goZzWtrPyu7XR/go-log" + logging "gx/ipfs/QmSpJByNKFX1sCsHBEp3R73FL4NF6FnQTEGyNAXHm2GS52/go-log" ) var log = logging.Logger("config") diff --git a/config/identity.go b/config/identity.go index d997bc2b632..edac9298338 100644 --- a/config/identity.go +++ b/config/identity.go @@ -2,7 +2,7 @@ package config import ( "encoding/base64" - ic "gx/ipfs/QmUWER4r4qMvaCnX5zREcfyiWN7cXN9g3a7fkRqNz8qWPP/go-libp2p-crypto" + ic "gx/ipfs/QmVoi5es8D5fNHZDqoW6DgDAEPEV5hQp8GBz161vZXiwpQ/go-libp2p-crypto" ) // Identity tracks the configuration of the local node's identity. diff --git a/config/init.go b/config/init.go index ac0c8f23bb3..d640b1b9c31 100644 --- a/config/init.go +++ b/config/init.go @@ -6,8 +6,8 @@ import ( "fmt" "io" - peer "gx/ipfs/QmRBqJF7hb8ZSpRcMwUt8hNhydWcxGEhtk81HKq6oUwKvs/go-libp2p-peer" - ci "gx/ipfs/QmUWER4r4qMvaCnX5zREcfyiWN7cXN9g3a7fkRqNz8qWPP/go-libp2p-crypto" + ci "gx/ipfs/QmVoi5es8D5fNHZDqoW6DgDAEPEV5hQp8GBz161vZXiwpQ/go-libp2p-crypto" + peer "gx/ipfs/QmWtbQU15LaB5B1JC2F7TV9P4K88vD3PpA4AJrwfCjhML8/go-libp2p-peer" ) func Init(out io.Writer, nBitsForKeypair int) (*Config, error) { From b4fd445e0e35ed6d2285c7d887f92d85ef69fb2c Mon Sep 17 00:00:00 2001 From: Jeromy Date: Mon, 29 Aug 2016 14:56:55 -0700 Subject: [PATCH 086/414] go-ipfs-config: config: guard against privkey being overwritten in fsrepo setConfig License: MIT Signed-off-by: Jeromy --- config/identity.go | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/config/identity.go b/config/identity.go index d997bc2b632..55fc11e70e0 100644 --- a/config/identity.go +++ b/config/identity.go @@ -5,6 +5,10 @@ import ( ic "gx/ipfs/QmUWER4r4qMvaCnX5zREcfyiWN7cXN9g3a7fkRqNz8qWPP/go-libp2p-crypto" ) +const IdentityTag = "Identity" +const PrivKeyTag = "PrivKey" +const PrivKeySelector = IdentityTag + "." + PrivKeyTag + // Identity tracks the configuration of the local node's identity. type Identity struct { PeerID string From d22951764f27daea79c61ebd80226155456f61e1 Mon Sep 17 00:00:00 2001 From: George Antoniadis Date: Sat, 10 Sep 2016 23:22:17 +0100 Subject: [PATCH 087/414] go-ipfs-config: Extract peerset, update peer, peerset, secio, libp2p License: MIT Signed-off-by: George Antoniadis --- config/init.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/config/init.go b/config/init.go index d640b1b9c31..7e17faa0513 100644 --- a/config/init.go +++ b/config/init.go @@ -7,7 +7,7 @@ import ( "io" ci "gx/ipfs/QmVoi5es8D5fNHZDqoW6DgDAEPEV5hQp8GBz161vZXiwpQ/go-libp2p-crypto" - peer "gx/ipfs/QmWtbQU15LaB5B1JC2F7TV9P4K88vD3PpA4AJrwfCjhML8/go-libp2p-peer" + peer "gx/ipfs/QmWXjJo15p4pzT7cayEwZi2sWgJqLnGDof6ZGMh9xBgU1p/go-libp2p-peer" ) func Init(out io.Writer, nBitsForKeypair int) (*Config, error) { From 3e6db54da249a0c99a20c14bc2f4ef2439697500 Mon Sep 17 00:00:00 2001 From: Jeromy Date: Wed, 5 Oct 2016 15:49:08 -0700 Subject: [PATCH 088/414] go-ipfs-config: update to libp2p 4.0.1 and propogate other changes License: MIT Signed-off-by: Jeromy --- config/identity.go | 2 +- config/init.go | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/config/identity.go b/config/identity.go index 61e11cf5b29..ca89ae72f3d 100644 --- a/config/identity.go +++ b/config/identity.go @@ -2,7 +2,7 @@ package config import ( "encoding/base64" - ic "gx/ipfs/QmVoi5es8D5fNHZDqoW6DgDAEPEV5hQp8GBz161vZXiwpQ/go-libp2p-crypto" + ic "gx/ipfs/QmfWDLQjGjVe4fr5CoztYW2DYYjRysMJrFe1RCsXLPTf46/go-libp2p-crypto" ) const IdentityTag = "Identity" diff --git a/config/init.go b/config/init.go index 7e17faa0513..edb5408b2f3 100644 --- a/config/init.go +++ b/config/init.go @@ -6,8 +6,8 @@ import ( "fmt" "io" - ci "gx/ipfs/QmVoi5es8D5fNHZDqoW6DgDAEPEV5hQp8GBz161vZXiwpQ/go-libp2p-crypto" - peer "gx/ipfs/QmWXjJo15p4pzT7cayEwZi2sWgJqLnGDof6ZGMh9xBgU1p/go-libp2p-peer" + peer "gx/ipfs/QmfMmLGoKzCHDN7cGgk64PJr4iipzidDRME8HABSJqvmhC/go-libp2p-peer" + ci "gx/ipfs/QmfWDLQjGjVe4fr5CoztYW2DYYjRysMJrFe1RCsXLPTf46/go-libp2p-crypto" ) func Init(out io.Writer, nBitsForKeypair int) (*Config, error) { From ed67b7bf9a76ef829fa6327ec9e89ffcbdfc0191 Mon Sep 17 00:00:00 2001 From: Richard Littauer Date: Fri, 1 Jul 2016 18:36:55 +0100 Subject: [PATCH 089/414] go-ipfs-config: Changed so only explicit ipfs cli commands are lowercased License: MIT Signed-off-by: Richard Littauer --- config/bootstrap_peers.go | 2 +- config/config.go | 2 +- config/tour.go | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/config/bootstrap_peers.go b/config/bootstrap_peers.go index db6bad2e662..788112ec0aa 100644 --- a/config/bootstrap_peers.go +++ b/config/bootstrap_peers.go @@ -8,7 +8,7 @@ import ( ) // DefaultBootstrapAddresses are the hardcoded bootstrap addresses -// for ipfs. they are nodes run by the ipfs team. docs on these later. +// for IPFS. they are nodes run by the IPFS team. docs on these later. // As with all p2p networks, bootstrap is an important security concern. // // NOTE: This is here -- and not inside cmd/ipfs/init.go -- because of an diff --git a/config/config.go b/config/config.go index d367ac30421..898cf56a472 100644 --- a/config/config.go +++ b/config/config.go @@ -15,7 +15,7 @@ import ( var log = logging.Logger("config") -// Config is used to load IPFS config files. +// Config is used to load ipfs config files. type Config struct { Identity Identity // local node's peer identity Datastore Datastore // local node's storage diff --git a/config/tour.go b/config/tour.go index cf9aef35502..e22d8453f51 100644 --- a/config/tour.go +++ b/config/tour.go @@ -1,6 +1,6 @@ package config -// Tour stores the ipfs tour read-list and resume point +// Tour stores the 'ipfs tour' read-list and resume point type Tour struct { Last string // last tour topic read // Done []string // all topics done so far From 07559a265a32f44a36871f63da81c071b3e61a76 Mon Sep 17 00:00:00 2001 From: Jeromy Date: Fri, 11 Nov 2016 10:31:24 -0800 Subject: [PATCH 090/414] go-ipfs-config: add config option to disable bandwidth metrics License: MIT Signed-off-by: Jeromy --- config/swarm.go | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/config/swarm.go b/config/swarm.go index d398b3d80af..7d074d996d2 100644 --- a/config/swarm.go +++ b/config/swarm.go @@ -1,5 +1,6 @@ package config type SwarmConfig struct { - AddrFilters []string + AddrFilters []string + DisableBandwidthMetrics bool } From 608f6f378cfc6d2c4288249328ebedb10735dab7 Mon Sep 17 00:00:00 2001 From: Lars Gierth Date: Sun, 18 Dec 2016 05:52:56 +0100 Subject: [PATCH 091/414] go-ipfs-config: bootstrap: add a few /ip6 nodes License: MIT Signed-off-by: Lars Gierth --- config/bootstrap_peers.go | 26 +++++++++++++++++--------- 1 file changed, 17 insertions(+), 9 deletions(-) diff --git a/config/bootstrap_peers.go b/config/bootstrap_peers.go index 788112ec0aa..ef9a5222e00 100644 --- a/config/bootstrap_peers.go +++ b/config/bootstrap_peers.go @@ -14,15 +14,23 @@ import ( // NOTE: This is here -- and not inside cmd/ipfs/init.go -- because of an // import dependency issue. TODO: move this into a config/default/ package. var DefaultBootstrapAddresses = []string{ - "/ip4/104.131.131.82/tcp/4001/ipfs/QmaCpDMGvV2BGHeYERUEnRQAwe3N8SzbUtfsmvsqQLuvuJ", // mars.i.ipfs.io - "/ip4/104.236.176.52/tcp/4001/ipfs/QmSoLnSGccFuZQJzRadHn95W2CrSFmZuTdDWP8HXaHca9z", // neptune.i.ipfs.io - "/ip4/104.236.179.241/tcp/4001/ipfs/QmSoLPppuBtQSGwKDZT2M73ULpjvfd3aZ6ha4oFGL1KrGM", // pluto.i.ipfs.io - "/ip4/162.243.248.213/tcp/4001/ipfs/QmSoLueR4xBeUbY9WZ9xGUUxunbKWcrNFTDAadQJmocnWm", // uranus.i.ipfs.io - "/ip4/128.199.219.111/tcp/4001/ipfs/QmSoLSafTMBsPKadTEgaXctDQVcqN88CNLHXMkTNwMKPnu", // saturn.i.ipfs.io - "/ip4/104.236.76.40/tcp/4001/ipfs/QmSoLV4Bbm51jM9C4gDYZQ9Cy3U6aXMJDAbzgu2fzaDs64", // venus.i.ipfs.io - "/ip4/178.62.158.247/tcp/4001/ipfs/QmSoLer265NRgSp2LA3dPaeykiS1J6DifTC88f5uVQKNAd", // earth.i.ipfs.io - "/ip4/178.62.61.185/tcp/4001/ipfs/QmSoLMeWqB7YGVLJN3pNLQpmmEk35v6wYtsMGLzSr5QBU3", // mercury.i.ipfs.io - "/ip4/104.236.151.122/tcp/4001/ipfs/QmSoLju6m7xTh3DuokvT3886QRYqxAzb1kShaanJgW36yx", // jupiter.i.ipfs.io + "/ip4/104.131.131.82/tcp/4001/ipfs/QmaCpDMGvV2BGHeYERUEnRQAwe3N8SzbUtfsmvsqQLuvuJ", // mars.i.ipfs.io + "/ip4/104.236.176.52/tcp/4001/ipfs/QmSoLnSGccFuZQJzRadHn95W2CrSFmZuTdDWP8HXaHca9z", // neptune.i.ipfs.io + "/ip4/104.236.179.241/tcp/4001/ipfs/QmSoLPppuBtQSGwKDZT2M73ULpjvfd3aZ6ha4oFGL1KrGM", // pluto.i.ipfs.io + "/ip4/162.243.248.213/tcp/4001/ipfs/QmSoLueR4xBeUbY9WZ9xGUUxunbKWcrNFTDAadQJmocnWm", // uranus.i.ipfs.io + "/ip4/128.199.219.111/tcp/4001/ipfs/QmSoLSafTMBsPKadTEgaXctDQVcqN88CNLHXMkTNwMKPnu", // saturn.i.ipfs.io + "/ip4/104.236.76.40/tcp/4001/ipfs/QmSoLV4Bbm51jM9C4gDYZQ9Cy3U6aXMJDAbzgu2fzaDs64", // venus.i.ipfs.io + "/ip4/178.62.158.247/tcp/4001/ipfs/QmSoLer265NRgSp2LA3dPaeykiS1J6DifTC88f5uVQKNAd", // earth.i.ipfs.io + "/ip4/178.62.61.185/tcp/4001/ipfs/QmSoLMeWqB7YGVLJN3pNLQpmmEk35v6wYtsMGLzSr5QBU3", // mercury.i.ipfs.io + "/ip4/104.236.151.122/tcp/4001/ipfs/QmSoLju6m7xTh3DuokvT3886QRYqxAzb1kShaanJgW36yx", // jupiter.i.ipfs.io + "/ip6/2604:a880:1:20::1f9:9001/tcp/4001/ipfs/QmSoLnSGccFuZQJzRadHn95W2CrSFmZuTdDWP8HXaHca9z", // neptune.i.ipfs.io + "/ip6/2604:a880:1:20::203:d001/tcp/4001/ipfs/QmSoLPppuBtQSGwKDZT2M73ULpjvfd3aZ6ha4oFGL1KrGM", // pluto.i.ipfs.io + "/ip6/2604:a880:0:1010::23:d001/tcp/4001/ipfs/QmSoLueR4xBeUbY9WZ9xGUUxunbKWcrNFTDAadQJmocnWm", // uranus.i.ipfs.io + "/ip6/2400:6180:0:d0::151:6001/tcp/4001/ipfs/QmSoLSafTMBsPKadTEgaXctDQVcqN88CNLHXMkTNwMKPnu", // saturn.i.ipfs.io + "/ip6/2604:a880:800:10::4a:5001/tcp/4001/ipfs/QmSoLV4Bbm51jM9C4gDYZQ9Cy3U6aXMJDAbzgu2fzaDs64", // venus.i.ipfs.io + "/ip6/2a03:b0c0:0:1010::23:1001/tcp/4001/ipfs/QmSoLer265NRgSp2LA3dPaeykiS1J6DifTC88f5uVQKNAd", // earth.i.ipfs.io + "/ip6/2a03:b0c0:1:d0::e7:1/tcp/4001/ipfs/QmSoLMeWqB7YGVLJN3pNLQpmmEk35v6wYtsMGLzSr5QBU3", // mercury.i.ipfs.io + "/ip6/2604:a880:1:20::1d9:6001/tcp/4001/ipfs/QmSoLju6m7xTh3DuokvT3886QRYqxAzb1kShaanJgW36yx", // jupiter.i.ipfs.io } // BootstrapPeer is a peer used to bootstrap the network. From 90644b31309f7d98775a875dbb912ddf0bd8cc7f Mon Sep 17 00:00:00 2001 From: Jeromy Date: Thu, 2 Feb 2017 20:09:02 -0800 Subject: [PATCH 092/414] go-ipfs-config: update go-multihash and bubble up deps License: MIT Signed-off-by: Jeromy --- config/identity.go | 2 +- config/init.go | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/config/identity.go b/config/identity.go index ca89ae72f3d..d8420cc54ec 100644 --- a/config/identity.go +++ b/config/identity.go @@ -2,7 +2,7 @@ package config import ( "encoding/base64" - ic "gx/ipfs/QmfWDLQjGjVe4fr5CoztYW2DYYjRysMJrFe1RCsXLPTf46/go-libp2p-crypto" + ic "gx/ipfs/QmNiCwBNA8MWDADTFVq1BonUEJbS2SvjAoNkZZrhEwcuUi/go-libp2p-crypto" ) const IdentityTag = "Identity" diff --git a/config/init.go b/config/init.go index edb5408b2f3..28782c8f335 100644 --- a/config/init.go +++ b/config/init.go @@ -6,8 +6,8 @@ import ( "fmt" "io" - peer "gx/ipfs/QmfMmLGoKzCHDN7cGgk64PJr4iipzidDRME8HABSJqvmhC/go-libp2p-peer" - ci "gx/ipfs/QmfWDLQjGjVe4fr5CoztYW2DYYjRysMJrFe1RCsXLPTf46/go-libp2p-crypto" + ci "gx/ipfs/QmNiCwBNA8MWDADTFVq1BonUEJbS2SvjAoNkZZrhEwcuUi/go-libp2p-crypto" + peer "gx/ipfs/QmZcUPvPhD1Xvk6mwijYF8AfR3mG31S1YsEfHG4khrFPRr/go-libp2p-peer" ) func Init(out io.Writer, nBitsForKeypair int) (*Config, error) { From 4b5929d47f1681615c407007c214a93aa75ae10d Mon Sep 17 00:00:00 2001 From: Jeromy Date: Sun, 5 Mar 2017 23:06:04 -0800 Subject: [PATCH 093/414] go-ipfs-config: update go-libp2p-kad-dht with getclosestpeers fix License: MIT Signed-off-by: Jeromy --- config/identity.go | 2 +- config/init.go | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/config/identity.go b/config/identity.go index d8420cc54ec..28ca64c3cb4 100644 --- a/config/identity.go +++ b/config/identity.go @@ -2,7 +2,7 @@ package config import ( "encoding/base64" - ic "gx/ipfs/QmNiCwBNA8MWDADTFVq1BonUEJbS2SvjAoNkZZrhEwcuUi/go-libp2p-crypto" + ic "gx/ipfs/QmPGxZ1DP2w45WcogpW1h43BvseXbfke9N91qotpoQcUeS/go-libp2p-crypto" ) const IdentityTag = "Identity" diff --git a/config/init.go b/config/init.go index 28782c8f335..55131f6457f 100644 --- a/config/init.go +++ b/config/init.go @@ -6,8 +6,8 @@ import ( "fmt" "io" - ci "gx/ipfs/QmNiCwBNA8MWDADTFVq1BonUEJbS2SvjAoNkZZrhEwcuUi/go-libp2p-crypto" - peer "gx/ipfs/QmZcUPvPhD1Xvk6mwijYF8AfR3mG31S1YsEfHG4khrFPRr/go-libp2p-peer" + ci "gx/ipfs/QmPGxZ1DP2w45WcogpW1h43BvseXbfke9N91qotpoQcUeS/go-libp2p-crypto" + peer "gx/ipfs/QmWUswjn261LSyVxWAEpMVtPdy8zmKBJJfBpG3Qdpa8ZsE/go-libp2p-peer" ) func Init(out io.Writer, nBitsForKeypair int) (*Config, error) { From f1cb6feeb5e4b2199338429489eaac1032d15375 Mon Sep 17 00:00:00 2001 From: Jeromy Date: Fri, 20 Jan 2017 10:48:23 -0800 Subject: [PATCH 094/414] go-ipfs-config: Implement basic filestore 'no-copy' functionality License: MIT Signed-off-by: Jeromy --- config/config.go | 3 ++- config/experiments.go | 5 +++++ 2 files changed, 7 insertions(+), 1 deletion(-) create mode 100644 config/experiments.go diff --git a/config/config.go b/config/config.go index 898cf56a472..fa94d1e3f07 100644 --- a/config/config.go +++ b/config/config.go @@ -30,7 +30,8 @@ type Config struct { API API // local node's API settings Swarm SwarmConfig - Reprovider Reprovider + Reprovider Reprovider + Experimental Experiments } const ( diff --git a/config/experiments.go b/config/experiments.go new file mode 100644 index 00000000000..4757d15a362 --- /dev/null +++ b/config/experiments.go @@ -0,0 +1,5 @@ +package config + +type Experiments struct { + FilestoreEnabled bool +} From 0d70e835d722a93612e6d8611d78fb6776ea46ab Mon Sep 17 00:00:00 2001 From: Kevin Atkinson Date: Sat, 18 Mar 2017 18:50:10 -0400 Subject: [PATCH 095/414] go-ipfs-config: Add DisableNatPortMap option. License: MIT Signed-off-by: Kevin Atkinson --- config/swarm.go | 1 + 1 file changed, 1 insertion(+) diff --git a/config/swarm.go b/config/swarm.go index 7d074d996d2..d61c0a2e51b 100644 --- a/config/swarm.go +++ b/config/swarm.go @@ -3,4 +3,5 @@ package config type SwarmConfig struct { AddrFilters []string DisableBandwidthMetrics bool + DisableNatPortMap bool } From 4d73fe8b4296f094f4785fc43dd064c8fd614eb6 Mon Sep 17 00:00:00 2001 From: Jeromy Date: Wed, 22 Mar 2017 16:09:34 -0700 Subject: [PATCH 096/414] go-ipfs-config: add global config switch for sharding License: MIT Signed-off-by: Jeromy --- config/experiments.go | 1 + 1 file changed, 1 insertion(+) diff --git a/config/experiments.go b/config/experiments.go index 4757d15a362..8eb942b3989 100644 --- a/config/experiments.go +++ b/config/experiments.go @@ -2,4 +2,5 @@ package config type Experiments struct { FilestoreEnabled bool + ShardingEnabled bool } From 413034b740938a2c630323be08541edc090d72ce Mon Sep 17 00:00:00 2001 From: Jeromy Date: Fri, 24 Mar 2017 23:51:18 -0700 Subject: [PATCH 097/414] go-ipfs-config: bubble up updates from go-multihash changes License: MIT Signed-off-by: Jeromy --- config/identity.go | 2 +- config/init.go | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/config/identity.go b/config/identity.go index 28ca64c3cb4..c471bb4f6c6 100644 --- a/config/identity.go +++ b/config/identity.go @@ -2,7 +2,7 @@ package config import ( "encoding/base64" - ic "gx/ipfs/QmPGxZ1DP2w45WcogpW1h43BvseXbfke9N91qotpoQcUeS/go-libp2p-crypto" + ic "gx/ipfs/QmP1DfoUjiWH2ZBo1PBH6FupdBucbDepx3HpWmEY6JMUpY/go-libp2p-crypto" ) const IdentityTag = "Identity" diff --git a/config/init.go b/config/init.go index 55131f6457f..0538826f667 100644 --- a/config/init.go +++ b/config/init.go @@ -6,8 +6,8 @@ import ( "fmt" "io" - ci "gx/ipfs/QmPGxZ1DP2w45WcogpW1h43BvseXbfke9N91qotpoQcUeS/go-libp2p-crypto" - peer "gx/ipfs/QmWUswjn261LSyVxWAEpMVtPdy8zmKBJJfBpG3Qdpa8ZsE/go-libp2p-peer" + ci "gx/ipfs/QmP1DfoUjiWH2ZBo1PBH6FupdBucbDepx3HpWmEY6JMUpY/go-libp2p-crypto" + peer "gx/ipfs/QmdS9KpbDyPrieswibZhkod1oXqRwZJrUPzxCofAMWpFGq/go-libp2p-peer" ) func Init(out io.Writer, nBitsForKeypair int) (*Config, error) { From 53ceee47a91fefdc67bf1e630b1a2f29387aa767 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C5=81ukasz=20Magiera?= Date: Sun, 28 May 2017 23:36:37 +0200 Subject: [PATCH 098/414] go-ipfs-config: Corenet API: Apply suggestions, cleanups MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit License: MIT Signed-off-by: Łukasz Magiera --- config/experiments.go | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/config/experiments.go b/config/experiments.go index 8eb942b3989..f76572ee2af 100644 --- a/config/experiments.go +++ b/config/experiments.go @@ -1,6 +1,7 @@ package config type Experiments struct { - FilestoreEnabled bool - ShardingEnabled bool + FilestoreEnabled bool + ShardingEnabled bool + Libp2pStreamMounting bool } From 9e050b1526f9ba5689e3525be8a167618916de76 Mon Sep 17 00:00:00 2001 From: zramsay Date: Wed, 31 May 2017 16:56:11 -0400 Subject: [PATCH 099/414] go-ipfs-config: apply the megacheck tool to improve code quality License: MIT Signed-off-by: Zach Ramsay --- config/config.go | 3 --- 1 file changed, 3 deletions(-) diff --git a/config/config.go b/config/config.go index fa94d1e3f07..411cecc681f 100644 --- a/config/config.go +++ b/config/config.go @@ -10,11 +10,8 @@ import ( "strings" "github.com/ipfs/go-ipfs/Godeps/_workspace/src/github.com/mitchellh/go-homedir" - logging "gx/ipfs/QmSpJByNKFX1sCsHBEp3R73FL4NF6FnQTEGyNAXHm2GS52/go-log" ) -var log = logging.Logger("config") - // Config is used to load ipfs config files. type Config struct { Identity Identity // local node's peer identity From 11f5cc698bf87bbc254e333d8324f84e6be82778 Mon Sep 17 00:00:00 2001 From: zramsay Date: Wed, 31 May 2017 23:41:26 -0400 Subject: [PATCH 100/414] go-ipfs-config: address PR comments; remove commented/dead code License: MIT Signed-off-by: Zach Ramsay --- config/supernode.go | 7 ------- 1 file changed, 7 deletions(-) diff --git a/config/supernode.go b/config/supernode.go index de403fadd7d..a985040b26f 100644 --- a/config/supernode.go +++ b/config/supernode.go @@ -20,13 +20,6 @@ var DefaultSNRServers = []string{ "/ip4/178.62.61.185/tcp/4002/ipfs/QmVw6fGNqBixZE4bewRLT2VXX7fAHUHs8JyidDiJ1P7RUN", } -func initSNRConfig() (*SupernodeClientConfig, error) { - // TODO perform validation - return &SupernodeClientConfig{ - Servers: DefaultSNRServers, - }, nil -} - func (gcr *SupernodeClientConfig) ServerIPFSAddrs() ([]ipfsaddr.IPFSAddr, error) { var addrs []ipfsaddr.IPFSAddr for _, server := range gcr.Servers { From 08255bcd915fcdee98ac4cc5f729d5c48d49f261 Mon Sep 17 00:00:00 2001 From: Ivan Date: Sat, 10 Jun 2017 05:56:56 +0300 Subject: [PATCH 101/414] go-ipfs-config: Allow the use of the Range header in WebTorrent (#3929) * Allow the use of the Range header in WebTorrent License: MIT Signed-off-by: Ivan386 * Allow the use of the Range header in WebTorrent License: MIT Signed-off-by: Ivan --- config/init.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/config/init.go b/config/init.go index 0538826f667..5b17011dabe 100644 --- a/config/init.go +++ b/config/init.go @@ -65,7 +65,7 @@ func Init(out io.Writer, nBitsForKeypair int) (*Config, error) { HTTPHeaders: map[string][]string{ "Access-Control-Allow-Origin": []string{"*"}, "Access-Control-Allow-Methods": []string{"GET"}, - "Access-Control-Allow-Headers": []string{"X-Requested-With"}, + "Access-Control-Allow-Headers": []string{"X-Requested-With", "Range"}, }, }, Reprovider: Reprovider{ From c475d31c6163b21cbc9da4add93fe74f4a3b2406 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C5=81ukasz=20Magiera?= Date: Wed, 21 Jun 2017 20:37:07 +0200 Subject: [PATCH 102/414] go-ipfs-config: Disable MDNS in server profile, move it out from init.go MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit License: MIT Signed-off-by: Łukasz Magiera --- config/profile.go | 31 +++++++++++++++++++++++++++++++ 1 file changed, 31 insertions(+) create mode 100644 config/profile.go diff --git a/config/profile.go b/config/profile.go new file mode 100644 index 00000000000..2f754617c37 --- /dev/null +++ b/config/profile.go @@ -0,0 +1,31 @@ +package config + +// ConfigProfiles is a map holding configuration transformers +var ConfigProfiles = map[string]func(*Config) error{ + "server": func(c *Config) error { + + // defaultServerFilters has a list of non-routable IPv4 prefixes + // according to http://www.iana.org/assignments/iana-ipv4-special-registry/iana-ipv4-special-registry.xhtml + defaultServerFilters := []string{ + "/ip4/10.0.0.0/ipcidr/8", + "/ip4/100.64.0.0/ipcidr/10", + "/ip4/169.254.0.0/ipcidr/16", + "/ip4/172.16.0.0/ipcidr/12", + "/ip4/192.0.0.0/ipcidr/24", + "/ip4/192.0.0.0/ipcidr/29", + "/ip4/192.0.0.8/ipcidr/32", + "/ip4/192.0.0.170/ipcidr/32", + "/ip4/192.0.0.171/ipcidr/32", + "/ip4/192.0.2.0/ipcidr/24", + "/ip4/192.168.0.0/ipcidr/16", + "/ip4/198.18.0.0/ipcidr/15", + "/ip4/198.51.100.0/ipcidr/24", + "/ip4/203.0.113.0/ipcidr/24", + "/ip4/240.0.0.0/ipcidr/4", + } + + c.Swarm.AddrFilters = append(c.Swarm.AddrFilters, defaultServerFilters...) + c.Discovery.MDNS.Enabled = false + return nil + }, +} From af57db772588f78081d73b588747adc2fff2e97d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C5=81ukasz=20Magiera?= Date: Thu, 6 Jul 2017 21:42:17 +0200 Subject: [PATCH 103/414] go-ipfs-config: Add test init profile MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit License: MIT Signed-off-by: Łukasz Magiera --- config/profile.go | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/config/profile.go b/config/profile.go index 2f754617c37..359aa313a58 100644 --- a/config/profile.go +++ b/config/profile.go @@ -28,4 +28,17 @@ var ConfigProfiles = map[string]func(*Config) error{ c.Discovery.MDNS.Enabled = false return nil }, + "test": func(c *Config) error { + c.Addresses.API = "/ip4/127.0.0.1/tcp/0" + c.Addresses.Gateway = "/ip4/127.0.0.1/tcp/0" + + c.Swarm.DisableNatPortMap = true + c.Addresses.Swarm = []string{ + "/ip4/127.0.0.1/tcp/0", + } + + c.Bootstrap = []string{} + c.Discovery.MDNS.Enabled = false + return nil + }, } From 87d7ddbb9bf400b51c9c81ad30d8824c907a8bdc Mon Sep 17 00:00:00 2001 From: Jeromy Date: Tue, 11 Jul 2017 19:17:51 -0700 Subject: [PATCH 104/414] go-ipfs-config: update go-multihash and bubble up changes License: MIT Signed-off-by: Jeromy --- config/identity.go | 2 +- config/init.go | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/config/identity.go b/config/identity.go index c471bb4f6c6..077383c9346 100644 --- a/config/identity.go +++ b/config/identity.go @@ -2,7 +2,7 @@ package config import ( "encoding/base64" - ic "gx/ipfs/QmP1DfoUjiWH2ZBo1PBH6FupdBucbDepx3HpWmEY6JMUpY/go-libp2p-crypto" + ic "gx/ipfs/QmaPbCnUMBohSGo3KnxEa2bHqyJVVeEEcwtqJAYxerieBo/go-libp2p-crypto" ) const IdentityTag = "Identity" diff --git a/config/init.go b/config/init.go index 5b17011dabe..1f8ee434be1 100644 --- a/config/init.go +++ b/config/init.go @@ -6,8 +6,8 @@ import ( "fmt" "io" - ci "gx/ipfs/QmP1DfoUjiWH2ZBo1PBH6FupdBucbDepx3HpWmEY6JMUpY/go-libp2p-crypto" - peer "gx/ipfs/QmdS9KpbDyPrieswibZhkod1oXqRwZJrUPzxCofAMWpFGq/go-libp2p-peer" + peer "gx/ipfs/QmXYjuNuxVzXKJCfWasQk1RqkhVLDM9jtUKhqc2WPQmFSB/go-libp2p-peer" + ci "gx/ipfs/QmaPbCnUMBohSGo3KnxEa2bHqyJVVeEEcwtqJAYxerieBo/go-libp2p-crypto" ) func Init(out io.Writer, nBitsForKeypair int) (*Config, error) { From c875a44a8d6a71009f37da22a29e75175dae1742 Mon Sep 17 00:00:00 2001 From: Lars Gierth Date: Wed, 31 May 2017 02:49:14 +0200 Subject: [PATCH 105/414] go-ipfs-config: core: make announced swarm addresses configurable License: MIT Signed-off-by: Lars Gierth --- config/addresses.go | 8 +++++--- config/init.go | 6 ++++-- 2 files changed, 9 insertions(+), 5 deletions(-) diff --git a/config/addresses.go b/config/addresses.go index ba891526196..22c530655b2 100644 --- a/config/addresses.go +++ b/config/addresses.go @@ -2,7 +2,9 @@ package config // Addresses stores the (string) multiaddr addresses for the node. type Addresses struct { - Swarm []string // addresses for the swarm network - API string // address for the local API (RPC) - Gateway string // address to listen on for IPFS HTTP object gateway + Swarm []string // addresses for the swarm to listen on + Announce []string // swarm addresses to announce to the network + NoAnnounce []string // swarm addresses not to announce to the network + API string // address for the local API (RPC) + Gateway string // address to listen on for IPFS HTTP object gateway } diff --git a/config/init.go b/config/init.go index 1f8ee434be1..aa129d97e12 100644 --- a/config/init.go +++ b/config/init.go @@ -36,8 +36,10 @@ func Init(out io.Writer, nBitsForKeypair int) (*Config, error) { // "/ip4/0.0.0.0/udp/4002/utp", // disabled for now. "/ip6/::/tcp/4001", }, - API: "/ip4/127.0.0.1/tcp/5001", - Gateway: "/ip4/127.0.0.1/tcp/8080", + Announce: []string{}, + NoAnnounce: []string{}, + API: "/ip4/127.0.0.1/tcp/5001", + Gateway: "/ip4/127.0.0.1/tcp/8080", }, Datastore: datastore, From 2f2b1fbcd71c8693376d2cb7551f57707f3a653e Mon Sep 17 00:00:00 2001 From: Sherod Taylor Date: Sat, 5 Aug 2017 22:55:50 -0500 Subject: [PATCH 106/414] go-ipfs-config: Removed tour command and fix test License: MIT Signed-off-by: Sherod Taylor --- config/config.go | 1 - config/tour.go | 7 ------- 2 files changed, 8 deletions(-) delete mode 100644 config/tour.go diff --git a/config/config.go b/config/config.go index 411cecc681f..3e3c891683d 100644 --- a/config/config.go +++ b/config/config.go @@ -21,7 +21,6 @@ type Config struct { Discovery Discovery // local node's discovery mechanisms Ipns Ipns // Ipns settings Bootstrap []string // local nodes's bootstrap peer addresses - Tour Tour // local node's tour position Gateway Gateway // local node's gateway server options SupernodeRouting SupernodeClientConfig // local node's routing servers (if SupernodeRouting enabled) API API // local node's API settings diff --git a/config/tour.go b/config/tour.go deleted file mode 100644 index e22d8453f51..00000000000 --- a/config/tour.go +++ /dev/null @@ -1,7 +0,0 @@ -package config - -// Tour stores the 'ipfs tour' read-list and resume point -type Tour struct { - Last string // last tour topic read - // Done []string // all topics done so far -} From 92d7259c688d31a608a0a075d5f22cbe9bfda8ae Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C5=81ukasz=20Magiera?= Date: Tue, 1 Aug 2017 02:57:21 +0200 Subject: [PATCH 107/414] go-ipfs-config: Reprovider strategies MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit License: MIT Signed-off-by: Łukasz Magiera --- config/init.go | 1 + config/reprovider.go | 1 + 2 files changed, 2 insertions(+) diff --git a/config/init.go b/config/init.go index aa129d97e12..f31edd42b33 100644 --- a/config/init.go +++ b/config/init.go @@ -72,6 +72,7 @@ func Init(out io.Writer, nBitsForKeypair int) (*Config, error) { }, Reprovider: Reprovider{ Interval: "12h", + Strategy: "all", }, } diff --git a/config/reprovider.go b/config/reprovider.go index 53cf293ab61..fa029c2fc21 100644 --- a/config/reprovider.go +++ b/config/reprovider.go @@ -2,4 +2,5 @@ package config type Reprovider struct { Interval string // Time period to reprovide locally stored objects to the network + Strategy string // Which keys to announce } From b4973a585d317ed1620bea06f99a98503cef885d Mon Sep 17 00:00:00 2001 From: vyzo Date: Wed, 26 Jul 2017 14:13:59 +0300 Subject: [PATCH 108/414] go-ipfs-config: integrate circuit-relay transport - enabled by default, so that we can dial/receive dials - /p2p-circuit/QmId address is not announced; filtered at host with AddrsFactory - use case is manual swarm connect with relay address License: MIT Signed-off-by: vyzo --- config/swarm.go | 2 ++ 1 file changed, 2 insertions(+) diff --git a/config/swarm.go b/config/swarm.go index d61c0a2e51b..25c35d58521 100644 --- a/config/swarm.go +++ b/config/swarm.go @@ -4,4 +4,6 @@ type SwarmConfig struct { AddrFilters []string DisableBandwidthMetrics bool DisableNatPortMap bool + DisableRelay bool + EnableRelayHop bool } From f65d6e4d8a4b1306f28a705ea275573bb9f4b0c8 Mon Sep 17 00:00:00 2001 From: Lars Gierth Date: Mon, 7 Aug 2017 08:53:31 +0200 Subject: [PATCH 109/414] go-ipfs-config: bootstrap: add /dnsaddr nodes, remove half of /ip4,/ip6 nodes License: MIT Signed-off-by: Lars Gierth --- config/bootstrap_peers.go | 12 ++++-------- 1 file changed, 4 insertions(+), 8 deletions(-) diff --git a/config/bootstrap_peers.go b/config/bootstrap_peers.go index ef9a5222e00..2b166ff1985 100644 --- a/config/bootstrap_peers.go +++ b/config/bootstrap_peers.go @@ -14,23 +14,19 @@ import ( // NOTE: This is here -- and not inside cmd/ipfs/init.go -- because of an // import dependency issue. TODO: move this into a config/default/ package. var DefaultBootstrapAddresses = []string{ + "/dnsaddr/bootstrap.libp2p.io/ipfs/QmNnooDu7bfjPFoTZYxMNLWUQJyrVwtbZg5gBMjTezGAJN", + "/dnsaddr/bootstrap.libp2p.io/ipfs/QmQCU2EcMqAqQPR2i9bChDtGNJchTbq5TbXJJ16u19uLTa", + "/dnsaddr/bootstrap.libp2p.io/ipfs/QmbLHAnMoJPWSCR5Zhtx6BHJX9KiKNN6tpvbUcqanj75Nb", + "/dnsaddr/bootstrap.libp2p.io/ipfs/QmcZf59bWwK5XFi76CZX8cbJ4BhTzzA3gU1ZjYZcYW3dwt", "/ip4/104.131.131.82/tcp/4001/ipfs/QmaCpDMGvV2BGHeYERUEnRQAwe3N8SzbUtfsmvsqQLuvuJ", // mars.i.ipfs.io - "/ip4/104.236.176.52/tcp/4001/ipfs/QmSoLnSGccFuZQJzRadHn95W2CrSFmZuTdDWP8HXaHca9z", // neptune.i.ipfs.io "/ip4/104.236.179.241/tcp/4001/ipfs/QmSoLPppuBtQSGwKDZT2M73ULpjvfd3aZ6ha4oFGL1KrGM", // pluto.i.ipfs.io - "/ip4/162.243.248.213/tcp/4001/ipfs/QmSoLueR4xBeUbY9WZ9xGUUxunbKWcrNFTDAadQJmocnWm", // uranus.i.ipfs.io "/ip4/128.199.219.111/tcp/4001/ipfs/QmSoLSafTMBsPKadTEgaXctDQVcqN88CNLHXMkTNwMKPnu", // saturn.i.ipfs.io "/ip4/104.236.76.40/tcp/4001/ipfs/QmSoLV4Bbm51jM9C4gDYZQ9Cy3U6aXMJDAbzgu2fzaDs64", // venus.i.ipfs.io "/ip4/178.62.158.247/tcp/4001/ipfs/QmSoLer265NRgSp2LA3dPaeykiS1J6DifTC88f5uVQKNAd", // earth.i.ipfs.io - "/ip4/178.62.61.185/tcp/4001/ipfs/QmSoLMeWqB7YGVLJN3pNLQpmmEk35v6wYtsMGLzSr5QBU3", // mercury.i.ipfs.io - "/ip4/104.236.151.122/tcp/4001/ipfs/QmSoLju6m7xTh3DuokvT3886QRYqxAzb1kShaanJgW36yx", // jupiter.i.ipfs.io - "/ip6/2604:a880:1:20::1f9:9001/tcp/4001/ipfs/QmSoLnSGccFuZQJzRadHn95W2CrSFmZuTdDWP8HXaHca9z", // neptune.i.ipfs.io "/ip6/2604:a880:1:20::203:d001/tcp/4001/ipfs/QmSoLPppuBtQSGwKDZT2M73ULpjvfd3aZ6ha4oFGL1KrGM", // pluto.i.ipfs.io - "/ip6/2604:a880:0:1010::23:d001/tcp/4001/ipfs/QmSoLueR4xBeUbY9WZ9xGUUxunbKWcrNFTDAadQJmocnWm", // uranus.i.ipfs.io "/ip6/2400:6180:0:d0::151:6001/tcp/4001/ipfs/QmSoLSafTMBsPKadTEgaXctDQVcqN88CNLHXMkTNwMKPnu", // saturn.i.ipfs.io "/ip6/2604:a880:800:10::4a:5001/tcp/4001/ipfs/QmSoLV4Bbm51jM9C4gDYZQ9Cy3U6aXMJDAbzgu2fzaDs64", // venus.i.ipfs.io "/ip6/2a03:b0c0:0:1010::23:1001/tcp/4001/ipfs/QmSoLer265NRgSp2LA3dPaeykiS1J6DifTC88f5uVQKNAd", // earth.i.ipfs.io - "/ip6/2a03:b0c0:1:d0::e7:1/tcp/4001/ipfs/QmSoLMeWqB7YGVLJN3pNLQpmmEk35v6wYtsMGLzSr5QBU3", // mercury.i.ipfs.io - "/ip6/2604:a880:1:20::1d9:6001/tcp/4001/ipfs/QmSoLju6m7xTh3DuokvT3886QRYqxAzb1kShaanJgW36yx", // jupiter.i.ipfs.io } // BootstrapPeer is a peer used to bootstrap the network. From 9c60623f12f948f8175cf373ee28bbf5792a4355 Mon Sep 17 00:00:00 2001 From: Jeromy Date: Tue, 15 Mar 2016 13:46:03 -0700 Subject: [PATCH 110/414] go-ipfs-config: make datastore configuration nicely customizable License: MIT Signed-off-by: Jeromy make things super customizable License: MIT Signed-off-by: Jeromy better json format License: MIT Signed-off-by: Jeromy Migrate to new flatfs License: MIT Signed-off-by: Jakub Sztandera --- config/datastore.go | 35 +++++++++++++++++++---------------- config/init.go | 39 +++++++++++++++++++++++++++++---------- 2 files changed, 48 insertions(+), 26 deletions(-) diff --git a/config/datastore.go b/config/datastore.go index 2b861a113cf..aec78e0e114 100644 --- a/config/datastore.go +++ b/config/datastore.go @@ -1,40 +1,43 @@ package config -import ( - "encoding/json" -) - // DefaultDataStoreDirectory is the directory to store all the local IPFS data. const DefaultDataStoreDirectory = "datastore" // Datastore tracks the configuration of the datastore. type Datastore struct { - Type string - Path string StorageMax string // in B, kB, kiB, MB, ... StorageGCWatermark int64 // in percentage to multiply on StorageMax GCPeriod string // in ns, us, ms, s, m, h + Path string + NoSync bool // deprecated + + Spec map[string]interface{} - Params *json.RawMessage - NoSync bool HashOnRead bool BloomFilterSize int } -func (d *Datastore) ParamData() []byte { - if d.Params == nil { - return nil - } - - return []byte(*d.Params) -} - type S3Datastore struct { Region string `json:"region"` Bucket string `json:"bucket"` ACL string `json:"acl"` } +type FlatDS struct { + Path string + ShardFunc string + Sync bool +} + +type LevelDB struct { + Path string + Compression string +} + +type SbsDS struct { + Path string +} + // DataStorePath returns the default data store path given a configuration root // (set an empty string to have the default configuration root) func DataStorePath(configroot string) (string, error) { diff --git a/config/init.go b/config/init.go index f31edd42b33..ae41b68e9fa 100644 --- a/config/init.go +++ b/config/init.go @@ -42,7 +42,7 @@ func Init(out io.Writer, nBitsForKeypair int) (*Config, error) { Gateway: "/ip4/127.0.0.1/tcp/8080", }, - Datastore: datastore, + Datastore: *datastore, Bootstrap: BootstrapPeerStrings(bootstrapPeers), Identity: identity, Discovery: Discovery{MDNS{ @@ -79,19 +79,38 @@ func Init(out io.Writer, nBitsForKeypair int) (*Config, error) { return conf, nil } -func datastoreConfig() (Datastore, error) { - dspath, err := DataStorePath("") - if err != nil { - return Datastore{}, err - } - return Datastore{ - Path: dspath, - Type: "leveldb", +func datastoreConfig() (*Datastore, error) { + return &Datastore{ StorageMax: "10GB", StorageGCWatermark: 90, // 90% GCPeriod: "1h", - HashOnRead: false, BloomFilterSize: 0, + Spec: map[string]interface{}{ + "type": "mount", + "mounts": []interface{}{ + map[string]interface{}{ + "mountpoint": "/blocks", + "type": "measure", + "prefix": "flatfs.datastore", + "child": map[string]interface{}{ + "type": "flatfs", + "path": "blocks", + "nosync": false, + "shardFunc": "/repo/flatfs/shard/v1/next-to-last/2", + }, + }, + map[string]interface{}{ + "mountpoint": "/", + "type": "measure", + "prefix": "leveldb.datastore", + "child": map[string]interface{}{ + "type": "levelds", + "path": "datastore", + "compression": "none", + }, + }, + }, + }, }, nil } From 94a60d3bc70ddaf2aeecc5906baa3a3286b2278e Mon Sep 17 00:00:00 2001 From: Kevin Atkinson Date: Wed, 10 May 2017 03:48:23 -0400 Subject: [PATCH 111/414] go-ipfs-config: cleanup and bug fixes License: MIT Signed-off-by: Kevin Atkinson --- config/datastore.go | 33 ++++++++++----------------------- config/init.go | 2 +- 2 files changed, 11 insertions(+), 24 deletions(-) diff --git a/config/datastore.go b/config/datastore.go index aec78e0e114..2b2bcb51828 100644 --- a/config/datastore.go +++ b/config/datastore.go @@ -1,5 +1,9 @@ package config +import ( + "encoding/json" +) + // DefaultDataStoreDirectory is the directory to store all the local IPFS data. const DefaultDataStoreDirectory = "datastore" @@ -8,8 +12,12 @@ type Datastore struct { StorageMax string // in B, kB, kiB, MB, ... StorageGCWatermark int64 // in percentage to multiply on StorageMax GCPeriod string // in ns, us, ms, s, m, h - Path string - NoSync bool // deprecated + + // deprecated fields, use Spec + Type string `json:",omitempty"` + Path string `json:",omitempty"` + NoSync bool `json:",omitempty"` + Params *json.RawMessage `json:",omitempty"` Spec map[string]interface{} @@ -17,27 +25,6 @@ type Datastore struct { BloomFilterSize int } -type S3Datastore struct { - Region string `json:"region"` - Bucket string `json:"bucket"` - ACL string `json:"acl"` -} - -type FlatDS struct { - Path string - ShardFunc string - Sync bool -} - -type LevelDB struct { - Path string - Compression string -} - -type SbsDS struct { - Path string -} - // DataStorePath returns the default data store path given a configuration root // (set an empty string to have the default configuration root) func DataStorePath(configroot string) (string, error) { diff --git a/config/init.go b/config/init.go index ae41b68e9fa..1ab42f6ff7e 100644 --- a/config/init.go +++ b/config/init.go @@ -95,7 +95,7 @@ func datastoreConfig() (*Datastore, error) { "child": map[string]interface{}{ "type": "flatfs", "path": "blocks", - "nosync": false, + "sync": true, "shardFunc": "/repo/flatfs/shard/v1/next-to-last/2", }, }, From f142bea007fd749624e002561d76476e6ebdf89a Mon Sep 17 00:00:00 2001 From: Kevin Atkinson Date: Sat, 20 May 2017 00:12:03 -0400 Subject: [PATCH 112/414] go-ipfs-config: bump repo version, remove support for old config License: MIT Signed-off-by: Kevin Atkinson --- config/init.go | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-) diff --git a/config/init.go b/config/init.go index 1ab42f6ff7e..7b6424920b2 100644 --- a/config/init.go +++ b/config/init.go @@ -21,10 +21,7 @@ func Init(out io.Writer, nBitsForKeypair int) (*Config, error) { return nil, err } - datastore, err := datastoreConfig() - if err != nil { - return nil, err - } + datastore := DefaultDatastoreConfig() conf := &Config{ @@ -79,7 +76,8 @@ func Init(out io.Writer, nBitsForKeypair int) (*Config, error) { return conf, nil } -func datastoreConfig() (*Datastore, error) { +// DatastoreConfig is an internal function exported to aid in testing. +func DefaultDatastoreConfig() *Datastore { return &Datastore{ StorageMax: "10GB", StorageGCWatermark: 90, // 90% @@ -111,7 +109,7 @@ func datastoreConfig() (*Datastore, error) { }, }, }, - }, nil + } } // identityConfig initializes a new identity. From 4eb6ac60549fb55f32aef34a8c176976521389a4 Mon Sep 17 00:00:00 2001 From: Kevin Atkinson Date: Mon, 12 Jun 2017 21:43:17 -0400 Subject: [PATCH 113/414] go-ipfs-config: address p.r. comments License: MIT Signed-off-by: Kevin Atkinson --- config/init.go | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/config/init.go b/config/init.go index 7b6424920b2..e0470c71d73 100644 --- a/config/init.go +++ b/config/init.go @@ -39,7 +39,7 @@ func Init(out io.Writer, nBitsForKeypair int) (*Config, error) { Gateway: "/ip4/127.0.0.1/tcp/8080", }, - Datastore: *datastore, + Datastore: datastore, Bootstrap: BootstrapPeerStrings(bootstrapPeers), Identity: identity, Discovery: Discovery{MDNS{ @@ -77,8 +77,8 @@ func Init(out io.Writer, nBitsForKeypair int) (*Config, error) { } // DatastoreConfig is an internal function exported to aid in testing. -func DefaultDatastoreConfig() *Datastore { - return &Datastore{ +func DefaultDatastoreConfig() Datastore { + return Datastore{ StorageMax: "10GB", StorageGCWatermark: 90, // 90% GCPeriod: "1h", From 2aa8f0221b87adf642d746a7a1b65a9577f482bd Mon Sep 17 00:00:00 2001 From: Kevin Atkinson Date: Fri, 14 Jul 2017 15:44:48 -0400 Subject: [PATCH 114/414] go-ipfs-config: Address p.r. feedback License: MIT Signed-off-by: Kevin Atkinson --- config/init.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/config/init.go b/config/init.go index e0470c71d73..80923355e5c 100644 --- a/config/init.go +++ b/config/init.go @@ -76,7 +76,7 @@ func Init(out io.Writer, nBitsForKeypair int) (*Config, error) { return conf, nil } -// DatastoreConfig is an internal function exported to aid in testing. +// DefaultDatastoreConfig is an internal function exported to aid in testing. func DefaultDatastoreConfig() Datastore { return Datastore{ StorageMax: "10GB", From 6110648544dbe354f85e35cb6c7819d0b8aea83e Mon Sep 17 00:00:00 2001 From: Jeromy Date: Mon, 4 Sep 2017 12:33:15 -0700 Subject: [PATCH 115/414] go-ipfs-config: add badger init profile License: MIT Signed-off-by: Jeromy --- config/profile.go | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/config/profile.go b/config/profile.go index 359aa313a58..e276ee573ad 100644 --- a/config/profile.go +++ b/config/profile.go @@ -41,4 +41,11 @@ var ConfigProfiles = map[string]func(*Config) error{ c.Discovery.MDNS.Enabled = false return nil }, + "badgerds": func(c *Config) error { + c.Datastore.Spec = map[string]interface{}{ + "type": "badgerds", + "path": "badgerds", + } + return nil + }, } From 118baa65431ecb9d0ca37a1c4907912dc05ccfaf Mon Sep 17 00:00:00 2001 From: Jeromy Date: Tue, 5 Sep 2017 21:24:48 -0700 Subject: [PATCH 116/414] go-ipfs-config: add measure layer to badgerds profile defaults License: MIT Signed-off-by: Jeromy --- config/profile.go | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/config/profile.go b/config/profile.go index e276ee573ad..4912e4be02d 100644 --- a/config/profile.go +++ b/config/profile.go @@ -43,8 +43,12 @@ var ConfigProfiles = map[string]func(*Config) error{ }, "badgerds": func(c *Config) error { c.Datastore.Spec = map[string]interface{}{ - "type": "badgerds", - "path": "badgerds", + "type": "measure", + "prefix": "badger.datastore", + "child": map[string]interface{}{ + "type": "badgerds", + "path": "badgerds", + }, } return nil }, From 9e4fa0d44a067cd8c65add26f6d986689e52821c Mon Sep 17 00:00:00 2001 From: Jeromy Date: Tue, 5 Sep 2017 22:46:01 -0700 Subject: [PATCH 117/414] go-ipfs-config: add option to set syncWrites to badger License: MIT Signed-off-by: Jeromy --- config/profile.go | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/config/profile.go b/config/profile.go index 4912e4be02d..3a7bf3694f3 100644 --- a/config/profile.go +++ b/config/profile.go @@ -46,8 +46,9 @@ var ConfigProfiles = map[string]func(*Config) error{ "type": "measure", "prefix": "badger.datastore", "child": map[string]interface{}{ - "type": "badgerds", - "path": "badgerds", + "type": "badgerds", + "path": "badgerds", + "syncWrites": true, }, } return nil From 842d0d3248cfadb2104c6974be7caef7b6171d32 Mon Sep 17 00:00:00 2001 From: Steven Allen Date: Sat, 14 Oct 2017 16:43:30 -0700 Subject: [PATCH 118/414] go-ipfs-config: remove the rest of the supernode code missed in the initial cleanup License: MIT Signed-off-by: Steven Allen --- config/config.go | 21 ++++++++++----------- config/supernode.go | 33 --------------------------------- 2 files changed, 10 insertions(+), 44 deletions(-) delete mode 100644 config/supernode.go diff --git a/config/config.go b/config/config.go index 3e3c891683d..ac7c1152b77 100644 --- a/config/config.go +++ b/config/config.go @@ -14,17 +14,16 @@ import ( // Config is used to load ipfs config files. type Config struct { - Identity Identity // local node's peer identity - Datastore Datastore // local node's storage - Addresses Addresses // local node's addresses - Mounts Mounts // local node's mount points - Discovery Discovery // local node's discovery mechanisms - Ipns Ipns // Ipns settings - Bootstrap []string // local nodes's bootstrap peer addresses - Gateway Gateway // local node's gateway server options - SupernodeRouting SupernodeClientConfig // local node's routing servers (if SupernodeRouting enabled) - API API // local node's API settings - Swarm SwarmConfig + Identity Identity // local node's peer identity + Datastore Datastore // local node's storage + Addresses Addresses // local node's addresses + Mounts Mounts // local node's mount points + Discovery Discovery // local node's discovery mechanisms + Ipns Ipns // Ipns settings + Bootstrap []string // local nodes's bootstrap peer addresses + Gateway Gateway // local node's gateway server options + API API // local node's API settings + Swarm SwarmConfig Reprovider Reprovider Experimental Experiments diff --git a/config/supernode.go b/config/supernode.go deleted file mode 100644 index a985040b26f..00000000000 --- a/config/supernode.go +++ /dev/null @@ -1,33 +0,0 @@ -package config - -import "github.com/ipfs/go-ipfs/thirdparty/ipfsaddr" - -// TODO replace with final servers before merge - -// TODO rename -type SupernodeClientConfig struct { - Servers []string -} - -var DefaultSNRServers = []string{ - "/ip4/104.236.176.52/tcp/4002/ipfs/QmXdb7tWTxdFEQEFgWBqkuYSrZd3mXrC7HxkD4krGNYx2U", - "/ip4/104.236.179.241/tcp/4002/ipfs/QmVRqViDByUxjUMoPnjurjKvZhaEMFDtK35FJXHAM4Lkj6", - "/ip4/104.236.151.122/tcp/4002/ipfs/QmSZwGx8Tn8tmcM4PtDJaMeUQNRhNFdBLVGPzRiNaRJtFH", - "/ip4/162.243.248.213/tcp/4002/ipfs/QmbHVEEepCi7rn7VL7Exxpd2Ci9NNB6ifvqwhsrbRMgQFP", - "/ip4/128.199.219.111/tcp/4002/ipfs/Qmb3brdCYmKG1ycwqCbo6LUwWxTuo3FisnJV2yir7oN92R", - "/ip4/104.236.76.40/tcp/4002/ipfs/QmdRBCV8Cz2dGhoKLkD3YjPwVFECmqADQkx5ZteF2c6Fy4", - "/ip4/178.62.158.247/tcp/4002/ipfs/QmUdiMPci7YoEUBkyFZAh2pAbjqcPr7LezyiPD2artLw3v", - "/ip4/178.62.61.185/tcp/4002/ipfs/QmVw6fGNqBixZE4bewRLT2VXX7fAHUHs8JyidDiJ1P7RUN", -} - -func (gcr *SupernodeClientConfig) ServerIPFSAddrs() ([]ipfsaddr.IPFSAddr, error) { - var addrs []ipfsaddr.IPFSAddr - for _, server := range gcr.Servers { - addr, err := ipfsaddr.ParseString(server) - if err != nil { - return nil, err - } - addrs = append(addrs, addr) - } - return addrs, nil -} From 810c8e73a41a72220c30f9f82210d18952bdd1b2 Mon Sep 17 00:00:00 2001 From: Jeromy Date: Thu, 14 Sep 2017 13:43:37 -0700 Subject: [PATCH 119/414] go-ipfs-config: Integrate connection manager License: MIT Signed-off-by: Jeromy --- config/swarm.go | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/config/swarm.go b/config/swarm.go index 25c35d58521..5b128f38aab 100644 --- a/config/swarm.go +++ b/config/swarm.go @@ -6,4 +6,14 @@ type SwarmConfig struct { DisableNatPortMap bool DisableRelay bool EnableRelayHop bool + + ConnMgr ConnMgr +} + +// ConnMgr defines configuration options for the libp2p connection manager +type ConnMgr struct { + Type string + LowWater int + HighWater int + GracePeriod string } From 330b646a349132f3514c940b99815a6c24e74048 Mon Sep 17 00:00:00 2001 From: Jeromy Date: Thu, 19 Oct 2017 09:15:12 -0700 Subject: [PATCH 120/414] go-ipfs-config: default settings for the connection manager License: MIT Signed-off-by: Jeromy --- config/init.go | 21 +++++++++++++++++++++ 1 file changed, 21 insertions(+) diff --git a/config/init.go b/config/init.go index 80923355e5c..0b3537d2561 100644 --- a/config/init.go +++ b/config/init.go @@ -5,6 +5,7 @@ import ( "errors" "fmt" "io" + "time" peer "gx/ipfs/QmXYjuNuxVzXKJCfWasQk1RqkhVLDM9jtUKhqc2WPQmFSB/go-libp2p-peer" ci "gx/ipfs/QmaPbCnUMBohSGo3KnxEa2bHqyJVVeEEcwtqJAYxerieBo/go-libp2p-crypto" @@ -71,11 +72,31 @@ func Init(out io.Writer, nBitsForKeypair int) (*Config, error) { Interval: "12h", Strategy: "all", }, + Swarm: SwarmConfig{ + ConnMgr: ConnMgr{ + LowWater: DefaultConnMgrLowWater, + HighWater: DefaultConnMgrHighWater, + GracePeriod: DefaultConnMgrGracePeriod.String(), + Type: "basic", + }, + }, } return conf, nil } +// DefaultConnMgrHighWater is the default value for the connection managers +// 'high water' mark +const DefaultConnMgrHighWater = 900 + +// DefaultConnMgrLowWater is the default value for the connection managers 'low +// water' mark +const DefaultConnMgrLowWater = 600 + +// DefaultConnMgrGracePeriod is the default value for the connection managers +// grace period +const DefaultConnMgrGracePeriod = time.Second * 20 + // DefaultDatastoreConfig is an internal function exported to aid in testing. func DefaultDatastoreConfig() Datastore { return Datastore{ From 516673de698969acf25a0e6df8fc9d5f3b22309b Mon Sep 17 00:00:00 2001 From: Jeromy Date: Tue, 24 Oct 2017 07:14:01 -0700 Subject: [PATCH 121/414] go-ipfs-config: extract go-ipfs-addr License: MIT Signed-off-by: Jeromy --- config/bootstrap_peers.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/config/bootstrap_peers.go b/config/bootstrap_peers.go index 2b166ff1985..9b3946e3667 100644 --- a/config/bootstrap_peers.go +++ b/config/bootstrap_peers.go @@ -4,7 +4,7 @@ import ( "errors" "fmt" - iaddr "github.com/ipfs/go-ipfs/thirdparty/ipfsaddr" + iaddr "gx/ipfs/QmeS8cCKawUwejVrsBtmC1toTXmwVWZGiRJqzgTURVWeF9/go-ipfs-addr" ) // DefaultBootstrapAddresses are the hardcoded bootstrap addresses From a93e2514df941a7bf97a048b78674709ca5407c6 Mon Sep 17 00:00:00 2001 From: Jan Winkelmann Date: Sat, 1 Apr 2017 16:58:17 +0200 Subject: [PATCH 122/414] go-ipfs-config: cmd: use go-ipfs-cmds License: MIT Signed-off-by: keks --- config/identity.go | 1 + 1 file changed, 1 insertion(+) diff --git a/config/identity.go b/config/identity.go index 077383c9346..c440cc427aa 100644 --- a/config/identity.go +++ b/config/identity.go @@ -2,6 +2,7 @@ package config import ( "encoding/base64" + ic "gx/ipfs/QmaPbCnUMBohSGo3KnxEa2bHqyJVVeEEcwtqJAYxerieBo/go-libp2p-crypto" ) From 8662bbb33056b2bd4f3718b391f4cc641d6bd7ad Mon Sep 17 00:00:00 2001 From: Steven Allen Date: Mon, 20 Nov 2017 16:25:06 -0800 Subject: [PATCH 123/414] go-ipfs-config: gx: massive update Note: This commit is technically broken. However, I need to make a bunch of cmds changes to make this work and I'd rather not bundle both changes into a single commit. License: MIT Signed-off-by: Steven Allen --- config/bootstrap_peers.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/config/bootstrap_peers.go b/config/bootstrap_peers.go index 9b3946e3667..b45bfcaeebe 100644 --- a/config/bootstrap_peers.go +++ b/config/bootstrap_peers.go @@ -4,7 +4,7 @@ import ( "errors" "fmt" - iaddr "gx/ipfs/QmeS8cCKawUwejVrsBtmC1toTXmwVWZGiRJqzgTURVWeF9/go-ipfs-addr" + iaddr "gx/ipfs/QmUnAfDeH1Nths56yuMvkw4V3sNF4d1xBbWy5hfZG7LF6G/go-ipfs-addr" ) // DefaultBootstrapAddresses are the hardcoded bootstrap addresses From 85b87f7a04cc700a9298d4f7667c1be6144e0ed4 Mon Sep 17 00:00:00 2001 From: Steven Allen Date: Sun, 3 Dec 2017 21:34:29 -0800 Subject: [PATCH 124/414] go-ipfs-config: gx: update go-multihash License: MIT Signed-off-by: Steven Allen --- config/bootstrap_peers.go | 2 +- config/init.go | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/config/bootstrap_peers.go b/config/bootstrap_peers.go index b45bfcaeebe..d4f6469dc14 100644 --- a/config/bootstrap_peers.go +++ b/config/bootstrap_peers.go @@ -4,7 +4,7 @@ import ( "errors" "fmt" - iaddr "gx/ipfs/QmUnAfDeH1Nths56yuMvkw4V3sNF4d1xBbWy5hfZG7LF6G/go-ipfs-addr" + iaddr "gx/ipfs/QmdMeXVB1V1SAZcFzoCuM3zR9K8PeuzCYg4zXNHcHh6dHU/go-ipfs-addr" ) // DefaultBootstrapAddresses are the hardcoded bootstrap addresses diff --git a/config/init.go b/config/init.go index 0b3537d2561..1c7874e3d90 100644 --- a/config/init.go +++ b/config/init.go @@ -7,7 +7,7 @@ import ( "io" "time" - peer "gx/ipfs/QmXYjuNuxVzXKJCfWasQk1RqkhVLDM9jtUKhqc2WPQmFSB/go-libp2p-peer" + peer "gx/ipfs/QmWNY7dV54ZDYmTA1ykVdwNCqC11mpU4zSUp6XDpLTH9eG/go-libp2p-peer" ci "gx/ipfs/QmaPbCnUMBohSGo3KnxEa2bHqyJVVeEEcwtqJAYxerieBo/go-libp2p-crypto" ) From 3de82a7c54fb9c21f4c053408e96e5d7dc81c5af Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C5=81ukasz=20Magiera?= Date: Tue, 5 Sep 2017 23:44:37 +0200 Subject: [PATCH 125/414] go-ipfs-config: config: revert profile subcommand MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit License: MIT Signed-off-by: Łukasz Magiera --- config/init.go | 26 ++++++---- config/profile.go | 126 ++++++++++++++++++++++++++++------------------ 2 files changed, 92 insertions(+), 60 deletions(-) diff --git a/config/init.go b/config/init.go index 1c7874e3d90..2b1def8b522 100644 --- a/config/init.go +++ b/config/init.go @@ -28,17 +28,7 @@ func Init(out io.Writer, nBitsForKeypair int) (*Config, error) { // setup the node's default addresses. // NOTE: two swarm listen addrs, one tcp, one utp. - Addresses: Addresses{ - Swarm: []string{ - "/ip4/0.0.0.0/tcp/4001", - // "/ip4/0.0.0.0/udp/4002/utp", // disabled for now. - "/ip6/::/tcp/4001", - }, - Announce: []string{}, - NoAnnounce: []string{}, - API: "/ip4/127.0.0.1/tcp/5001", - Gateway: "/ip4/127.0.0.1/tcp/8080", - }, + Addresses: addressesConfig(), Datastore: datastore, Bootstrap: BootstrapPeerStrings(bootstrapPeers), @@ -97,6 +87,20 @@ const DefaultConnMgrLowWater = 600 // grace period const DefaultConnMgrGracePeriod = time.Second * 20 +func addressesConfig() Addresses { + return Addresses{ + Swarm: []string{ + "/ip4/0.0.0.0/tcp/4001", + // "/ip4/0.0.0.0/udp/4002/utp", // disabled for now. + "/ip6/::/tcp/4001", + }, + Announce: []string{}, + NoAnnounce: []string{}, + API: "/ip4/127.0.0.1/tcp/5001", + Gateway: "/ip4/127.0.0.1/tcp/8080", + } +} + // DefaultDatastoreConfig is an internal function exported to aid in testing. func DefaultDatastoreConfig() Datastore { return Datastore{ diff --git a/config/profile.go b/config/profile.go index 3a7bf3694f3..a4160306a8b 100644 --- a/config/profile.go +++ b/config/profile.go @@ -1,56 +1,84 @@ package config -// ConfigProfiles is a map holding configuration transformers -var ConfigProfiles = map[string]func(*Config) error{ - "server": func(c *Config) error { - - // defaultServerFilters has a list of non-routable IPv4 prefixes - // according to http://www.iana.org/assignments/iana-ipv4-special-registry/iana-ipv4-special-registry.xhtml - defaultServerFilters := []string{ - "/ip4/10.0.0.0/ipcidr/8", - "/ip4/100.64.0.0/ipcidr/10", - "/ip4/169.254.0.0/ipcidr/16", - "/ip4/172.16.0.0/ipcidr/12", - "/ip4/192.0.0.0/ipcidr/24", - "/ip4/192.0.0.0/ipcidr/29", - "/ip4/192.0.0.8/ipcidr/32", - "/ip4/192.0.0.170/ipcidr/32", - "/ip4/192.0.0.171/ipcidr/32", - "/ip4/192.0.2.0/ipcidr/24", - "/ip4/192.168.0.0/ipcidr/16", - "/ip4/198.18.0.0/ipcidr/15", - "/ip4/198.51.100.0/ipcidr/24", - "/ip4/203.0.113.0/ipcidr/24", - "/ip4/240.0.0.0/ipcidr/4", - } - - c.Swarm.AddrFilters = append(c.Swarm.AddrFilters, defaultServerFilters...) - c.Discovery.MDNS.Enabled = false - return nil +type Transformer func(c *Config) error + +type Profile struct { + Apply Transformer + Unapply Transformer +} + +// Profiles is a map holding configuration transformers +var Profiles = map[string]*Profile{ + "server": { + Apply: func(c *Config) error { + + // defaultServerFilters has a list of non-routable IPv4 prefixes + // according to http://www.iana.org/assignments/iana-ipv4-special-registry/iana-ipv4-special-registry.xhtml + defaultServerFilters := []string{ + "/ip4/10.0.0.0/ipcidr/8", + "/ip4/100.64.0.0/ipcidr/10", + "/ip4/169.254.0.0/ipcidr/16", + "/ip4/172.16.0.0/ipcidr/12", + "/ip4/192.0.0.0/ipcidr/24", + "/ip4/192.0.0.0/ipcidr/29", + "/ip4/192.0.0.8/ipcidr/32", + "/ip4/192.0.0.170/ipcidr/32", + "/ip4/192.0.0.171/ipcidr/32", + "/ip4/192.0.2.0/ipcidr/24", + "/ip4/192.168.0.0/ipcidr/16", + "/ip4/198.18.0.0/ipcidr/15", + "/ip4/198.51.100.0/ipcidr/24", + "/ip4/203.0.113.0/ipcidr/24", + "/ip4/240.0.0.0/ipcidr/4", + } + + c.Swarm.AddrFilters = append(c.Swarm.AddrFilters, defaultServerFilters...) + c.Discovery.MDNS.Enabled = false + return nil + }, + Unapply: func(c *Config) error { + c.Swarm.AddrFilters = []string{} + c.Discovery.MDNS.Enabled = true + return nil + }, }, - "test": func(c *Config) error { - c.Addresses.API = "/ip4/127.0.0.1/tcp/0" - c.Addresses.Gateway = "/ip4/127.0.0.1/tcp/0" - - c.Swarm.DisableNatPortMap = true - c.Addresses.Swarm = []string{ - "/ip4/127.0.0.1/tcp/0", - } - - c.Bootstrap = []string{} - c.Discovery.MDNS.Enabled = false - return nil + "test": { + Apply: func(c *Config) error { + c.Addresses.API = "/ip4/127.0.0.1/tcp/0" + c.Addresses.Gateway = "/ip4/127.0.0.1/tcp/0" + c.Addresses.Swarm = []string{ + "/ip4/127.0.0.1/tcp/0", + } + + c.Swarm.DisableNatPortMap = true + + c.Bootstrap = []string{} + c.Discovery.MDNS.Enabled = false + return nil + }, + Unapply: func(c *Config) error { + c.Addresses = addressesConfig() + + c.Swarm.DisableNatPortMap = false + return nil + }, }, - "badgerds": func(c *Config) error { - c.Datastore.Spec = map[string]interface{}{ - "type": "measure", - "prefix": "badger.datastore", - "child": map[string]interface{}{ - "type": "badgerds", - "path": "badgerds", - "syncWrites": true, + "badgerds": { + Apply: func(c *Config) error { + c.Datastore.Spec = map[string]interface{}{ + "type": "measure", + "prefix": "badger.datastore", + "child": map[string]interface{}{ + "type": "badgerds", + "path": "badgerds", + "syncWrites": true, + }, + } + return nil }, - } - return nil + Unapply: func(c *Config) error { + c.Datastore.Spec = DefaultDatastoreConfig().Spec + return nil + }, }, } From cb7bc06600af76356c2d75a2b7e60e7216b07253 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C5=81ukasz=20Magiera?= Date: Wed, 6 Sep 2017 13:54:45 +0200 Subject: [PATCH 126/414] go-ipfs-config: config: profile tests, docs MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit License: MIT Signed-off-by: Łukasz Magiera --- config/profile.go | 24 ++++++++++++------------ 1 file changed, 12 insertions(+), 12 deletions(-) diff --git a/config/profile.go b/config/profile.go index a4160306a8b..7711d9e7c4f 100644 --- a/config/profile.go +++ b/config/profile.go @@ -7,7 +7,7 @@ type Profile struct { Unapply Transformer } -// Profiles is a map holding configuration transformers +// Profiles is a map holding configuration transformers. Docs are in docs/config.md var Profiles = map[string]*Profile{ "server": { Apply: func(c *Config) error { @@ -65,17 +65,17 @@ var Profiles = map[string]*Profile{ }, "badgerds": { Apply: func(c *Config) error { - c.Datastore.Spec = map[string]interface{}{ - "type": "measure", - "prefix": "badger.datastore", - "child": map[string]interface{}{ - "type": "badgerds", - "path": "badgerds", - "syncWrites": true, - }, - } - return nil - }, + c.Datastore.Spec = map[string]interface{}{ + "type": "measure", + "prefix": "badger.datastore", + "child": map[string]interface{}{ + "type": "badgerds", + "path": "badgerds", + "syncWrites": true, + }, + } + return nil + }, Unapply: func(c *Config) error { c.Datastore.Spec = DefaultDatastoreConfig().Spec return nil From 151c8dcf4e4a7c9b3f31fd79ad550e5feb4970f5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C5=81ukasz=20Magiera?= Date: Fri, 22 Sep 2017 00:13:58 +0200 Subject: [PATCH 127/414] go-ipfs-config: conifg-patch: apply review MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit License: MIT Signed-off-by: Łukasz Magiera --- config/profile.go | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/config/profile.go b/config/profile.go index 7711d9e7c4f..92fdbbc8e71 100644 --- a/config/profile.go +++ b/config/profile.go @@ -1,7 +1,9 @@ package config +// Transformer is a function which takes configuration and applies some filter to it type Transformer func(c *Config) error +// Profile applies some set of changes to the configuration type Profile struct { Apply Transformer Unapply Transformer @@ -32,11 +34,13 @@ var Profiles = map[string]*Profile{ "/ip4/240.0.0.0/ipcidr/4", } + c.Addresses.NoAnnounce = append(c.Addresses.NoAnnounce, defaultServerFilters...) c.Swarm.AddrFilters = append(c.Swarm.AddrFilters, defaultServerFilters...) c.Discovery.MDNS.Enabled = false return nil }, Unapply: func(c *Config) error { + c.Addresses.NoAnnounce = []string{} c.Swarm.AddrFilters = []string{} c.Discovery.MDNS.Enabled = true return nil From c2a74652fac692d1c9fd5d9071fc61439d2aa0d5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C5=81ukasz=20Magiera?= Date: Sun, 5 Nov 2017 14:21:14 +0100 Subject: [PATCH 128/414] go-ipfs-config: config: rename profile.Unapply to Revert MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit License: MIT Signed-off-by: Łukasz Magiera --- config/profile.go | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/config/profile.go b/config/profile.go index 92fdbbc8e71..061a41408eb 100644 --- a/config/profile.go +++ b/config/profile.go @@ -5,8 +5,8 @@ type Transformer func(c *Config) error // Profile applies some set of changes to the configuration type Profile struct { - Apply Transformer - Unapply Transformer + Apply Transformer + Revert Transformer } // Profiles is a map holding configuration transformers. Docs are in docs/config.md @@ -39,7 +39,7 @@ var Profiles = map[string]*Profile{ c.Discovery.MDNS.Enabled = false return nil }, - Unapply: func(c *Config) error { + Revert: func(c *Config) error { c.Addresses.NoAnnounce = []string{} c.Swarm.AddrFilters = []string{} c.Discovery.MDNS.Enabled = true @@ -60,7 +60,7 @@ var Profiles = map[string]*Profile{ c.Discovery.MDNS.Enabled = false return nil }, - Unapply: func(c *Config) error { + Revert: func(c *Config) error { c.Addresses = addressesConfig() c.Swarm.DisableNatPortMap = false @@ -80,7 +80,7 @@ var Profiles = map[string]*Profile{ } return nil }, - Unapply: func(c *Config) error { + Revert: func(c *Config) error { c.Datastore.Spec = DefaultDatastoreConfig().Spec return nil }, From 2423a8fb03d5c06ca7b11303bf8ee5029b5a22a7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C5=81ukasz=20Magiera?= Date: Sat, 25 Nov 2017 03:16:30 +0100 Subject: [PATCH 129/414] go-ipfs-config: config-patch: apply review suggestions MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit License: MIT Signed-off-by: Łukasz Magiera --- config/profile.go | 1 + 1 file changed, 1 insertion(+) diff --git a/config/profile.go b/config/profile.go index 061a41408eb..529cf3a97d3 100644 --- a/config/profile.go +++ b/config/profile.go @@ -64,6 +64,7 @@ var Profiles = map[string]*Profile{ c.Addresses = addressesConfig() c.Swarm.DisableNatPortMap = false + c.Discovery.MDNS.Enabled = true return nil }, }, From 4c300c521e19017c95951a7a30c1907a3fa37366 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C5=81ukasz=20Magiera?= Date: Sat, 16 Dec 2017 18:16:43 +0100 Subject: [PATCH 130/414] go-ipfs-config: config-patch: docs typo, fix server profile MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit License: MIT Signed-off-by: Łukasz Magiera --- config/profile.go | 79 ++++++++++++++++++++++++++++++++--------------- 1 file changed, 54 insertions(+), 25 deletions(-) diff --git a/config/profile.go b/config/profile.go index 529cf3a97d3..87668357f66 100644 --- a/config/profile.go +++ b/config/profile.go @@ -9,39 +9,38 @@ type Profile struct { Revert Transformer } +// defaultServerFilters has a list of non-routable IPv4 prefixes +// according to http://www.iana.org/assignments/iana-ipv4-special-registry/iana-ipv4-special-registry.xhtml +var defaultServerFilters = []string{ + "/ip4/10.0.0.0/ipcidr/8", + "/ip4/100.64.0.0/ipcidr/10", + "/ip4/169.254.0.0/ipcidr/16", + "/ip4/172.16.0.0/ipcidr/12", + "/ip4/192.0.0.0/ipcidr/24", + "/ip4/192.0.0.0/ipcidr/29", + "/ip4/192.0.0.8/ipcidr/32", + "/ip4/192.0.0.170/ipcidr/32", + "/ip4/192.0.0.171/ipcidr/32", + "/ip4/192.0.2.0/ipcidr/24", + "/ip4/192.168.0.0/ipcidr/16", + "/ip4/198.18.0.0/ipcidr/15", + "/ip4/198.51.100.0/ipcidr/24", + "/ip4/203.0.113.0/ipcidr/24", + "/ip4/240.0.0.0/ipcidr/4", +} + // Profiles is a map holding configuration transformers. Docs are in docs/config.md var Profiles = map[string]*Profile{ "server": { Apply: func(c *Config) error { - - // defaultServerFilters has a list of non-routable IPv4 prefixes - // according to http://www.iana.org/assignments/iana-ipv4-special-registry/iana-ipv4-special-registry.xhtml - defaultServerFilters := []string{ - "/ip4/10.0.0.0/ipcidr/8", - "/ip4/100.64.0.0/ipcidr/10", - "/ip4/169.254.0.0/ipcidr/16", - "/ip4/172.16.0.0/ipcidr/12", - "/ip4/192.0.0.0/ipcidr/24", - "/ip4/192.0.0.0/ipcidr/29", - "/ip4/192.0.0.8/ipcidr/32", - "/ip4/192.0.0.170/ipcidr/32", - "/ip4/192.0.0.171/ipcidr/32", - "/ip4/192.0.2.0/ipcidr/24", - "/ip4/192.168.0.0/ipcidr/16", - "/ip4/198.18.0.0/ipcidr/15", - "/ip4/198.51.100.0/ipcidr/24", - "/ip4/203.0.113.0/ipcidr/24", - "/ip4/240.0.0.0/ipcidr/4", - } - - c.Addresses.NoAnnounce = append(c.Addresses.NoAnnounce, defaultServerFilters...) - c.Swarm.AddrFilters = append(c.Swarm.AddrFilters, defaultServerFilters...) + c.Addresses.NoAnnounce = appendSingle(c.Addresses.NoAnnounce, defaultServerFilters) + c.Swarm.AddrFilters = appendSingle(c.Swarm.AddrFilters, defaultServerFilters) c.Discovery.MDNS.Enabled = false return nil }, Revert: func(c *Config) error { - c.Addresses.NoAnnounce = []string{} - c.Swarm.AddrFilters = []string{} + c.Addresses.NoAnnounce = deleteEntries(c.Addresses.NoAnnounce, defaultServerFilters) + c.Swarm.AddrFilters = deleteEntries(c.Swarm.AddrFilters, defaultServerFilters) c.Discovery.MDNS.Enabled = true return nil }, @@ -87,3 +86,33 @@ var Profiles = map[string]*Profile{ }, }, } + +func appendSingle(a []string, b []string) []string { + m := map[string]struct{}{} + for _, f := range a { + m[f] = struct{}{} + } + for _, f := range b { + m[f] = struct{}{} + } + return mapKeys(m) +} + +func deleteEntries(arr []string, del []string) []string { + m := map[string]struct{}{} + for _, f := range arr { + m[f] = struct{}{} + } + for _, f := range del { + delete(m, f) + } + return mapKeys(m) +} + +func mapKeys(m map[string]struct{}) []string { + out := make([]string, 0, len(m)) + for f := range m { + out = append(out, f) + } + return out +} From cdb9c2f316ecdb21bc0483e9eab7c564a4424cd8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C5=81ukasz=20Magiera?= Date: Sat, 16 Dec 2017 18:59:46 +0100 Subject: [PATCH 131/414] go-ipfs-config: config-patch: Inverse profiles MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit License: MIT Signed-off-by: Łukasz Magiera --- config/profile.go | 98 +++++++++++++++++++++-------------------------- 1 file changed, 43 insertions(+), 55 deletions(-) diff --git a/config/profile.go b/config/profile.go index 87668357f66..74383cda63f 100644 --- a/config/profile.go +++ b/config/profile.go @@ -3,12 +3,6 @@ package config // Transformer is a function which takes configuration and applies some filter to it type Transformer func(c *Config) error -// Profile applies some set of changes to the configuration -type Profile struct { - Apply Transformer - Revert Transformer -} - // defaultServerFilters has a list of non-routable IPv4 prefixes // according to http://www.iana.org/assignments/iana-ipv4-special-registry/iana-ipv4-special-registry.xhtml var defaultServerFilters = []string{ @@ -30,60 +24,54 @@ var defaultServerFilters = []string{ } // Profiles is a map holding configuration transformers. Docs are in docs/config.md -var Profiles = map[string]*Profile{ - "server": { - Apply: func(c *Config) error { - c.Addresses.NoAnnounce = appendSingle(c.Addresses.NoAnnounce, defaultServerFilters) - c.Swarm.AddrFilters = appendSingle(c.Swarm.AddrFilters, defaultServerFilters) - c.Discovery.MDNS.Enabled = false - return nil - }, - Revert: func(c *Config) error { - c.Addresses.NoAnnounce = deleteEntries(c.Addresses.NoAnnounce, defaultServerFilters) - c.Swarm.AddrFilters = deleteEntries(c.Swarm.AddrFilters, defaultServerFilters) - c.Discovery.MDNS.Enabled = true - return nil - }, +var Profiles = map[string]Transformer{ + "server": func(c *Config) error { + c.Addresses.NoAnnounce = appendSingle(c.Addresses.NoAnnounce, defaultServerFilters) + c.Swarm.AddrFilters = appendSingle(c.Swarm.AddrFilters, defaultServerFilters) + c.Discovery.MDNS.Enabled = false + return nil + }, + "local-discovery": func(c *Config) error { + c.Addresses.NoAnnounce = deleteEntries(c.Addresses.NoAnnounce, defaultServerFilters) + c.Swarm.AddrFilters = deleteEntries(c.Swarm.AddrFilters, defaultServerFilters) + c.Discovery.MDNS.Enabled = true + return nil }, - "test": { - Apply: func(c *Config) error { - c.Addresses.API = "/ip4/127.0.0.1/tcp/0" - c.Addresses.Gateway = "/ip4/127.0.0.1/tcp/0" - c.Addresses.Swarm = []string{ - "/ip4/127.0.0.1/tcp/0", - } + "test": func(c *Config) error { + c.Addresses.API = "/ip4/127.0.0.1/tcp/0" + c.Addresses.Gateway = "/ip4/127.0.0.1/tcp/0" + c.Addresses.Swarm = []string{ + "/ip4/127.0.0.1/tcp/0", + } - c.Swarm.DisableNatPortMap = true + c.Swarm.DisableNatPortMap = true - c.Bootstrap = []string{} - c.Discovery.MDNS.Enabled = false - return nil - }, - Revert: func(c *Config) error { - c.Addresses = addressesConfig() + c.Bootstrap = []string{} + c.Discovery.MDNS.Enabled = false + return nil + }, + "default-networking": func(c *Config) error { + c.Addresses = addressesConfig() - c.Swarm.DisableNatPortMap = false - c.Discovery.MDNS.Enabled = true - return nil - }, + c.Swarm.DisableNatPortMap = false + c.Discovery.MDNS.Enabled = true + return nil + }, + "badgerds": func(c *Config) error { + c.Datastore.Spec = map[string]interface{}{ + "type": "measure", + "prefix": "badger.datastore", + "child": map[string]interface{}{ + "type": "badgerds", + "path": "badgerds", + "syncWrites": true, + }, + } + return nil }, - "badgerds": { - Apply: func(c *Config) error { - c.Datastore.Spec = map[string]interface{}{ - "type": "measure", - "prefix": "badger.datastore", - "child": map[string]interface{}{ - "type": "badgerds", - "path": "badgerds", - "syncWrites": true, - }, - } - return nil - }, - Revert: func(c *Config) error { - c.Datastore.Spec = DefaultDatastoreConfig().Spec - return nil - }, + "default-datastore": func(c *Config) error { + c.Datastore.Spec = DefaultDatastoreConfig().Spec + return nil }, } From 60e814bc830aa40bfe0d9e5b3ccb513bdcbe9e9a Mon Sep 17 00:00:00 2001 From: keks Date: Thu, 7 Dec 2017 19:33:25 +0100 Subject: [PATCH 132/414] go-ipfs-config: cmds: use Executors - some fixes for cmds1.0 - reinsert plugin loading code, pretty print wrapper TODO: if plugin loading fails it only calls log.Warning. returning an error would be better but that would have to happen after PreRun, which is not possible atm. License: MIT Signed-off-by: keks --- config/init.go | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/config/init.go b/config/init.go index 2b1def8b522..a3ceee6d388 100644 --- a/config/init.go +++ b/config/init.go @@ -25,6 +25,11 @@ func Init(out io.Writer, nBitsForKeypair int) (*Config, error) { datastore := DefaultDatastoreConfig() conf := &Config{ + API: API{ + HTTPHeaders: map[string][]string{ + "Server": {"go-ipfs/" + CurrentVersionNumber}, + }, + }, // setup the node's default addresses. // NOTE: two swarm listen addrs, one tcp, one utp. From f1e0a382ca1d728eb851d372cbe943edb24979c2 Mon Sep 17 00:00:00 2001 From: Steven Allen Date: Wed, 24 Jan 2018 15:55:28 -0800 Subject: [PATCH 133/414] go-ipfs-config: gx: mass update License: MIT Signed-off-by: Steven Allen --- config/bootstrap_peers.go | 2 +- config/init.go | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/config/bootstrap_peers.go b/config/bootstrap_peers.go index d4f6469dc14..f59a3f65528 100644 --- a/config/bootstrap_peers.go +++ b/config/bootstrap_peers.go @@ -4,7 +4,7 @@ import ( "errors" "fmt" - iaddr "gx/ipfs/QmdMeXVB1V1SAZcFzoCuM3zR9K8PeuzCYg4zXNHcHh6dHU/go-ipfs-addr" + iaddr "gx/ipfs/QmWto9a6kfznUoW9owbLoBiLUMgRvgsVHRKFzs8zzzKYwp/go-ipfs-addr" ) // DefaultBootstrapAddresses are the hardcoded bootstrap addresses diff --git a/config/init.go b/config/init.go index a3ceee6d388..afcdbfec939 100644 --- a/config/init.go +++ b/config/init.go @@ -7,7 +7,7 @@ import ( "io" "time" - peer "gx/ipfs/QmWNY7dV54ZDYmTA1ykVdwNCqC11mpU4zSUp6XDpLTH9eG/go-libp2p-peer" + peer "gx/ipfs/Qma7H6RW8wRrfZpNSXwxYGcd1E149s42FpWNpDNieSVrnU/go-libp2p-peer" ci "gx/ipfs/QmaPbCnUMBohSGo3KnxEa2bHqyJVVeEEcwtqJAYxerieBo/go-libp2p-crypto" ) From e811add413517244f459310e32028a62288f70a3 Mon Sep 17 00:00:00 2001 From: Steven Allen Date: Sat, 27 Jan 2018 18:03:59 -0800 Subject: [PATCH 134/414] go-ipfs-config: update go-lib2p-loggables fixes a UUID bug I introduced (UUIDs were always an error value) License: MIT Signed-off-by: Steven Allen --- config/bootstrap_peers.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/config/bootstrap_peers.go b/config/bootstrap_peers.go index f59a3f65528..ee8b7419dfa 100644 --- a/config/bootstrap_peers.go +++ b/config/bootstrap_peers.go @@ -4,7 +4,7 @@ import ( "errors" "fmt" - iaddr "gx/ipfs/QmWto9a6kfznUoW9owbLoBiLUMgRvgsVHRKFzs8zzzKYwp/go-ipfs-addr" + iaddr "gx/ipfs/QmPWejECnZ4a2eShmnMFBfaLQR7AjuNDPxiY7jmR4fPjg6/go-ipfs-addr" ) // DefaultBootstrapAddresses are the hardcoded bootstrap addresses From ca129b458a21d2114e6a68ed37cfdd545b4bbb42 Mon Sep 17 00:00:00 2001 From: Steven Allen Date: Wed, 31 Jan 2018 18:54:57 -0800 Subject: [PATCH 135/414] go-ipfs-config: gx: update go-log License: MIT Signed-off-by: Steven Allen --- config/bootstrap_peers.go | 2 +- config/init.go | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/config/bootstrap_peers.go b/config/bootstrap_peers.go index ee8b7419dfa..23b5eefe3f2 100644 --- a/config/bootstrap_peers.go +++ b/config/bootstrap_peers.go @@ -4,7 +4,7 @@ import ( "errors" "fmt" - iaddr "gx/ipfs/QmPWejECnZ4a2eShmnMFBfaLQR7AjuNDPxiY7jmR4fPjg6/go-ipfs-addr" + iaddr "gx/ipfs/QmQViVWBHbU6HmYjXcdNq7tVASCNgdg64ZGcauuDkLCivW/go-ipfs-addr" ) // DefaultBootstrapAddresses are the hardcoded bootstrap addresses diff --git a/config/init.go b/config/init.go index afcdbfec939..26ac8e6ccf4 100644 --- a/config/init.go +++ b/config/init.go @@ -7,7 +7,7 @@ import ( "io" "time" - peer "gx/ipfs/Qma7H6RW8wRrfZpNSXwxYGcd1E149s42FpWNpDNieSVrnU/go-libp2p-peer" + peer "gx/ipfs/QmZoWKhxUmZ2seW4BzX6fJkNR8hh9PsGModr7q171yq2SS/go-libp2p-peer" ci "gx/ipfs/QmaPbCnUMBohSGo3KnxEa2bHqyJVVeEEcwtqJAYxerieBo/go-libp2p-crypto" ) From efb99b5e5910d84fc37c3631ec213c2de2765eb7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C5=81ukasz=20Magiera?= Date: Sun, 20 Aug 2017 16:24:01 +0200 Subject: [PATCH 136/414] go-ipfs-config: daemon: config option for routing MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit License: MIT Signed-off-by: Łukasz Magiera --- config/discovery.go | 5 ++++- config/init.go | 11 +++++++---- 2 files changed, 11 insertions(+), 5 deletions(-) diff --git a/config/discovery.go b/config/discovery.go index 4fb8508f00a..30c24ea19b3 100644 --- a/config/discovery.go +++ b/config/discovery.go @@ -1,7 +1,10 @@ package config type Discovery struct { - MDNS MDNS + MDNS MDNS + + //Routing sets default daemon routing mode. + Routing string } type MDNS struct { diff --git a/config/init.go b/config/init.go index 26ac8e6ccf4..e2d6a281f12 100644 --- a/config/init.go +++ b/config/init.go @@ -38,10 +38,13 @@ func Init(out io.Writer, nBitsForKeypair int) (*Config, error) { Datastore: datastore, Bootstrap: BootstrapPeerStrings(bootstrapPeers), Identity: identity, - Discovery: Discovery{MDNS{ - Enabled: true, - Interval: 10, - }}, + Discovery: Discovery{ + MDNS: MDNS{ + Enabled: true, + Interval: 10, + }, + Routing: "dht", + }, // setup the node mount points. Mounts: Mounts{ From 8d8b02b79715349cca4e9576b9d1bed90eaa8bb0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C5=81ukasz=20Magiera?= Date: Sun, 20 Aug 2017 17:57:00 +0200 Subject: [PATCH 137/414] go-ipfs-config: init: lowpower profile MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit License: MIT Signed-off-by: Łukasz Magiera --- config/discovery.go | 2 +- config/profile.go | 5 +++++ 2 files changed, 6 insertions(+), 1 deletion(-) diff --git a/config/discovery.go b/config/discovery.go index 30c24ea19b3..64f7af64a68 100644 --- a/config/discovery.go +++ b/config/discovery.go @@ -1,7 +1,7 @@ package config type Discovery struct { - MDNS MDNS + MDNS MDNS //Routing sets default daemon routing mode. Routing string diff --git a/config/profile.go b/config/profile.go index 74383cda63f..6aa5f505380 100644 --- a/config/profile.go +++ b/config/profile.go @@ -73,6 +73,11 @@ var Profiles = map[string]Transformer{ c.Datastore.Spec = DefaultDatastoreConfig().Spec return nil }, + "lowpower": func(c *Config) error { + c.Discovery.Routing = "dhtclient" + c.Reprovider.Interval = "0" + return nil + }, } func appendSingle(a []string, b []string) []string { From 88d7dfec2ffd3b33890872a2a5138a37d6b2e5f8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C5=81ukasz=20Magiera?= Date: Tue, 31 Oct 2017 19:34:38 +0100 Subject: [PATCH 138/414] go-ipfs-config: config: apply review to lowpower profile MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit License: MIT Signed-off-by: Łukasz Magiera --- config/config.go | 1 + config/discovery.go | 3 --- config/init.go | 5 ++++- config/profile.go | 8 +++++++- config/routing.go | 7 +++++++ 5 files changed, 19 insertions(+), 5 deletions(-) create mode 100644 config/routing.go diff --git a/config/config.go b/config/config.go index ac7c1152b77..719170baad8 100644 --- a/config/config.go +++ b/config/config.go @@ -19,6 +19,7 @@ type Config struct { Addresses Addresses // local node's addresses Mounts Mounts // local node's mount points Discovery Discovery // local node's discovery mechanisms + Routing Routing // local node's routing settings Ipns Ipns // Ipns settings Bootstrap []string // local nodes's bootstrap peer addresses Gateway Gateway // local node's gateway server options diff --git a/config/discovery.go b/config/discovery.go index 64f7af64a68..4fb8508f00a 100644 --- a/config/discovery.go +++ b/config/discovery.go @@ -2,9 +2,6 @@ package config type Discovery struct { MDNS MDNS - - //Routing sets default daemon routing mode. - Routing string } type MDNS struct { diff --git a/config/init.go b/config/init.go index e2d6a281f12..54d17f7b7bf 100644 --- a/config/init.go +++ b/config/init.go @@ -43,7 +43,10 @@ func Init(out io.Writer, nBitsForKeypair int) (*Config, error) { Enabled: true, Interval: 10, }, - Routing: "dht", + }, + + Routing: Routing{ + Type: "dht", }, // setup the node mount points. diff --git a/config/profile.go b/config/profile.go index 6aa5f505380..b20382ef4ed 100644 --- a/config/profile.go +++ b/config/profile.go @@ -1,5 +1,7 @@ package config +import "time" + // Transformer is a function which takes configuration and applies some filter to it type Transformer func(c *Config) error @@ -74,8 +76,12 @@ var Profiles = map[string]Transformer{ return nil }, "lowpower": func(c *Config) error { - c.Discovery.Routing = "dhtclient" + c.Routing.Type = "dhtclient" c.Reprovider.Interval = "0" + + c.Swarm.ConnMgr.LowWater = 20 + c.Swarm.ConnMgr.HighWater = 40 + c.Swarm.ConnMgr.GracePeriod = time.Minute.String() return nil }, } diff --git a/config/routing.go b/config/routing.go new file mode 100644 index 00000000000..e601cd5e8d3 --- /dev/null +++ b/config/routing.go @@ -0,0 +1,7 @@ +package config + +// Routing defines configuration options for libp2p routing +type Routing struct { + // Type sets default daemon routing mode. + Type string +} From 020c55ad623645589c75624ad7b45d2e0b4227ed Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C5=81ukasz=20Magiera?= Date: Tue, 20 Mar 2018 17:50:37 +0100 Subject: [PATCH 139/414] go-ipfs-config: Fix missing profile docs MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit License: MIT Signed-off-by: Łukasz Magiera --- config/profile.go | 157 +++++++++++++++++++++++++++++++--------------- 1 file changed, 107 insertions(+), 50 deletions(-) diff --git a/config/profile.go b/config/profile.go index b20382ef4ed..6d2d2b3a5c3 100644 --- a/config/profile.go +++ b/config/profile.go @@ -5,6 +5,15 @@ import "time" // Transformer is a function which takes configuration and applies some filter to it type Transformer func(c *Config) error +// Profile contains the profile transformer the description of the profile +type Profile struct { + // Description briefly describes the functionality of the profile + Description string + + // Transform takes ipfs configuration and applies the profile to it + Transform Transformer +} + // defaultServerFilters has a list of non-routable IPv4 prefixes // according to http://www.iana.org/assignments/iana-ipv4-special-registry/iana-ipv4-special-registry.xhtml var defaultServerFilters = []string{ @@ -26,63 +35,111 @@ var defaultServerFilters = []string{ } // Profiles is a map holding configuration transformers. Docs are in docs/config.md -var Profiles = map[string]Transformer{ - "server": func(c *Config) error { - c.Addresses.NoAnnounce = appendSingle(c.Addresses.NoAnnounce, defaultServerFilters) - c.Swarm.AddrFilters = appendSingle(c.Swarm.AddrFilters, defaultServerFilters) - c.Discovery.MDNS.Enabled = false - return nil +var Profiles = map[string]Profile{ + "server": { + Description: `Disables local host discovery, recommended when +running IPFS on machines with public IPv4 addresses.`, + + Transform: func(c *Config) error { + c.Addresses.NoAnnounce = appendSingle(c.Addresses.NoAnnounce, defaultServerFilters) + c.Swarm.AddrFilters = appendSingle(c.Swarm.AddrFilters, defaultServerFilters) + c.Discovery.MDNS.Enabled = false + return nil + }, }, - "local-discovery": func(c *Config) error { - c.Addresses.NoAnnounce = deleteEntries(c.Addresses.NoAnnounce, defaultServerFilters) - c.Swarm.AddrFilters = deleteEntries(c.Swarm.AddrFilters, defaultServerFilters) - c.Discovery.MDNS.Enabled = true - return nil + + "local-discovery": { + Description: `Sets default values to fields affected by the server +profile, enables discovery in local networks.`, + + Transform: func(c *Config) error { + c.Addresses.NoAnnounce = deleteEntries(c.Addresses.NoAnnounce, defaultServerFilters) + c.Swarm.AddrFilters = deleteEntries(c.Swarm.AddrFilters, defaultServerFilters) + c.Discovery.MDNS.Enabled = true + return nil + }, }, - "test": func(c *Config) error { - c.Addresses.API = "/ip4/127.0.0.1/tcp/0" - c.Addresses.Gateway = "/ip4/127.0.0.1/tcp/0" - c.Addresses.Swarm = []string{ - "/ip4/127.0.0.1/tcp/0", - } - - c.Swarm.DisableNatPortMap = true - - c.Bootstrap = []string{} - c.Discovery.MDNS.Enabled = false - return nil + "test": { + Description: `Reduces external interference of IPFS daemon, this +is useful when using the daemon in test environments.`, + + Transform: func(c *Config) error { + c.Addresses.API = "/ip4/127.0.0.1/tcp/0" + c.Addresses.Gateway = "/ip4/127.0.0.1/tcp/0" + c.Addresses.Swarm = []string{ + "/ip4/127.0.0.1/tcp/0", + } + + c.Swarm.DisableNatPortMap = true + + c.Bootstrap = []string{} + c.Discovery.MDNS.Enabled = false + return nil + }, }, - "default-networking": func(c *Config) error { - c.Addresses = addressesConfig() + "default-networking": { + Description: `Restores default network settings. +Inverse profile of the test profile.`, + + Transform: func(c *Config) error { + c.Addresses = addressesConfig() - c.Swarm.DisableNatPortMap = false - c.Discovery.MDNS.Enabled = true - return nil + c.Swarm.DisableNatPortMap = false + c.Discovery.MDNS.Enabled = true + return nil + }, }, - "badgerds": func(c *Config) error { - c.Datastore.Spec = map[string]interface{}{ - "type": "measure", - "prefix": "badger.datastore", - "child": map[string]interface{}{ - "type": "badgerds", - "path": "badgerds", - "syncWrites": true, - }, - } - return nil + "badgerds": { + Description: `Replaces default datastore configuration with experimental +badger datastore. + +If you apply this profile after ipfs init, you will need +to convert your datastore to the new configuration. +You can do this using ipfs-ds-convert. + +WARNING: badger datastore is experimental. +Make sure to backup your data frequently.`, + + Transform: func(c *Config) error { + c.Datastore.Spec = map[string]interface{}{ + "type": "measure", + "prefix": "badger.datastore", + "child": map[string]interface{}{ + "type": "badgerds", + "path": "badgerds", + "syncWrites": true, + }, + } + return nil + }, }, - "default-datastore": func(c *Config) error { - c.Datastore.Spec = DefaultDatastoreConfig().Spec - return nil + "default-datastore": { + Description: `Restores default datastore configuration. + +If you apply this profile after ipfs init, you will need +to convert your datastore to the new configuration. +You can do this using ipfs-ds-convert. +`, + + Transform: func(c *Config) error { + c.Datastore.Spec = DefaultDatastoreConfig().Spec + return nil + }, }, - "lowpower": func(c *Config) error { - c.Routing.Type = "dhtclient" - c.Reprovider.Interval = "0" - - c.Swarm.ConnMgr.LowWater = 20 - c.Swarm.ConnMgr.HighWater = 40 - c.Swarm.ConnMgr.GracePeriod = time.Minute.String() - return nil + "lowpower": { + Description: `Reduces daemon overhead on the system. May affect node +functionality - performance of content discovery and data +fetching may be degraded. +`, + Transform: func(c *Config) error { + c.Routing.Type = "dhtclient" + c.Reprovider.Interval = "0" + + c.Swarm.ConnMgr.LowWater = 20 + c.Swarm.ConnMgr.HighWater = 40 + c.Swarm.ConnMgr.GracePeriod = time.Minute.String() + return nil + }, }, } From 0c8a2e192f92395ebd44603b5b89b5bdc47ba22c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C5=81ukasz=20Magiera?= Date: Mon, 26 Mar 2018 19:32:15 +0200 Subject: [PATCH 140/414] go-ipfs-config: config/profile: disable UPnP/NAT in server profile, docs MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit License: MIT Signed-off-by: Łukasz Magiera --- config/profile.go | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/config/profile.go b/config/profile.go index 6d2d2b3a5c3..a7d4f1fe318 100644 --- a/config/profile.go +++ b/config/profile.go @@ -44,6 +44,7 @@ running IPFS on machines with public IPv4 addresses.`, c.Addresses.NoAnnounce = appendSingle(c.Addresses.NoAnnounce, defaultServerFilters) c.Swarm.AddrFilters = appendSingle(c.Swarm.AddrFilters, defaultServerFilters) c.Discovery.MDNS.Enabled = false + c.Swarm.DisableNatPortMap = true return nil }, }, @@ -56,6 +57,7 @@ profile, enables discovery in local networks.`, c.Addresses.NoAnnounce = deleteEntries(c.Addresses.NoAnnounce, defaultServerFilters) c.Swarm.AddrFilters = deleteEntries(c.Swarm.AddrFilters, defaultServerFilters) c.Discovery.MDNS.Enabled = true + c.Swarm.DisableNatPortMap = false return nil }, }, @@ -97,6 +99,11 @@ If you apply this profile after ipfs init, you will need to convert your datastore to the new configuration. You can do this using ipfs-ds-convert. +For more on ipfs-ds-convert see +$ ipfs-ds-convert --help +and +$ ipfs-ds-convert convert --help + WARNING: badger datastore is experimental. Make sure to backup your data frequently.`, @@ -119,6 +126,11 @@ Make sure to backup your data frequently.`, If you apply this profile after ipfs init, you will need to convert your datastore to the new configuration. You can do this using ipfs-ds-convert. + +For more on ipfs-ds-convert see +$ ipfs-ds-convert --help +and +$ ipfs-ds-convert convert --help `, Transform: func(c *Config) error { From af1fc17657d8bf9ce29cc7460d6643c4cc830842 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C5=81ukasz=20Magiera?= Date: Sun, 18 Mar 2018 19:54:46 +0100 Subject: [PATCH 141/414] go-ipfs-config: fix error style MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit License: MIT Signed-off-by: Łukasz Magiera --- config/config.go | 4 ++-- config/init.go | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/config/config.go b/config/config.go index 719170baad8..8ec6d324aeb 100644 --- a/config/config.go +++ b/config/config.go @@ -93,7 +93,7 @@ func FromMap(v map[string]interface{}) (*Config, error) { } var conf Config if err := json.NewDecoder(buf).Decode(&conf); err != nil { - return nil, fmt.Errorf("Failure to decode config: %s", err) + return nil, fmt.Errorf("failure to decode config: %s", err) } return &conf, nil } @@ -105,7 +105,7 @@ func ToMap(conf *Config) (map[string]interface{}, error) { } var m map[string]interface{} if err := json.NewDecoder(buf).Decode(&m); err != nil { - return nil, fmt.Errorf("Failure to decode config: %s", err) + return nil, fmt.Errorf("failure to decode config: %s", err) } return m, nil } diff --git a/config/init.go b/config/init.go index 54d17f7b7bf..6efc8712515 100644 --- a/config/init.go +++ b/config/init.go @@ -153,7 +153,7 @@ func identityConfig(out io.Writer, nbits int) (Identity, error) { // TODO guard higher up ident := Identity{} if nbits < 1024 { - return ident, errors.New("Bitsize less than 1024 is considered unsafe.") + return ident, errors.New("bitsize less than 1024 is considered unsafe") } fmt.Fprintf(out, "generating %v-bit RSA keypair...", nbits) From 97590c70cc3f8d96a42e733a72dcee6856a3ef99 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C5=81ukasz=20Magiera?= Date: Tue, 20 Mar 2018 16:56:56 +0100 Subject: [PATCH 142/414] go-ipfs-config: fix default-net profile not reverting bootstrap config MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit License: MIT Signed-off-by: Łukasz Magiera --- config/profile.go | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/config/profile.go b/config/profile.go index a7d4f1fe318..eab44cfb745 100644 --- a/config/profile.go +++ b/config/profile.go @@ -86,6 +86,12 @@ Inverse profile of the test profile.`, Transform: func(c *Config) error { c.Addresses = addressesConfig() + bootstrapPeers, err := DefaultBootstrapPeers() + if err != nil { + return err + } + c.Bootstrap = appendSingle(c.Bootstrap, BootstrapPeerStrings(bootstrapPeers)) + c.Swarm.DisableNatPortMap = false c.Discovery.MDNS.Enabled = true return nil From a55c0fb51d842c9f52c52c16d8450bb32319d779 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C5=81ukasz=20Magiera?= Date: Fri, 30 Mar 2018 20:38:52 +0200 Subject: [PATCH 143/414] go-ipfs-config: profile: fix test profile tests MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit License: MIT Signed-off-by: Łukasz Magiera --- config/profile.go | 15 +++++++++++---- 1 file changed, 11 insertions(+), 4 deletions(-) diff --git a/config/profile.go b/config/profile.go index eab44cfb745..d3f1b42d09c 100644 --- a/config/profile.go +++ b/config/profile.go @@ -162,14 +162,21 @@ fetching may be degraded. } func appendSingle(a []string, b []string) []string { - m := map[string]struct{}{} + out := make([]string, 0, len(a)+len(b)) + m := map[string]bool{} for _, f := range a { - m[f] = struct{}{} + if !m[f] { + out = append(out, f) + } + m[f] = true } for _, f := range b { - m[f] = struct{}{} + if !m[f] { + out = append(out, f) + } + m[f] = true } - return mapKeys(m) + return out } func deleteEntries(arr []string, del []string) []string { From c78cad770072739909e022aa49a8eabf02c0e0bd Mon Sep 17 00:00:00 2001 From: Steven Allen Date: Thu, 3 May 2018 21:39:52 -0700 Subject: [PATCH 144/414] go-ipfs-config: update deps License: MIT Signed-off-by: Steven Allen --- config/bootstrap_peers.go | 2 +- config/identity.go | 2 +- config/init.go | 4 ++-- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/config/bootstrap_peers.go b/config/bootstrap_peers.go index 23b5eefe3f2..8fa6f8bb648 100644 --- a/config/bootstrap_peers.go +++ b/config/bootstrap_peers.go @@ -4,7 +4,7 @@ import ( "errors" "fmt" - iaddr "gx/ipfs/QmQViVWBHbU6HmYjXcdNq7tVASCNgdg64ZGcauuDkLCivW/go-ipfs-addr" + iaddr "gx/ipfs/QmcHEQW4F7u74t1Qpgvz654rGoX6frjFm3HJA67YCV9jia/go-ipfs-addr" ) // DefaultBootstrapAddresses are the hardcoded bootstrap addresses diff --git a/config/identity.go b/config/identity.go index c440cc427aa..60fe772d911 100644 --- a/config/identity.go +++ b/config/identity.go @@ -3,7 +3,7 @@ package config import ( "encoding/base64" - ic "gx/ipfs/QmaPbCnUMBohSGo3KnxEa2bHqyJVVeEEcwtqJAYxerieBo/go-libp2p-crypto" + ic "gx/ipfs/Qme1knMqwt1hKZbc1BmQFmnm9f36nyQGwXxPGVpVJ9rMK5/go-libp2p-crypto" ) const IdentityTag = "Identity" diff --git a/config/init.go b/config/init.go index 6efc8712515..2f49b2bfdd2 100644 --- a/config/init.go +++ b/config/init.go @@ -7,8 +7,8 @@ import ( "io" "time" - peer "gx/ipfs/QmZoWKhxUmZ2seW4BzX6fJkNR8hh9PsGModr7q171yq2SS/go-libp2p-peer" - ci "gx/ipfs/QmaPbCnUMBohSGo3KnxEa2bHqyJVVeEEcwtqJAYxerieBo/go-libp2p-crypto" + peer "gx/ipfs/QmcJukH2sAFjY3HdBKq35WDzWoL3UUu2gt9wdfqZTUyM74/go-libp2p-peer" + ci "gx/ipfs/Qme1knMqwt1hKZbc1BmQFmnm9f36nyQGwXxPGVpVJ9rMK5/go-libp2p-crypto" ) func Init(out io.Writer, nBitsForKeypair int) (*Config, error) { From 5455b50a3daf39684538460d9f5820a4cb2a2d9f Mon Sep 17 00:00:00 2001 From: Steven Allen Date: Mon, 4 Jun 2018 09:53:40 -0700 Subject: [PATCH 145/414] go-ipfs-config: update multiplexers License: MIT Signed-off-by: Steven Allen --- config/bootstrap_peers.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/config/bootstrap_peers.go b/config/bootstrap_peers.go index 8fa6f8bb648..bf87fea2c8c 100644 --- a/config/bootstrap_peers.go +++ b/config/bootstrap_peers.go @@ -4,7 +4,7 @@ import ( "errors" "fmt" - iaddr "gx/ipfs/QmcHEQW4F7u74t1Qpgvz654rGoX6frjFm3HJA67YCV9jia/go-ipfs-addr" + iaddr "gx/ipfs/QmSMVXVvKFrWoxEixGxY28CUhtyaGTfXiM6m2A7mZUyVHe/go-ipfs-addr" ) // DefaultBootstrapAddresses are the hardcoded bootstrap addresses From e66b6dd87293e5d813e6b32a8291cd3a30325e83 Mon Sep 17 00:00:00 2001 From: Steven Allen Date: Tue, 5 Jun 2018 23:55:08 -0700 Subject: [PATCH 146/414] go-ipfs-config: update gx imports License: MIT Signed-off-by: Steven Allen --- config/bootstrap_peers.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/config/bootstrap_peers.go b/config/bootstrap_peers.go index bf87fea2c8c..176cdb10b48 100644 --- a/config/bootstrap_peers.go +++ b/config/bootstrap_peers.go @@ -4,7 +4,7 @@ import ( "errors" "fmt" - iaddr "gx/ipfs/QmSMVXVvKFrWoxEixGxY28CUhtyaGTfXiM6m2A7mZUyVHe/go-ipfs-addr" + iaddr "gx/ipfs/Qmey6omaMEzs9DiSQWwnPwTCJRn3RE8rWLjfidRrTzUq6t/go-ipfs-addr" ) // DefaultBootstrapAddresses are the hardcoded bootstrap addresses From 4a566363483e665f356677d52f61d38bc87dd25e Mon Sep 17 00:00:00 2001 From: Steven Allen Date: Fri, 8 Jun 2018 22:01:00 -0700 Subject: [PATCH 147/414] go-ipfs-config: gx update go-log, sys, go-crypto * go-log * sys * go-crypto License: MIT Signed-off-by: Steven Allen --- config/bootstrap_peers.go | 2 +- config/init.go | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/config/bootstrap_peers.go b/config/bootstrap_peers.go index 176cdb10b48..e66ad36bb7c 100644 --- a/config/bootstrap_peers.go +++ b/config/bootstrap_peers.go @@ -4,7 +4,7 @@ import ( "errors" "fmt" - iaddr "gx/ipfs/Qmey6omaMEzs9DiSQWwnPwTCJRn3RE8rWLjfidRrTzUq6t/go-ipfs-addr" + iaddr "gx/ipfs/QmckPUj15AbTcLh6MpDEsQpfVCx34tmP2Xg1aNwLb5fiRF/go-ipfs-addr" ) // DefaultBootstrapAddresses are the hardcoded bootstrap addresses diff --git a/config/init.go b/config/init.go index 2f49b2bfdd2..e16806c46f8 100644 --- a/config/init.go +++ b/config/init.go @@ -7,7 +7,7 @@ import ( "io" "time" - peer "gx/ipfs/QmcJukH2sAFjY3HdBKq35WDzWoL3UUu2gt9wdfqZTUyM74/go-libp2p-peer" + peer "gx/ipfs/QmVf8hTAsLLFtn4WPCRNdnaF2Eag2qTBS6uR8AiHPZARXy/go-libp2p-peer" ci "gx/ipfs/Qme1knMqwt1hKZbc1BmQFmnm9f36nyQGwXxPGVpVJ9rMK5/go-libp2p-crypto" ) From 019e7b27d917e19a4209054cfdae7a3529f67f27 Mon Sep 17 00:00:00 2001 From: Steven Allen Date: Tue, 12 Jun 2018 14:37:29 -0700 Subject: [PATCH 148/414] go-ipfs-config: make ipfs swarm connect /ipfs/QmId work fixes #5102 Also, allow specifying multiple addresses for a single peer. License: MIT Signed-off-by: Steven Allen --- config/bootstrap_peers.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/config/bootstrap_peers.go b/config/bootstrap_peers.go index e66ad36bb7c..74ca92e07cb 100644 --- a/config/bootstrap_peers.go +++ b/config/bootstrap_peers.go @@ -4,7 +4,7 @@ import ( "errors" "fmt" - iaddr "gx/ipfs/QmckPUj15AbTcLh6MpDEsQpfVCx34tmP2Xg1aNwLb5fiRF/go-ipfs-addr" + iaddr "gx/ipfs/QmaKviZCLQrpuyFdSjteik7kJFcQpcyZgb1VuuwaCBBaEa/go-ipfs-addr" ) // DefaultBootstrapAddresses are the hardcoded bootstrap addresses From 4b1900435f29e35df25c98f87042a9e348edcb4c Mon Sep 17 00:00:00 2001 From: Steven Allen Date: Thu, 21 Jun 2018 14:35:43 -0700 Subject: [PATCH 149/414] go-ipfs-config: explicitly import go-multiaddr-dns in config/bootstrap_peers We need it to parse the dnsaddr addresses. While we import it elsewhere, we should really be importing it every where we need it so that other users can import our packages directly. fixes #5143 License: MIT Signed-off-by: Steven Allen --- config/bootstrap_peers.go | 3 +++ 1 file changed, 3 insertions(+) diff --git a/config/bootstrap_peers.go b/config/bootstrap_peers.go index 74ca92e07cb..2c12a8b6588 100644 --- a/config/bootstrap_peers.go +++ b/config/bootstrap_peers.go @@ -5,6 +5,9 @@ import ( "fmt" iaddr "gx/ipfs/QmaKviZCLQrpuyFdSjteik7kJFcQpcyZgb1VuuwaCBBaEa/go-ipfs-addr" + // Needs to be imported so that users can import this package directly + // and still parse the bootstrap addresses. + _ "gx/ipfs/QmT8461vVVyBPyHJHQ6mvm8UdQ8UZNA5n6Z7kBk7GRf1xu/go-multiaddr-dns" ) // DefaultBootstrapAddresses are the hardcoded bootstrap addresses From 7fded300ef2abce8e6cbb2e328a5c2acde9f2d4e Mon Sep 17 00:00:00 2001 From: Steven Allen Date: Mon, 25 Jun 2018 20:41:25 -0700 Subject: [PATCH 150/414] go-ipfs-config: gx update Updates: * go-kad-dht: Query performance improvements, DHT client fixes, validates records on *local* put. * go-libp2p-swarm/go-libp2p-transport: Timeout improvements. * go-multiaddr-net: Exposes useful Conn methods (CloseWrite, CloseRead, etc.) * go-log: fixes possible panic when enabling/disabling events. * go-multiaddr: fixes possible panic when stringifying malformed multiaddrs, adds support for consuming /p2p/ multiaddrs. fixes #5113 unblocks #4895 License: MIT Signed-off-by: Steven Allen --- config/bootstrap_peers.go | 4 ++-- config/init.go | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/config/bootstrap_peers.go b/config/bootstrap_peers.go index 2c12a8b6588..bf5a4534562 100644 --- a/config/bootstrap_peers.go +++ b/config/bootstrap_peers.go @@ -4,10 +4,10 @@ import ( "errors" "fmt" - iaddr "gx/ipfs/QmaKviZCLQrpuyFdSjteik7kJFcQpcyZgb1VuuwaCBBaEa/go-ipfs-addr" + iaddr "gx/ipfs/QmWUtfQveCqT8cgNzN54at4sDMiFbANFRFCXuSDiTqJwC8/go-ipfs-addr" // Needs to be imported so that users can import this package directly // and still parse the bootstrap addresses. - _ "gx/ipfs/QmT8461vVVyBPyHJHQ6mvm8UdQ8UZNA5n6Z7kBk7GRf1xu/go-multiaddr-dns" + _ "gx/ipfs/QmfXU2MhWoegxHoeMd3A2ytL2P6CY4FfqGWc23LTNWBwZt/go-multiaddr-dns" ) // DefaultBootstrapAddresses are the hardcoded bootstrap addresses diff --git a/config/init.go b/config/init.go index e16806c46f8..218d3251b0c 100644 --- a/config/init.go +++ b/config/init.go @@ -7,7 +7,7 @@ import ( "io" "time" - peer "gx/ipfs/QmVf8hTAsLLFtn4WPCRNdnaF2Eag2qTBS6uR8AiHPZARXy/go-libp2p-peer" + peer "gx/ipfs/QmdVrMn1LhB4ybb8hMVaMLXnA8XRSewMnK6YqXKXoTcRvN/go-libp2p-peer" ci "gx/ipfs/Qme1knMqwt1hKZbc1BmQFmnm9f36nyQGwXxPGVpVJ9rMK5/go-libp2p-crypto" ) From ee071dbd6a09736844b19f322e70303bb792b3e9 Mon Sep 17 00:00:00 2001 From: Kevin Atkinson Date: Sat, 23 Jun 2018 17:03:57 -0400 Subject: [PATCH 151/414] go-ipfs-config: Add config option to enable urlstore. License: MIT Signed-off-by: Kevin Atkinson --- config/experiments.go | 1 + 1 file changed, 1 insertion(+) diff --git a/config/experiments.go b/config/experiments.go index f76572ee2af..ab48c868159 100644 --- a/config/experiments.go +++ b/config/experiments.go @@ -2,6 +2,7 @@ package config type Experiments struct { FilestoreEnabled bool + UrlstoreEnabled bool ShardingEnabled bool Libp2pStreamMounting bool } From 54e8e770fbb651e303cfc6d2c55fe66758d1644f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C5=81ukasz=20Magiera?= Date: Sun, 22 Jul 2018 21:31:49 +0200 Subject: [PATCH 152/414] go-ipfs-config: move serialize package to config MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit License: MIT Signed-off-by: Łukasz Magiera --- config/serialize/serialize.go | 71 ++++++++++++++++++++++++++++++ config/serialize/serialize_test.go | 37 ++++++++++++++++ 2 files changed, 108 insertions(+) create mode 100644 config/serialize/serialize.go create mode 100644 config/serialize/serialize_test.go diff --git a/config/serialize/serialize.go b/config/serialize/serialize.go new file mode 100644 index 00000000000..f1a48251320 --- /dev/null +++ b/config/serialize/serialize.go @@ -0,0 +1,71 @@ +package fsrepo + +import ( + "encoding/json" + "errors" + "fmt" + "io" + "os" + "path/filepath" + + "github.com/ipfs/go-ipfs/repo/config" + + "gx/ipfs/QmPdKqUcHGFdeSpvjVoaTRPPstGif9GBZb5Q56RVw9o69A/go-ipfs-util" + "gx/ipfs/QmdYwCmx8pZRkzdcd8MhmLJqYVoVTC1aGsy5Q4reMGLNLg/atomicfile" +) + +// ReadConfigFile reads the config from `filename` into `cfg`. +func ReadConfigFile(filename string, cfg interface{}) error { + f, err := os.Open(filename) + if err != nil { + return err + } + defer f.Close() + if err := json.NewDecoder(f).Decode(cfg); err != nil { + return fmt.Errorf("failure to decode config: %s", err) + } + return nil +} + +// WriteConfigFile writes the config from `cfg` into `filename`. +func WriteConfigFile(filename string, cfg interface{}) error { + err := os.MkdirAll(filepath.Dir(filename), 0775) + if err != nil { + return err + } + + f, err := atomicfile.New(filename, 0660) + if err != nil { + return err + } + defer f.Close() + + return encode(f, cfg) +} + +// encode configuration with JSON +func encode(w io.Writer, value interface{}) error { + // need to prettyprint, hence MarshalIndent, instead of Encoder + buf, err := config.Marshal(value) + if err != nil { + return err + } + _, err = w.Write(buf) + return err +} + +// Load reads given file and returns the read config, or error. +func Load(filename string) (*config.Config, error) { + // if nothing is there, fail. User must run 'ipfs init' + if !util.FileExists(filename) { + return nil, errors.New("ipfs not initialized, please run 'ipfs init'") + } + + var cfg config.Config + err := ReadConfigFile(filename, &cfg) + if err != nil { + return nil, err + } + + return &cfg, err +} diff --git a/config/serialize/serialize_test.go b/config/serialize/serialize_test.go new file mode 100644 index 00000000000..443024ed8f6 --- /dev/null +++ b/config/serialize/serialize_test.go @@ -0,0 +1,37 @@ +package fsrepo + +import ( + "os" + "runtime" + "testing" + + config "github.com/ipfs/go-ipfs/repo/config" +) + +func TestConfig(t *testing.T) { + const filename = ".ipfsconfig" + cfgWritten := new(config.Config) + cfgWritten.Identity.PeerID = "faketest" + + err := WriteConfigFile(filename, cfgWritten) + if err != nil { + t.Fatal(err) + } + cfgRead, err := Load(filename) + if err != nil { + t.Fatal(err) + } + if cfgWritten.Identity.PeerID != cfgRead.Identity.PeerID { + t.Fatal() + } + st, err := os.Stat(filename) + if err != nil { + t.Fatalf("cannot stat config file: %v", err) + } + + if runtime.GOOS != "windows" { // see https://golang.org/src/os/types_windows.go + if g := st.Mode().Perm(); g&0117 != 0 { + t.Fatalf("config file should not be executable or accessible to world: %v", g) + } + } +} From d67080f478b0dc7671addd0b52cda27ee6f83421 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C5=81ukasz=20Magiera?= Date: Mon, 23 Jul 2018 16:12:26 +0200 Subject: [PATCH 153/414] go-ipfs-config: Setup gx --- config/config.go | 2 +- config/serialize/serialize.go | 2 +- config/serialize/serialize_test.go | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/config/config.go b/config/config.go index 8ec6d324aeb..59c1c6c46b9 100644 --- a/config/config.go +++ b/config/config.go @@ -9,7 +9,7 @@ import ( "path/filepath" "strings" - "github.com/ipfs/go-ipfs/Godeps/_workspace/src/github.com/mitchellh/go-homedir" + "gx/ipfs/QmdcULN1WCzgoQmcCaUAmEhwcxHYsDrbZ2LvRJKCL8dMrK/go-homedir" ) // Config is used to load ipfs config files. diff --git a/config/serialize/serialize.go b/config/serialize/serialize.go index f1a48251320..366d167995b 100644 --- a/config/serialize/serialize.go +++ b/config/serialize/serialize.go @@ -8,7 +8,7 @@ import ( "os" "path/filepath" - "github.com/ipfs/go-ipfs/repo/config" + "github.com/ipfs/go-ipfs-config" "gx/ipfs/QmPdKqUcHGFdeSpvjVoaTRPPstGif9GBZb5Q56RVw9o69A/go-ipfs-util" "gx/ipfs/QmdYwCmx8pZRkzdcd8MhmLJqYVoVTC1aGsy5Q4reMGLNLg/atomicfile" diff --git a/config/serialize/serialize_test.go b/config/serialize/serialize_test.go index 443024ed8f6..e5abdb852f3 100644 --- a/config/serialize/serialize_test.go +++ b/config/serialize/serialize_test.go @@ -5,7 +5,7 @@ import ( "runtime" "testing" - config "github.com/ipfs/go-ipfs/repo/config" + config "github.com/ipfs/go-ipfs-config" ) func TestConfig(t *testing.T) { From 757f25d4b152aa72817b84a780ac606c499e5894 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C5=81ukasz=20Magiera?= Date: Mon, 23 Jul 2018 16:13:00 +0200 Subject: [PATCH 154/414] go-ipfs-config: gx-go uw --- config/bootstrap_peers.go | 4 ++-- config/config.go | 2 +- config/identity.go | 2 +- config/init.go | 4 ++-- config/serialize/serialize.go | 4 ++-- 5 files changed, 8 insertions(+), 8 deletions(-) diff --git a/config/bootstrap_peers.go b/config/bootstrap_peers.go index bf5a4534562..92fc580eabe 100644 --- a/config/bootstrap_peers.go +++ b/config/bootstrap_peers.go @@ -4,10 +4,10 @@ import ( "errors" "fmt" - iaddr "gx/ipfs/QmWUtfQveCqT8cgNzN54at4sDMiFbANFRFCXuSDiTqJwC8/go-ipfs-addr" + iaddr "github.com/ipfs/go-ipfs-addr" // Needs to be imported so that users can import this package directly // and still parse the bootstrap addresses. - _ "gx/ipfs/QmfXU2MhWoegxHoeMd3A2ytL2P6CY4FfqGWc23LTNWBwZt/go-multiaddr-dns" + _ "github.com/multiformats/go-multiaddr-dns" ) // DefaultBootstrapAddresses are the hardcoded bootstrap addresses diff --git a/config/config.go b/config/config.go index 59c1c6c46b9..c1eefea10b1 100644 --- a/config/config.go +++ b/config/config.go @@ -9,7 +9,7 @@ import ( "path/filepath" "strings" - "gx/ipfs/QmdcULN1WCzgoQmcCaUAmEhwcxHYsDrbZ2LvRJKCL8dMrK/go-homedir" + "github.com/mitchellh/go-homedir" ) // Config is used to load ipfs config files. diff --git a/config/identity.go b/config/identity.go index 60fe772d911..c09af56440f 100644 --- a/config/identity.go +++ b/config/identity.go @@ -3,7 +3,7 @@ package config import ( "encoding/base64" - ic "gx/ipfs/Qme1knMqwt1hKZbc1BmQFmnm9f36nyQGwXxPGVpVJ9rMK5/go-libp2p-crypto" + ic "github.com/libp2p/go-libp2p-crypto" ) const IdentityTag = "Identity" diff --git a/config/init.go b/config/init.go index 218d3251b0c..5f8ab8a43f6 100644 --- a/config/init.go +++ b/config/init.go @@ -7,8 +7,8 @@ import ( "io" "time" - peer "gx/ipfs/QmdVrMn1LhB4ybb8hMVaMLXnA8XRSewMnK6YqXKXoTcRvN/go-libp2p-peer" - ci "gx/ipfs/Qme1knMqwt1hKZbc1BmQFmnm9f36nyQGwXxPGVpVJ9rMK5/go-libp2p-crypto" + ci "github.com/libp2p/go-libp2p-crypto" + peer "github.com/libp2p/go-libp2p-peer" ) func Init(out io.Writer, nBitsForKeypair int) (*Config, error) { diff --git a/config/serialize/serialize.go b/config/serialize/serialize.go index 366d167995b..eedf7e1aa53 100644 --- a/config/serialize/serialize.go +++ b/config/serialize/serialize.go @@ -10,8 +10,8 @@ import ( "github.com/ipfs/go-ipfs-config" - "gx/ipfs/QmPdKqUcHGFdeSpvjVoaTRPPstGif9GBZb5Q56RVw9o69A/go-ipfs-util" - "gx/ipfs/QmdYwCmx8pZRkzdcd8MhmLJqYVoVTC1aGsy5Q4reMGLNLg/atomicfile" + "github.com/facebookgo/atomicfile" + "github.com/ipfs/go-ipfs-util" ) // ReadConfigFile reads the config from `filename` into `cfg`. From 512b4d3b156104fc32c3930b3736b4fe290b28fc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C5=81ukasz=20Magiera?= Date: Mon, 23 Jul 2018 19:04:48 +0200 Subject: [PATCH 155/414] go-ipfs-config: remove version.go --- config/init.go | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/config/init.go b/config/init.go index 5f8ab8a43f6..c4ea9e41bcd 100644 --- a/config/init.go +++ b/config/init.go @@ -26,9 +26,7 @@ func Init(out io.Writer, nBitsForKeypair int) (*Config, error) { conf := &Config{ API: API{ - HTTPHeaders: map[string][]string{ - "Server": {"go-ipfs/" + CurrentVersionNumber}, - }, + HTTPHeaders: map[string][]string{}, }, // setup the node's default addresses. From 212b72f236c6c6d0836a0eafacb774c17e67e52d Mon Sep 17 00:00:00 2001 From: vyzo Date: Sun, 12 Aug 2018 14:16:38 +0300 Subject: [PATCH 156/414] go-ipfs-config: add pubsub configuration --- config/config.go | 1 + config/pubsub.go | 5 +++++ 2 files changed, 6 insertions(+) create mode 100644 config/pubsub.go diff --git a/config/config.go b/config/config.go index c1eefea10b1..44b700f1141 100644 --- a/config/config.go +++ b/config/config.go @@ -25,6 +25,7 @@ type Config struct { Gateway Gateway // local node's gateway server options API API // local node's API settings Swarm SwarmConfig + Pubsub PubsubConfig Reprovider Reprovider Experimental Experiments diff --git a/config/pubsub.go b/config/pubsub.go new file mode 100644 index 00000000000..da25b0f24d1 --- /dev/null +++ b/config/pubsub.go @@ -0,0 +1,5 @@ +package config + +type PubsubConfig struct { + Router string +} From 32cf2a65d75139a91d6c028fe4bdfe42ac8b9ca8 Mon Sep 17 00:00:00 2001 From: Marten Seemann Date: Sun, 26 Aug 2018 10:42:03 +0700 Subject: [PATCH 157/414] go-ipfs-config: add QUIC experiment --- config/experiments.go | 1 + 1 file changed, 1 insertion(+) diff --git a/config/experiments.go b/config/experiments.go index ab48c868159..d6c3d99531c 100644 --- a/config/experiments.go +++ b/config/experiments.go @@ -5,4 +5,5 @@ type Experiments struct { UrlstoreEnabled bool ShardingEnabled bool Libp2pStreamMounting bool + QUIC bool } From 6a618df199319152a78fdf343f3bbb0d1720f201 Mon Sep 17 00:00:00 2001 From: Steven Allen Date: Sat, 15 Sep 2018 13:56:12 -0700 Subject: [PATCH 158/414] go-ipfs-config: allow multiple API/Gateway addresses Alternative to #6 that doesn't require a migration. --- config/addresses.go | 4 ++-- config/init.go | 4 ++-- config/profile.go | 4 ++-- config/types.go | 37 +++++++++++++++++++++++++++++++++++++ 4 files changed, 43 insertions(+), 6 deletions(-) create mode 100644 config/types.go diff --git a/config/addresses.go b/config/addresses.go index 22c530655b2..2d88468fdac 100644 --- a/config/addresses.go +++ b/config/addresses.go @@ -5,6 +5,6 @@ type Addresses struct { Swarm []string // addresses for the swarm to listen on Announce []string // swarm addresses to announce to the network NoAnnounce []string // swarm addresses not to announce to the network - API string // address for the local API (RPC) - Gateway string // address to listen on for IPFS HTTP object gateway + API Strings // address for the local API (RPC) + Gateway Strings // address to listen on for IPFS HTTP object gateway } diff --git a/config/init.go b/config/init.go index c4ea9e41bcd..f45bf56725b 100644 --- a/config/init.go +++ b/config/init.go @@ -105,8 +105,8 @@ func addressesConfig() Addresses { }, Announce: []string{}, NoAnnounce: []string{}, - API: "/ip4/127.0.0.1/tcp/5001", - Gateway: "/ip4/127.0.0.1/tcp/8080", + API: Strings{"/ip4/127.0.0.1/tcp/5001"}, + Gateway: Strings{"/ip4/127.0.0.1/tcp/8080"}, } } diff --git a/config/profile.go b/config/profile.go index d3f1b42d09c..d23cadc6d97 100644 --- a/config/profile.go +++ b/config/profile.go @@ -66,8 +66,8 @@ profile, enables discovery in local networks.`, is useful when using the daemon in test environments.`, Transform: func(c *Config) error { - c.Addresses.API = "/ip4/127.0.0.1/tcp/0" - c.Addresses.Gateway = "/ip4/127.0.0.1/tcp/0" + c.Addresses.API = Strings{"/ip4/127.0.0.1/tcp/0"} + c.Addresses.Gateway = Strings{"/ip4/127.0.0.1/tcp/0"} c.Addresses.Swarm = []string{ "/ip4/127.0.0.1/tcp/0", } diff --git a/config/types.go b/config/types.go new file mode 100644 index 00000000000..376cc64f072 --- /dev/null +++ b/config/types.go @@ -0,0 +1,37 @@ +package config + +import ( + "encoding/json" +) + +// Strings is a helper type that (un)marshals a single string to/from a single +// JSON string and a slice of strings to/from a JSON array of strings. +type Strings []string + +// UnmarshalJSON conforms to the json.Unmarshaler interface. +func (o *Strings) UnmarshalJSON(data []byte) error { + if data[0] == '[' { + return json.Unmarshal(data, (*[]string)(o)) + } + var value string + if err := json.Unmarshal(data, &value); err != nil { + return err + } + *o = []string{value} + return nil +} + +// MarshalJSON conforms to the json.Marshaler interface. +func (o Strings) MarshalJSON() ([]byte, error) { + switch len(o) { + case 0: + return json.Marshal(nil) + case 1: + return json.Marshal(o[0]) + default: + return json.Marshal([]string(o)) + } +} + +var _ json.Unmarshaler = (*Strings)(nil) +var _ json.Marshaler = (*Strings)(nil) From d7c1f55724a48c24372628096c0bf3300bb4f0fd Mon Sep 17 00:00:00 2001 From: Lars Gierth Date: Sat, 15 Sep 2018 21:22:38 +0200 Subject: [PATCH 159/414] go-ipfs-config: Add Gateway.APICommands for /api allowlists --- config/gateway.go | 1 + config/init.go | 1 + 2 files changed, 2 insertions(+) diff --git a/config/gateway.go b/config/gateway.go index a8ba7059071..7e64b566fb4 100644 --- a/config/gateway.go +++ b/config/gateway.go @@ -6,4 +6,5 @@ type Gateway struct { RootRedirect string Writable bool PathPrefixes []string + APICommands []string } diff --git a/config/init.go b/config/init.go index c4ea9e41bcd..22aa699b8e3 100644 --- a/config/init.go +++ b/config/init.go @@ -66,6 +66,7 @@ func Init(out io.Writer, nBitsForKeypair int) (*Config, error) { "Access-Control-Allow-Methods": []string{"GET"}, "Access-Control-Allow-Headers": []string{"X-Requested-With", "Range"}, }, + APICommands: []string{}, }, Reprovider: Reprovider{ Interval: "12h", From 6a3a087039664e3735aece67f887d32e0006d27e Mon Sep 17 00:00:00 2001 From: Lars Gierth Date: Wed, 3 Oct 2018 08:04:32 +0200 Subject: [PATCH 160/414] go-ipfs-config: Fix handling of null strings --- config/types.go | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/config/types.go b/config/types.go index 376cc64f072..58451c68f12 100644 --- a/config/types.go +++ b/config/types.go @@ -17,7 +17,11 @@ func (o *Strings) UnmarshalJSON(data []byte) error { if err := json.Unmarshal(data, &value); err != nil { return err } - *o = []string{value} + if len(value) == 0 { + *o = []string{} + } else { + *o = []string{value} + } return nil } From 43a6230e1409a68dd7a3f874cef7e1e16288dea0 Mon Sep 17 00:00:00 2001 From: Dr Ian Preston Date: Thu, 4 Oct 2018 23:42:48 +0100 Subject: [PATCH 161/414] go-ipfs-config: add experiment for p2p http proxy License: MIT Signed-off-by: Ian Preston --- config/experiments.go | 1 + 1 file changed, 1 insertion(+) diff --git a/config/experiments.go b/config/experiments.go index d6c3d99531c..828953360e6 100644 --- a/config/experiments.go +++ b/config/experiments.go @@ -5,5 +5,6 @@ type Experiments struct { UrlstoreEnabled bool ShardingEnabled bool Libp2pStreamMounting bool + P2pHttpProxy bool QUIC bool } From 1ca5f8e640203f2d1ea7aff2222dfcb6cc43c228 Mon Sep 17 00:00:00 2001 From: Ivan Date: Sun, 14 Oct 2018 21:32:55 +0200 Subject: [PATCH 162/414] go-ipfs-config: Allow the use of the User-Agent header License: MIT Signed-off-by: Ivan --- config/init.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/config/init.go b/config/init.go index a6e70b71184..f45a596737f 100644 --- a/config/init.go +++ b/config/init.go @@ -64,7 +64,7 @@ func Init(out io.Writer, nBitsForKeypair int) (*Config, error) { HTTPHeaders: map[string][]string{ "Access-Control-Allow-Origin": []string{"*"}, "Access-Control-Allow-Methods": []string{"GET"}, - "Access-Control-Allow-Headers": []string{"X-Requested-With", "Range"}, + "Access-Control-Allow-Headers": []string{"X-Requested-With", "Range", "User-Agent"}, }, APICommands: []string{}, }, From 7cecbb9dce8b6db19d0c976248f1f0d2d6ca85f5 Mon Sep 17 00:00:00 2001 From: Steven Allen Date: Thu, 25 Oct 2018 10:15:54 -0700 Subject: [PATCH 163/414] go-ipfs-config: add pubsub message signing options to config --- config/pubsub.go | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/config/pubsub.go b/config/pubsub.go index da25b0f24d1..94e03e28b82 100644 --- a/config/pubsub.go +++ b/config/pubsub.go @@ -1,5 +1,18 @@ package config type PubsubConfig struct { + // Router can be either floodsub (legacy) or gossipsub (new and + // backwards compatible). Router string + + // DisableSigning disables message signing. Message signing is *enabled* + // by default. + DisableSigning bool + + // StrictSignatureVerification enables strict signature verification. + // When enabled, unsigned messages will be rejected. Eventually, this + // will be made the default and this option will disappear. Once this + // happens, networks will either need to completely disable or + // completely enable message signing. + StrictSignatureVerification bool } From 77a3e94a6330a964aa27f8269d50ae1ee39aa613 Mon Sep 17 00:00:00 2001 From: Lucas Molas Date: Mon, 29 Oct 2018 11:03:54 -0300 Subject: [PATCH 164/414] go-ipfs-config: profile: add badger truncate option --- config/profile.go | 1 + 1 file changed, 1 insertion(+) diff --git a/config/profile.go b/config/profile.go index d23cadc6d97..38f3f861d58 100644 --- a/config/profile.go +++ b/config/profile.go @@ -121,6 +121,7 @@ Make sure to backup your data frequently.`, "type": "badgerds", "path": "badgerds", "syncWrites": true, + "truncate": true, }, } return nil From b83ea099ff15ff9952d0f078302025838bfa926d Mon Sep 17 00:00:00 2001 From: tarekbadr Date: Sat, 3 Nov 2018 15:41:49 +0200 Subject: [PATCH 165/414] go-ipfs-config: change randomports Description --- config/profile.go | 31 ++++++++++++++++++++++++++++++- 1 file changed, 30 insertions(+), 1 deletion(-) diff --git a/config/profile.go b/config/profile.go index d23cadc6d97..ee568b4033f 100644 --- a/config/profile.go +++ b/config/profile.go @@ -1,6 +1,10 @@ package config -import "time" +import ( + "fmt" + "net" + "time" +) // Transformer is a function which takes configuration and applies some filter to it type Transformer func(c *Config) error @@ -159,6 +163,31 @@ fetching may be degraded. return nil }, }, + "randomports": { + Description: `Use a random port number for swarm.`, + + Transform: func(c *Config) error { + port, err := getAvailablePort() + if err != nil { + return err + } + c.Addresses.Swarm = []string{ + fmt.Sprintf("/ip4/0.0.0.0/tcp/%d", port), + fmt.Sprintf("/ip6/::/tcp/%d", port), + } + return nil + }, + }, +} + +func getAvailablePort() (port int, err error) { + ln, err := net.Listen("tcp", "[::]:0") + if err != nil { + return 0, err + } + defer ln.Close() + port = ln.Addr().(*net.TCPAddr).Port + return port, nil } func appendSingle(a []string, b []string) []string { From bf2923e47b37089c85c20ab339ab84083e8f59df Mon Sep 17 00:00:00 2001 From: vyzo Date: Tue, 20 Nov 2018 12:53:47 +0200 Subject: [PATCH 166/414] go-ipfs-config: autorelay options --- config/swarm.go | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/config/swarm.go b/config/swarm.go index 5b128f38aab..16dc54d9cba 100644 --- a/config/swarm.go +++ b/config/swarm.go @@ -7,6 +7,12 @@ type SwarmConfig struct { DisableRelay bool EnableRelayHop bool + // autorelay functionality + // if true, then the libp2p host will be constructed with autorelay functionality. + EnableAutoRelay bool + // if true, then an AutoNATService will be instantiated to facilitate autorelay + EnableAutoNATService bool + ConnMgr ConnMgr } From b627585f2826938f964cbb5a44b5f710d08bdeee Mon Sep 17 00:00:00 2001 From: Steven Allen Date: Tue, 23 Oct 2018 09:47:51 -0700 Subject: [PATCH 167/414] go-ipfs-config: add a Clone function The user must call this before modifying the config. Given that the config contains slices/maps modifications can modified *shared* state, even after dereferencing. --- config/config.go | 16 ++++++++++++++++ config/config_test.go | 23 +++++++++++++++++++++++ 2 files changed, 39 insertions(+) create mode 100644 config/config_test.go diff --git a/config/config.go b/config/config.go index 44b700f1141..dc987547951 100644 --- a/config/config.go +++ b/config/config.go @@ -110,3 +110,19 @@ func ToMap(conf *Config) (map[string]interface{}, error) { } return m, nil } + +// Clone copies the config. Use when updating. +func (c *Config) Clone() (*Config, error) { + var newConfig Config + var buf bytes.Buffer + + if err := json.NewEncoder(&buf).Encode(c); err != nil { + return nil, fmt.Errorf("failure to encode config: %s", err) + } + + if err := json.NewDecoder(&buf).Decode(&newConfig); err != nil { + return nil, fmt.Errorf("failure to decode config: %s", err) + } + + return &newConfig, nil +} diff --git a/config/config_test.go b/config/config_test.go new file mode 100644 index 00000000000..9c82bb2ff1a --- /dev/null +++ b/config/config_test.go @@ -0,0 +1,23 @@ +package config + +import ( + "testing" +) + +func TestClone(t *testing.T) { + c := new(Config) + c.Identity.PeerID = "faketest" + c.API.HTTPHeaders = map[string][]string{"foo": []string{"bar"}} + + newCfg, err := c.Clone() + if err != nil { + t.Fatal(err) + } + if newCfg.Identity.PeerID != c.Identity.PeerID { + t.Fatal("peer ID not preserved") + } + delete(c.API.HTTPHeaders, "foo") + if newCfg.API.HTTPHeaders["foo"][0] != "bar" { + t.Fatal("HTTP headers not preserved") + } +} From 3cd45d889ab0326cbafd6b36c17aa9d81991cea7 Mon Sep 17 00:00:00 2001 From: Steven Allen Date: Tue, 23 Oct 2018 09:49:35 -0700 Subject: [PATCH 168/414] go-ipfs-config: add tests for the "Strings" type (missed in my previous PR) --- config/types_test.go | 53 ++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 53 insertions(+) create mode 100644 config/types_test.go diff --git a/config/types_test.go b/config/types_test.go new file mode 100644 index 00000000000..7523962ae83 --- /dev/null +++ b/config/types_test.go @@ -0,0 +1,53 @@ +package config + +import ( + "encoding/json" + "testing" +) + +func TestOneStrings(t *testing.T) { + out, err := json.Marshal(Strings{"one"}) + if err != nil { + t.Fatal(err) + + } + expected := "\"one\"" + if string(out) != expected { + t.Fatalf("expected %s, got %s", expected, string(out)) + } +} + +func TestNoStrings(t *testing.T) { + out, err := json.Marshal(Strings{}) + if err != nil { + t.Fatal(err) + + } + expected := "null" + if string(out) != expected { + t.Fatalf("expected %s, got %s", expected, string(out)) + } +} + +func TestManyStrings(t *testing.T) { + out, err := json.Marshal(Strings{"one", "two"}) + if err != nil { + t.Fatal(err) + + } + expected := "[\"one\",\"two\"]" + if string(out) != expected { + t.Fatalf("expected %s, got %s", expected, string(out)) + } +} + +func TestFunkyStrings(t *testing.T) { + toParse := " [ \"one\", \"two\" ] " + var s Strings + if err := json.Unmarshal([]byte(toParse), &s); err != nil { + t.Fatal(err) + } + if len(s) != 2 || s[0] != "one" && s[1] != "two" { + t.Fatalf("unexpected result: %v", s) + } +} From e4282bdb7ab3f69d892b1d4e0798b3823e181555 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C5=81ukasz=20Magiera?= Date: Tue, 6 Nov 2018 15:39:53 +0100 Subject: [PATCH 169/414] go-ipfs-config: Add one more test for config.Clone --- config/config_test.go | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/config/config_test.go b/config/config_test.go index 9c82bb2ff1a..dead06f8a23 100644 --- a/config/config_test.go +++ b/config/config_test.go @@ -7,7 +7,7 @@ import ( func TestClone(t *testing.T) { c := new(Config) c.Identity.PeerID = "faketest" - c.API.HTTPHeaders = map[string][]string{"foo": []string{"bar"}} + c.API.HTTPHeaders = map[string][]string{"foo": {"bar"}} newCfg, err := c.Clone() if err != nil { @@ -16,6 +16,12 @@ func TestClone(t *testing.T) { if newCfg.Identity.PeerID != c.Identity.PeerID { t.Fatal("peer ID not preserved") } + + c.API.HTTPHeaders["foo"] = []string{"baz"} + if newCfg.API.HTTPHeaders["foo"][0] != "bar" { + t.Fatal("HTTP headers not preserved") + } + delete(c.API.HTTPHeaders, "foo") if newCfg.API.HTTPHeaders["foo"][0] != "bar" { t.Fatal("HTTP headers not preserved") From bc31fd957c8d9db529f69e20f39954d0b0971570 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C5=81ukasz=20Magiera?= Date: Fri, 26 Oct 2018 01:55:25 +0200 Subject: [PATCH 170/414] go-ipfs-config: Add Gateway.NoFetch --- config/gateway.go | 1 + config/init.go | 1 + 2 files changed, 2 insertions(+) diff --git a/config/gateway.go b/config/gateway.go index 7e64b566fb4..017be9b285b 100644 --- a/config/gateway.go +++ b/config/gateway.go @@ -7,4 +7,5 @@ type Gateway struct { Writable bool PathPrefixes []string APICommands []string + NoFetch bool } diff --git a/config/init.go b/config/init.go index f45a596737f..0697cc4c928 100644 --- a/config/init.go +++ b/config/init.go @@ -60,6 +60,7 @@ func Init(out io.Writer, nBitsForKeypair int) (*Config, error) { Gateway: Gateway{ RootRedirect: "", Writable: false, + NoFetch: false, PathPrefixes: []string{}, HTTPHeaders: map[string][]string{ "Access-Control-Allow-Origin": []string{"*"}, From 3475f8350a253eb09f99aeff5ff2f65ab5052865 Mon Sep 17 00:00:00 2001 From: Marten Seemann Date: Thu, 18 Apr 2019 09:11:09 +0900 Subject: [PATCH 171/414] go-ipfs-config: add an experiment to prefer TLS over secio --- config/experiments.go | 1 + 1 file changed, 1 insertion(+) diff --git a/config/experiments.go b/config/experiments.go index 828953360e6..c5cb0cf2fbd 100644 --- a/config/experiments.go +++ b/config/experiments.go @@ -7,4 +7,5 @@ type Experiments struct { Libp2pStreamMounting bool P2pHttpProxy bool QUIC bool + PreferTLS bool } From c920b46f46ae71e284778762d34df2151cfcbc86 Mon Sep 17 00:00:00 2001 From: Teran McKinney Date: Wed, 1 May 2019 17:21:56 +0000 Subject: [PATCH 172/414] go-ipfs-config: Closes: #6284 Add appropriate IPv6 ranges to defaultServerFilters --- config/profile.go | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/config/profile.go b/config/profile.go index f293202eac5..458f6a82214 100644 --- a/config/profile.go +++ b/config/profile.go @@ -18,8 +18,9 @@ type Profile struct { Transform Transformer } -// defaultServerFilters has a list of non-routable IPv4 prefixes -// according to http://www.iana.org/assignments/iana-ipv4-special-registry/iana-ipv4-special-registry.xhtml +// defaultServerFilters has is a list of IPv4 and IPv6 prefixes that are private, local only, or unrouteable. +// according to https://www.iana.org/assignments/iana-ipv4-special-registry/iana-ipv4-special-registry.xhtml +// and https://www.iana.org/assignments/iana-ipv6-special-registry/iana-ipv6-special-registry.xhtml var defaultServerFilters = []string{ "/ip4/10.0.0.0/ipcidr/8", "/ip4/100.64.0.0/ipcidr/10", @@ -36,6 +37,11 @@ var defaultServerFilters = []string{ "/ip4/198.51.100.0/ipcidr/24", "/ip4/203.0.113.0/ipcidr/24", "/ip4/240.0.0.0/ipcidr/4", + "/ip6/100::/ipcidr/64", + "/ip6/2001:2::/ipcidr/48", + "/ip6/2001:db8::/ipcidr/32", + "/ip6/fc00::/ipcidr/7", + "/ip6/fe80::/ipcidr/10", } // Profiles is a map holding configuration transformers. Docs are in docs/config.md From b2029f15c7a8cc618da4ebf709cc3b2f21b95ce7 Mon Sep 17 00:00:00 2001 From: Michael Avila Date: Thu, 18 Apr 2019 13:54:58 -0700 Subject: [PATCH 173/414] go-ipfs-config: Add provider system experiment --- config/experiments.go | 1 + 1 file changed, 1 insertion(+) diff --git a/config/experiments.go b/config/experiments.go index c5cb0cf2fbd..6821ed6bc81 100644 --- a/config/experiments.go +++ b/config/experiments.go @@ -8,4 +8,5 @@ type Experiments struct { P2pHttpProxy bool QUIC bool PreferTLS bool + StrategicProviding bool } From e76a8cf714d93cf5c1dd3561d82225fa0aa6db7c Mon Sep 17 00:00:00 2001 From: Steven Allen Date: Fri, 31 May 2019 12:54:12 -0700 Subject: [PATCH 174/414] go-ipfs-config: migrate to the consolidated libp2p BREAKING: this also removes the dependency on go-ipfs-addr so we can deprecate that package. This only appears to affect go-ipfs itself. --- config/bootstrap_peers.go | 36 +++++++++++++++--------------------- config/identity.go | 2 +- config/init.go | 4 ++-- 3 files changed, 18 insertions(+), 24 deletions(-) diff --git a/config/bootstrap_peers.go b/config/bootstrap_peers.go index 92fc580eabe..9141c8bee89 100644 --- a/config/bootstrap_peers.go +++ b/config/bootstrap_peers.go @@ -4,7 +4,9 @@ import ( "errors" "fmt" - iaddr "github.com/ipfs/go-ipfs-addr" + peer "github.com/libp2p/go-libp2p-core/peer" + ma "github.com/multiformats/go-multiaddr" + // Needs to be imported so that users can import this package directly // and still parse the bootstrap addresses. _ "github.com/multiformats/go-multiaddr-dns" @@ -32,20 +34,17 @@ var DefaultBootstrapAddresses = []string{ "/ip6/2a03:b0c0:0:1010::23:1001/tcp/4001/ipfs/QmSoLer265NRgSp2LA3dPaeykiS1J6DifTC88f5uVQKNAd", // earth.i.ipfs.io } -// BootstrapPeer is a peer used to bootstrap the network. -type BootstrapPeer iaddr.IPFSAddr - // ErrInvalidPeerAddr signals an address is not a valid peer address. var ErrInvalidPeerAddr = errors.New("invalid peer address") -func (c *Config) BootstrapPeers() ([]BootstrapPeer, error) { +func (c *Config) BootstrapPeers() ([]peer.AddrInfo, error) { return ParseBootstrapPeers(c.Bootstrap) } // DefaultBootstrapPeers returns the (parsed) set of default bootstrap peers. // if it fails, it returns a meaningful error for the user. // This is here (and not inside cmd/ipfs/init) because of module dependency problems. -func DefaultBootstrapPeers() ([]BootstrapPeer, error) { +func DefaultBootstrapPeers() ([]peer.AddrInfo, error) { ps, err := ParseBootstrapPeers(DefaultBootstrapAddresses) if err != nil { return nil, fmt.Errorf(`failed to parse hardcoded bootstrap peers: %s @@ -54,31 +53,26 @@ This is a problem with the ipfs codebase. Please report it to the dev team.`, er return ps, nil } -func (c *Config) SetBootstrapPeers(bps []BootstrapPeer) { +func (c *Config) SetBootstrapPeers(bps []peer.AddrInfo) { c.Bootstrap = BootstrapPeerStrings(bps) } -func ParseBootstrapPeer(addr string) (BootstrapPeer, error) { - ia, err := iaddr.ParseString(addr) - if err != nil { - return nil, err - } - return BootstrapPeer(ia), err -} - -func ParseBootstrapPeers(addrs []string) ([]BootstrapPeer, error) { - peers := make([]BootstrapPeer, len(addrs)) - var err error +// ParseBootstrapPeer parses a bootstrap list into a list of AddrInfos. +func ParseBootstrapPeers(addrs []string) ([]peer.AddrInfo, error) { + maddrs := make([]ma.Multiaddr, len(addrs)) for i, addr := range addrs { - peers[i], err = ParseBootstrapPeer(addr) + var err error + maddrs[i], err = ma.NewMultiaddr(addr) if err != nil { return nil, err } } - return peers, nil + return peer.AddrInfosFromP2pAddrs(maddrs...) } -func BootstrapPeerStrings(bps []BootstrapPeer) []string { +// BootstrapPeerStrings formats a list of AddrInfos as a bootstrap peer list +// suitable for serialization. +func BootstrapPeerStrings(bps []peer.AddrInfo) []string { bpss := make([]string, len(bps)) for i, p := range bps { bpss[i] = p.String() diff --git a/config/identity.go b/config/identity.go index c09af56440f..f4e7c87200d 100644 --- a/config/identity.go +++ b/config/identity.go @@ -3,7 +3,7 @@ package config import ( "encoding/base64" - ic "github.com/libp2p/go-libp2p-crypto" + ic "github.com/libp2p/go-libp2p-core/crypto" ) const IdentityTag = "Identity" diff --git a/config/init.go b/config/init.go index 0697cc4c928..7f11c3a3d06 100644 --- a/config/init.go +++ b/config/init.go @@ -7,8 +7,8 @@ import ( "io" "time" - ci "github.com/libp2p/go-libp2p-crypto" - peer "github.com/libp2p/go-libp2p-peer" + ci "github.com/libp2p/go-libp2p-core/crypto" + peer "github.com/libp2p/go-libp2p-core/peer" ) func Init(out io.Writer, nBitsForKeypair int) (*Config, error) { From e9c30cf35647e317588dec94c9cdc7a8b19ca7d1 Mon Sep 17 00:00:00 2001 From: Steven Allen Date: Sat, 1 Jun 2019 09:00:12 -0700 Subject: [PATCH 175/414] go-ipfs-config: fix string formatting of bootstrap peers --- config/bootstrap_peers.go | 13 ++++++++++--- config/bootstrap_peers_test.go | 24 ++++++++++++++++++++++++ 2 files changed, 34 insertions(+), 3 deletions(-) create mode 100644 config/bootstrap_peers_test.go diff --git a/config/bootstrap_peers.go b/config/bootstrap_peers.go index 9141c8bee89..f4a13dc9d06 100644 --- a/config/bootstrap_peers.go +++ b/config/bootstrap_peers.go @@ -73,9 +73,16 @@ func ParseBootstrapPeers(addrs []string) ([]peer.AddrInfo, error) { // BootstrapPeerStrings formats a list of AddrInfos as a bootstrap peer list // suitable for serialization. func BootstrapPeerStrings(bps []peer.AddrInfo) []string { - bpss := make([]string, len(bps)) - for i, p := range bps { - bpss[i] = p.String() + bpss := make([]string, 0, len(bps)) + for _, pi := range bps { + addrs, err := peer.AddrInfoToP2pAddrs(&pi) + if err != nil { + // programmer error. + panic(err) + } + for _, addr := range addrs { + bpss = append(bpss, addr.String()) + } } return bpss } diff --git a/config/bootstrap_peers_test.go b/config/bootstrap_peers_test.go new file mode 100644 index 00000000000..eeea9b5fdc0 --- /dev/null +++ b/config/bootstrap_peers_test.go @@ -0,0 +1,24 @@ +package config + +import ( + "sort" + "testing" +) + +func TestBoostrapPeerStrings(t *testing.T) { + parsed, err := ParseBootstrapPeers(DefaultBootstrapAddresses) + if err != nil { + t.Fatal(err) + } + + formatted := BootstrapPeerStrings(parsed) + sort.Strings(formatted) + expected := append([]string{}, DefaultBootstrapAddresses...) + sort.Strings(expected) + + for i, s := range formatted { + if expected[i] != s { + t.Fatalf("expected %s, %s", expected[i], s) + } + } +} From f61d052ce10a04119867d18b5959deb385f5656f Mon Sep 17 00:00:00 2001 From: Michael Avila Date: Thu, 27 Jun 2019 12:20:44 -0700 Subject: [PATCH 176/414] go-ipfs-config: Add very basic (possibly temporary) Provider configs --- config/config.go | 1 + config/provider.go | 5 +++++ 2 files changed, 6 insertions(+) create mode 100644 config/provider.go diff --git a/config/config.go b/config/config.go index dc987547951..3a5d3fe2060 100644 --- a/config/config.go +++ b/config/config.go @@ -27,6 +27,7 @@ type Config struct { Swarm SwarmConfig Pubsub PubsubConfig + Provider Provider Reprovider Reprovider Experimental Experiments } diff --git a/config/provider.go b/config/provider.go new file mode 100644 index 00000000000..f2b5afe05b4 --- /dev/null +++ b/config/provider.go @@ -0,0 +1,5 @@ +package config + +type Provider struct { + Strategy string // Which keys to announce +} From 86abf1fc5758f08e30244c30c9826d338200a545 Mon Sep 17 00:00:00 2001 From: Michael Avila Date: Thu, 27 Jun 2019 12:52:23 -0700 Subject: [PATCH 177/414] go-ipfs-config: Fix bad go fmt --- config/config.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/config/config.go b/config/config.go index 3a5d3fe2060..ba12fa645c8 100644 --- a/config/config.go +++ b/config/config.go @@ -27,7 +27,7 @@ type Config struct { Swarm SwarmConfig Pubsub PubsubConfig - Provider Provider + Provider Provider Reprovider Reprovider Experimental Experiments } From a7ff340af6b0663589de0a1237f53bf61b14fac8 Mon Sep 17 00:00:00 2001 From: Steven Allen Date: Thu, 29 Aug 2019 10:15:25 -0700 Subject: [PATCH 178/414] go-ipfs-config: chore: bump minimum key size to 2048 --- config/init.go | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/config/init.go b/config/init.go index 7f11c3a3d06..d658866ef62 100644 --- a/config/init.go +++ b/config/init.go @@ -152,8 +152,8 @@ func DefaultDatastoreConfig() Datastore { func identityConfig(out io.Writer, nbits int) (Identity, error) { // TODO guard higher up ident := Identity{} - if nbits < 1024 { - return ident, errors.New("bitsize less than 1024 is considered unsafe") + if nbits < 2048 { + return ident, errors.New("bitsize less than 2048 is considered unsafe") } fmt.Fprintf(out, "generating %v-bit RSA keypair...", nbits) From a04a858922618fcb0164c5c13f4564aca4de88b0 Mon Sep 17 00:00:00 2001 From: Steven Allen Date: Thu, 29 Aug 2019 10:15:31 -0700 Subject: [PATCH 179/414] go-ipfs-config: add plugins config section * Allow users to store plugin specific config options. * Allow users to disable specific plugins. Eventually, we can use this to allow loading plugins from non-standard locations. --- config/config.go | 1 + config/plugins.go | 11 +++++++++++ 2 files changed, 12 insertions(+) create mode 100644 config/plugins.go diff --git a/config/config.go b/config/config.go index ba12fa645c8..3f140474566 100644 --- a/config/config.go +++ b/config/config.go @@ -30,6 +30,7 @@ type Config struct { Provider Provider Reprovider Reprovider Experimental Experiments + Plugins Plugins } const ( diff --git a/config/plugins.go b/config/plugins.go new file mode 100644 index 00000000000..004f5468f74 --- /dev/null +++ b/config/plugins.go @@ -0,0 +1,11 @@ +package config + +type Plugins struct { + Plugins map[string]Plugin `json:",omitempty"` + // TODO: Loader Path? Leaving that out for now due to security concerns. +} + +type Plugin struct { + Disabled bool + Config interface{} +} From 25e3e1974b849b2410cb1f5b2a24ad17f682d252 Mon Sep 17 00:00:00 2001 From: Steven Allen Date: Thu, 29 Aug 2019 10:25:35 -0700 Subject: [PATCH 180/414] go-ipfs-config: nit: omit empty plugin values Let's try to slim down default configs a bit. --- config/plugins.go | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/config/plugins.go b/config/plugins.go index 004f5468f74..c9b148049a1 100644 --- a/config/plugins.go +++ b/config/plugins.go @@ -6,6 +6,6 @@ type Plugins struct { } type Plugin struct { - Disabled bool - Config interface{} + Disabled bool `json:",omitempty"` + Config interface{} `json:",omitempty"` } From 40bc2372f975792227f48a6ac2dc06f56470555c Mon Sep 17 00:00:00 2001 From: Steven Allen Date: Thu, 29 Aug 2019 11:48:53 -0700 Subject: [PATCH 181/414] go-ipfs-config: make it easier to detect an uninitialized repo --- config/serialize/serialize.go | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/config/serialize/serialize.go b/config/serialize/serialize.go index eedf7e1aa53..af11774b409 100644 --- a/config/serialize/serialize.go +++ b/config/serialize/serialize.go @@ -11,13 +11,19 @@ import ( "github.com/ipfs/go-ipfs-config" "github.com/facebookgo/atomicfile" - "github.com/ipfs/go-ipfs-util" ) +// ErrNotInitialized is returned when we fail to read the config because the +// repo doesn't exist. +var ErrNotInitialized = errors.New("ipfs not initialized, please run 'ipfs init'") + // ReadConfigFile reads the config from `filename` into `cfg`. func ReadConfigFile(filename string, cfg interface{}) error { f, err := os.Open(filename) if err != nil { + if os.IsNotExist(err) { + err = ErrNotInitialized + } return err } defer f.Close() @@ -56,11 +62,6 @@ func encode(w io.Writer, value interface{}) error { // Load reads given file and returns the read config, or error. func Load(filename string) (*config.Config, error) { - // if nothing is there, fail. User must run 'ipfs init' - if !util.FileExists(filename) { - return nil, errors.New("ipfs not initialized, please run 'ipfs init'") - } - var cfg config.Config err := ReadConfigFile(filename, &cfg) if err != nil { From f0b5fe9733aaa35b24312c46d0687f024b31b645 Mon Sep 17 00:00:00 2001 From: Steven Allen Date: Thu, 29 Aug 2019 13:54:28 -0700 Subject: [PATCH 182/414] go-ipfs-config: plugins: don't omit empty config values Turns out the go-ipfs config logic really doesn't play well with this. Let's just keep them and avoid encoding empty values another way. --- config/plugins.go | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/config/plugins.go b/config/plugins.go index c9b148049a1..08a1acb34f5 100644 --- a/config/plugins.go +++ b/config/plugins.go @@ -1,11 +1,11 @@ package config type Plugins struct { - Plugins map[string]Plugin `json:",omitempty"` + Plugins map[string]Plugin // TODO: Loader Path? Leaving that out for now due to security concerns. } type Plugin struct { - Disabled bool `json:",omitempty"` - Config interface{} `json:",omitempty"` + Disabled bool + Config interface{} } From 66886eb1ffd43f7b30bbc0b3eeabba8547d0058c Mon Sep 17 00:00:00 2001 From: Steven Allen Date: Wed, 4 Dec 2019 13:31:28 -0500 Subject: [PATCH 183/414] go-ipfs-config: fix(init): use key size constraints defined in libp2p --- config/init.go | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/config/init.go b/config/init.go index d658866ef62..54e862fe129 100644 --- a/config/init.go +++ b/config/init.go @@ -2,7 +2,6 @@ package config import ( "encoding/base64" - "errors" "fmt" "io" "time" @@ -152,8 +151,8 @@ func DefaultDatastoreConfig() Datastore { func identityConfig(out io.Writer, nbits int) (Identity, error) { // TODO guard higher up ident := Identity{} - if nbits < 2048 { - return ident, errors.New("bitsize less than 2048 is considered unsafe") + if nbits < ci.MinRsaKeyBits { + return ident, ci.ErrRsaKeyTooSmall } fmt.Fprintf(out, "generating %v-bit RSA keypair...", nbits) From d0d55a8548dd413919b6a2c1fd0cf497918e7c3c Mon Sep 17 00:00:00 2001 From: Steven Allen Date: Tue, 23 Jul 2019 16:30:34 -0700 Subject: [PATCH 184/414] go-ipfs-config: migrate multiaddrs from /ipfs -> /p2p See: https://github.com/libp2p/libp2p/issues/79 --- config/bootstrap_peers.go | 26 +++++++++++++------------- 1 file changed, 13 insertions(+), 13 deletions(-) diff --git a/config/bootstrap_peers.go b/config/bootstrap_peers.go index f4a13dc9d06..a4027f824af 100644 --- a/config/bootstrap_peers.go +++ b/config/bootstrap_peers.go @@ -19,19 +19,19 @@ import ( // NOTE: This is here -- and not inside cmd/ipfs/init.go -- because of an // import dependency issue. TODO: move this into a config/default/ package. var DefaultBootstrapAddresses = []string{ - "/dnsaddr/bootstrap.libp2p.io/ipfs/QmNnooDu7bfjPFoTZYxMNLWUQJyrVwtbZg5gBMjTezGAJN", - "/dnsaddr/bootstrap.libp2p.io/ipfs/QmQCU2EcMqAqQPR2i9bChDtGNJchTbq5TbXJJ16u19uLTa", - "/dnsaddr/bootstrap.libp2p.io/ipfs/QmbLHAnMoJPWSCR5Zhtx6BHJX9KiKNN6tpvbUcqanj75Nb", - "/dnsaddr/bootstrap.libp2p.io/ipfs/QmcZf59bWwK5XFi76CZX8cbJ4BhTzzA3gU1ZjYZcYW3dwt", - "/ip4/104.131.131.82/tcp/4001/ipfs/QmaCpDMGvV2BGHeYERUEnRQAwe3N8SzbUtfsmvsqQLuvuJ", // mars.i.ipfs.io - "/ip4/104.236.179.241/tcp/4001/ipfs/QmSoLPppuBtQSGwKDZT2M73ULpjvfd3aZ6ha4oFGL1KrGM", // pluto.i.ipfs.io - "/ip4/128.199.219.111/tcp/4001/ipfs/QmSoLSafTMBsPKadTEgaXctDQVcqN88CNLHXMkTNwMKPnu", // saturn.i.ipfs.io - "/ip4/104.236.76.40/tcp/4001/ipfs/QmSoLV4Bbm51jM9C4gDYZQ9Cy3U6aXMJDAbzgu2fzaDs64", // venus.i.ipfs.io - "/ip4/178.62.158.247/tcp/4001/ipfs/QmSoLer265NRgSp2LA3dPaeykiS1J6DifTC88f5uVQKNAd", // earth.i.ipfs.io - "/ip6/2604:a880:1:20::203:d001/tcp/4001/ipfs/QmSoLPppuBtQSGwKDZT2M73ULpjvfd3aZ6ha4oFGL1KrGM", // pluto.i.ipfs.io - "/ip6/2400:6180:0:d0::151:6001/tcp/4001/ipfs/QmSoLSafTMBsPKadTEgaXctDQVcqN88CNLHXMkTNwMKPnu", // saturn.i.ipfs.io - "/ip6/2604:a880:800:10::4a:5001/tcp/4001/ipfs/QmSoLV4Bbm51jM9C4gDYZQ9Cy3U6aXMJDAbzgu2fzaDs64", // venus.i.ipfs.io - "/ip6/2a03:b0c0:0:1010::23:1001/tcp/4001/ipfs/QmSoLer265NRgSp2LA3dPaeykiS1J6DifTC88f5uVQKNAd", // earth.i.ipfs.io + "/dnsaddr/bootstrap.libp2p.io/p2p/QmNnooDu7bfjPFoTZYxMNLWUQJyrVwtbZg5gBMjTezGAJN", + "/dnsaddr/bootstrap.libp2p.io/p2p/QmQCU2EcMqAqQPR2i9bChDtGNJchTbq5TbXJJ16u19uLTa", + "/dnsaddr/bootstrap.libp2p.io/p2p/QmbLHAnMoJPWSCR5Zhtx6BHJX9KiKNN6tpvbUcqanj75Nb", + "/dnsaddr/bootstrap.libp2p.io/p2p/QmcZf59bWwK5XFi76CZX8cbJ4BhTzzA3gU1ZjYZcYW3dwt", + "/ip4/104.131.131.82/tcp/4001/p2p/QmaCpDMGvV2BGHeYERUEnRQAwe3N8SzbUtfsmvsqQLuvuJ", // mars.i.ipfs.io + "/ip4/104.236.179.241/tcp/4001/p2p/QmSoLPppuBtQSGwKDZT2M73ULpjvfd3aZ6ha4oFGL1KrGM", // pluto.i.ipfs.io + "/ip4/128.199.219.111/tcp/4001/p2p/QmSoLSafTMBsPKadTEgaXctDQVcqN88CNLHXMkTNwMKPnu", // saturn.i.ipfs.io + "/ip4/104.236.76.40/tcp/4001/p2p/QmSoLV4Bbm51jM9C4gDYZQ9Cy3U6aXMJDAbzgu2fzaDs64", // venus.i.ipfs.io + "/ip4/178.62.158.247/tcp/4001/p2p/QmSoLer265NRgSp2LA3dPaeykiS1J6DifTC88f5uVQKNAd", // earth.i.ipfs.io + "/ip6/2604:a880:1:20::203:d001/tcp/4001/p2p/QmSoLPppuBtQSGwKDZT2M73ULpjvfd3aZ6ha4oFGL1KrGM", // pluto.i.ipfs.io + "/ip6/2400:6180:0:d0::151:6001/tcp/4001/p2p/QmSoLSafTMBsPKadTEgaXctDQVcqN88CNLHXMkTNwMKPnu", // saturn.i.ipfs.io + "/ip6/2604:a880:800:10::4a:5001/tcp/4001/p2p/QmSoLV4Bbm51jM9C4gDYZQ9Cy3U6aXMJDAbzgu2fzaDs64", // venus.i.ipfs.io + "/ip6/2a03:b0c0:0:1010::23:1001/tcp/4001/p2p/QmSoLer265NRgSp2LA3dPaeykiS1J6DifTC88f5uVQKNAd", // earth.i.ipfs.io } // ErrInvalidPeerAddr signals an address is not a valid peer address. From 95a14f43ac32abec20de73035b27fbc154fbaa43 Mon Sep 17 00:00:00 2001 From: Adin Schmahmann Date: Mon, 16 Dec 2019 13:28:05 -0500 Subject: [PATCH 185/414] go-ipfs-config: profile: badger profile now defaults to asynchronous writes --- config/profile.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/config/profile.go b/config/profile.go index 458f6a82214..bf0569535da 100644 --- a/config/profile.go +++ b/config/profile.go @@ -130,7 +130,7 @@ Make sure to backup your data frequently.`, "child": map[string]interface{}{ "type": "badgerds", "path": "badgerds", - "syncWrites": true, + "syncWrites": false, "truncate": true, }, } From 7dfdeeb04e3eb35b4e045e83dec88f23313a1ce8 Mon Sep 17 00:00:00 2001 From: Steven Allen Date: Tue, 11 Feb 2020 19:16:27 -0800 Subject: [PATCH 186/414] go-ipfs-config: feat: add graphsync option related to https://github.com/ipfs/go-ipfs/issues/6830 --- config/experiments.go | 1 + 1 file changed, 1 insertion(+) diff --git a/config/experiments.go b/config/experiments.go index 6821ed6bc81..2e14ce89a5a 100644 --- a/config/experiments.go +++ b/config/experiments.go @@ -4,6 +4,7 @@ type Experiments struct { FilestoreEnabled bool UrlstoreEnabled bool ShardingEnabled bool + GraphsyncEnabled bool Libp2pStreamMounting bool P2pHttpProxy bool QUIC bool From 265f8cf95d2a49a836c450d6cad63d3fa3fa3ed3 Mon Sep 17 00:00:00 2001 From: Marcin Rataj Date: Thu, 14 Mar 2019 20:31:46 -0700 Subject: [PATCH 187/414] go-ipfs-config: add config options for proxy/subdomain Co-authored-by: Steven --- config/gateway.go | 68 ++++++++++++++++++++++++++++++++++++++++++++--- 1 file changed, 64 insertions(+), 4 deletions(-) diff --git a/config/gateway.go b/config/gateway.go index 017be9b285b..644467891c9 100644 --- a/config/gateway.go +++ b/config/gateway.go @@ -1,11 +1,71 @@ package config +type GatewaySpec struct { + // Paths is explicit list of path prefixes that should be handled by + // this gateway. Example: `["/ipfs", "/ipns", "/api"]` + Paths []string + + // UseSubdomains indicates whether or not this gateway uses subdomains + // for IPFS resources instead of paths. That is: http://CID.ipfs.GATEWAY/... + // + // If this flag is set, any /ipns/$id and/or /ipfs/$id paths in PathPrefixes + // will be permanently redirected to http://$id.[ipns|ipfs].$gateway/. + // + // We do not support using both paths and subdomains for a single domain + // for security reasons (Origin isolation). + UseSubdomains bool + + // NoDNSLink configures this gateway to _not_ resolve DNSLink for the FQDN + // provided in `Host` HTTP header. + NoDNSLink bool +} + // Gateway contains options for the HTTP gateway server. type Gateway struct { - HTTPHeaders map[string][]string // HTTP headers to return with the gateway + + // HTTPHeaders configures the headers that should be returned by this + // gateway. + HTTPHeaders map[string][]string // HTTP headers to return with the gateway + + // RootRedirect is the path to which requests to `/` on this gateway + // should be redirected. RootRedirect string - Writable bool + + // Writable enables PUT/POST request handling by this gateway. Usually, + // writing is done through the API, not the gateway. + Writable bool + + // PathPrefixes is an array of acceptable url paths that a client can + // specify in X-Ipfs-Path-Prefix header. + // + // The X-Ipfs-Path-Prefix header is used to specify a base path to prepend + // to links in directory listings and for trailing-slash redirects. It is + // intended to be set by a frontend http proxy like nginx. + // + // Example: To mount blog.ipfs.io (a DNSLink site) at ipfs.io/blog + // set PathPrefixes to ["/blog"] and nginx config to translate paths + // and pass Host header (for DNSLink): + // location /blog/ { + // rewrite "^/blog(/.*)$" $1 break; + // proxy_set_header Host blog.ipfs.io; + // proxy_set_header X-Ipfs-Gateway-Prefix /blog; + // proxy_pass http://127.0.0.1:8080; + // } PathPrefixes []string - APICommands []string - NoFetch bool + + // FIXME: Not yet implemented + APICommands []string + + // NoFetch configures the gateway to _not_ fetch blocks in response to + // requests. + NoFetch bool + + // NoDNSLink configures the gateway to _not_ perform DNS TXT record + // lookups in response to requests with values in `Host` HTTP header. + // This flag can be overriden per FQDN in PublicGateways. + NoDNSLink bool + + // PublicGateways configures behavior of known public gateways. + // Each key is a fully qualified domain name (FQDN). + PublicGateways map[string]*GatewaySpec } From f455264a4b6e2310c999e470ae3a4522287bda98 Mon Sep 17 00:00:00 2001 From: Steven Allen Date: Tue, 17 Mar 2020 19:07:14 -0700 Subject: [PATCH 188/414] go-ipfs-config: feat: remove old bootstrap peers --- config/bootstrap_peers.go | 10 +--------- 1 file changed, 1 insertion(+), 9 deletions(-) diff --git a/config/bootstrap_peers.go b/config/bootstrap_peers.go index a4027f824af..9f586baf7d3 100644 --- a/config/bootstrap_peers.go +++ b/config/bootstrap_peers.go @@ -23,15 +23,7 @@ var DefaultBootstrapAddresses = []string{ "/dnsaddr/bootstrap.libp2p.io/p2p/QmQCU2EcMqAqQPR2i9bChDtGNJchTbq5TbXJJ16u19uLTa", "/dnsaddr/bootstrap.libp2p.io/p2p/QmbLHAnMoJPWSCR5Zhtx6BHJX9KiKNN6tpvbUcqanj75Nb", "/dnsaddr/bootstrap.libp2p.io/p2p/QmcZf59bWwK5XFi76CZX8cbJ4BhTzzA3gU1ZjYZcYW3dwt", - "/ip4/104.131.131.82/tcp/4001/p2p/QmaCpDMGvV2BGHeYERUEnRQAwe3N8SzbUtfsmvsqQLuvuJ", // mars.i.ipfs.io - "/ip4/104.236.179.241/tcp/4001/p2p/QmSoLPppuBtQSGwKDZT2M73ULpjvfd3aZ6ha4oFGL1KrGM", // pluto.i.ipfs.io - "/ip4/128.199.219.111/tcp/4001/p2p/QmSoLSafTMBsPKadTEgaXctDQVcqN88CNLHXMkTNwMKPnu", // saturn.i.ipfs.io - "/ip4/104.236.76.40/tcp/4001/p2p/QmSoLV4Bbm51jM9C4gDYZQ9Cy3U6aXMJDAbzgu2fzaDs64", // venus.i.ipfs.io - "/ip4/178.62.158.247/tcp/4001/p2p/QmSoLer265NRgSp2LA3dPaeykiS1J6DifTC88f5uVQKNAd", // earth.i.ipfs.io - "/ip6/2604:a880:1:20::203:d001/tcp/4001/p2p/QmSoLPppuBtQSGwKDZT2M73ULpjvfd3aZ6ha4oFGL1KrGM", // pluto.i.ipfs.io - "/ip6/2400:6180:0:d0::151:6001/tcp/4001/p2p/QmSoLSafTMBsPKadTEgaXctDQVcqN88CNLHXMkTNwMKPnu", // saturn.i.ipfs.io - "/ip6/2604:a880:800:10::4a:5001/tcp/4001/p2p/QmSoLV4Bbm51jM9C4gDYZQ9Cy3U6aXMJDAbzgu2fzaDs64", // venus.i.ipfs.io - "/ip6/2a03:b0c0:0:1010::23:1001/tcp/4001/p2p/QmSoLer265NRgSp2LA3dPaeykiS1J6DifTC88f5uVQKNAd", // earth.i.ipfs.io + "/ip4/104.131.131.82/tcp/4001/p2p/QmaCpDMGvV2BGHeYERUEnRQAwe3N8SzbUtfsmvsqQLuvuJ", // mars.i.ipfs.io } // ErrInvalidPeerAddr signals an address is not a valid peer address. From f83f2b1487f4a734a3a20f33e337ec667d1e72ae Mon Sep 17 00:00:00 2001 From: Steven Allen Date: Tue, 17 Mar 2020 19:08:22 -0700 Subject: [PATCH 189/414] go-ipfs-config: chore: remove unnecessary dependency We _used_ to need this dependency to parse the dns addresses. However, dnsaddr protocols are now all defined directly in go-multiaddr. --- config/bootstrap_peers.go | 4 ---- 1 file changed, 4 deletions(-) diff --git a/config/bootstrap_peers.go b/config/bootstrap_peers.go index 9f586baf7d3..91d01457307 100644 --- a/config/bootstrap_peers.go +++ b/config/bootstrap_peers.go @@ -6,10 +6,6 @@ import ( peer "github.com/libp2p/go-libp2p-core/peer" ma "github.com/multiformats/go-multiaddr" - - // Needs to be imported so that users can import this package directly - // and still parse the bootstrap addresses. - _ "github.com/multiformats/go-multiaddr-dns" ) // DefaultBootstrapAddresses are the hardcoded bootstrap addresses From cc723f94b8b1fd35b8c1914d25b86fde7f892319 Mon Sep 17 00:00:00 2001 From: Steven Allen Date: Wed, 25 Mar 2020 15:35:05 -0700 Subject: [PATCH 190/414] go-ipfs-config: feat: mark badger as stable We're still not ready to enable it by default but at least mark it as stable. --- config/init.go | 61 ++++++++++++++++++++++------------- config/profile.go | 81 +++++++++++++++++++++++++---------------------- 2 files changed, 82 insertions(+), 60 deletions(-) diff --git a/config/init.go b/config/init.go index 54e862fe129..ea1530c224d 100644 --- a/config/init.go +++ b/config/init.go @@ -118,29 +118,46 @@ func DefaultDatastoreConfig() Datastore { StorageGCWatermark: 90, // 90% GCPeriod: "1h", BloomFilterSize: 0, - Spec: map[string]interface{}{ - "type": "mount", - "mounts": []interface{}{ - map[string]interface{}{ - "mountpoint": "/blocks", - "type": "measure", - "prefix": "flatfs.datastore", - "child": map[string]interface{}{ - "type": "flatfs", - "path": "blocks", - "sync": true, - "shardFunc": "/repo/flatfs/shard/v1/next-to-last/2", - }, + Spec: flatfsSpec(), + } +} + +func badgerSpec() map[string]interface{} { + return map[string]interface{}{ + "type": "measure", + "prefix": "badger.datastore", + "child": map[string]interface{}{ + "type": "badgerds", + "path": "badgerds", + "syncWrites": false, + "truncate": true, + }, + } +} + +func flatfsSpec() map[string]interface{} { + return map[string]interface{}{ + "type": "mount", + "mounts": []interface{}{ + map[string]interface{}{ + "mountpoint": "/blocks", + "type": "measure", + "prefix": "flatfs.datastore", + "child": map[string]interface{}{ + "type": "flatfs", + "path": "blocks", + "sync": true, + "shardFunc": "/repo/flatfs/shard/v1/next-to-last/2", }, - map[string]interface{}{ - "mountpoint": "/", - "type": "measure", - "prefix": "leveldb.datastore", - "child": map[string]interface{}{ - "type": "levelds", - "path": "datastore", - "compression": "none", - }, + }, + map[string]interface{}{ + "mountpoint": "/", + "type": "measure", + "prefix": "leveldb.datastore", + "child": map[string]interface{}{ + "type": "levelds", + "path": "datastore", + "compression": "none", }, }, }, diff --git a/config/profile.go b/config/profile.go index bf0569535da..3f339dbf0e5 100644 --- a/config/profile.go +++ b/config/profile.go @@ -11,11 +11,14 @@ type Transformer func(c *Config) error // Profile contains the profile transformer the description of the profile type Profile struct { - // Description briefly describes the functionality of the profile + // Description briefly describes the functionality of the profile. Description string - // Transform takes ipfs configuration and applies the profile to it + // Transform takes ipfs configuration and applies the profile to it. Transform Transformer + + // InitOnly specifies that this profile can only be applied on init. + InitOnly bool } // defaultServerFilters has is a list of IPv4 and IPv6 prefixes that are private, local only, or unrouteable. @@ -107,51 +110,49 @@ Inverse profile of the test profile.`, return nil }, }, - "badgerds": { - Description: `Replaces default datastore configuration with experimental -badger datastore. - -If you apply this profile after ipfs init, you will need -to convert your datastore to the new configuration. -You can do this using ipfs-ds-convert. - -For more on ipfs-ds-convert see -$ ipfs-ds-convert --help -and -$ ipfs-ds-convert convert --help - -WARNING: badger datastore is experimental. -Make sure to backup your data frequently.`, + "flatfs": { + Description: `Configures the node to use the flatfs datastore. + +This is the most battle-tested and reliable datastore, but it's significantly +slower than the badger datastore. You should use this datastore if: + +* You need a very simple and very reliable datastore you and trust your + filesystem. This datastore stores each block as a separate file in the + underlying filesystem so it's unlikely to loose data unless there's an issue + with the underlying file system. +* You need to run garbage collection on a small (<= 10GiB) datastore. The + default datastore, badger, can leave several gigabytes of data behind when + garbage collecting. +* You're concerned about memory usage. In its default configuration, badger can + use up to several gigabytes of memory. + +This profile may only be applied when first initializing the node. +`, + InitOnly: true, Transform: func(c *Config) error { - c.Datastore.Spec = map[string]interface{}{ - "type": "measure", - "prefix": "badger.datastore", - "child": map[string]interface{}{ - "type": "badgerds", - "path": "badgerds", - "syncWrites": false, - "truncate": true, - }, - } + c.Datastore.Spec = flatfsSpec() return nil }, }, - "default-datastore": { - Description: `Restores default datastore configuration. + "badgerds": { + Description: `Configures the node to use the badger datastore. -If you apply this profile after ipfs init, you will need -to convert your datastore to the new configuration. -You can do this using ipfs-ds-convert. +This is the fastest datastore. Use this datastore if performance, especially +when adding many gigabytes of files, is critical. However: -For more on ipfs-ds-convert see -$ ipfs-ds-convert --help -and -$ ipfs-ds-convert convert --help -`, +* This datastore will not properly reclaim space when your datastore is + smaller than several gigabytes. If you run IPFS with '--enable-gc' (you have + enabled block-level garbage collection), you plan on storing very little data in + your IPFS node, and disk usage is more critical than performance, consider using + flatfs. +* This datastore uses up to several gigabytes of memory. +This profile may only be applied when first initializing the node.`, + + InitOnly: true, Transform: func(c *Config) error { - c.Datastore.Spec = DefaultDatastoreConfig().Spec + c.Datastore.Spec = badgerSpec() return nil }, }, @@ -187,6 +188,10 @@ fetching may be degraded. }, } +func init() { + Profiles["default-datatore"] = Profiles["badgerds"] +} + func getAvailablePort() (port int, err error) { ln, err := net.Listen("tcp", "[::]:0") if err != nil { From 542ca9296bd565f612ea70527aa26d4c8b50b001 Mon Sep 17 00:00:00 2001 From: Steven Allen Date: Sun, 29 Mar 2020 18:50:34 -0700 Subject: [PATCH 191/414] go-ipfs-config: feat: remove PreferTLS experiment This will now be enabled by default. --- config/experiments.go | 1 - 1 file changed, 1 deletion(-) diff --git a/config/experiments.go b/config/experiments.go index 2e14ce89a5a..5a27bab5bf0 100644 --- a/config/experiments.go +++ b/config/experiments.go @@ -8,6 +8,5 @@ type Experiments struct { Libp2pStreamMounting bool P2pHttpProxy bool QUIC bool - PreferTLS bool StrategicProviding bool } From 043f20c1f8cf4b2039cd64254f992ce8c1a13f9b Mon Sep 17 00:00:00 2001 From: Steven Allen Date: Mon, 6 Apr 2020 15:42:36 -0700 Subject: [PATCH 192/414] go-ipfs-config: feat: add private routing config field That way, users can enable/disable/configure routing on their local network. --- config/routing.go | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/config/routing.go b/config/routing.go index e601cd5e8d3..d63140aa108 100644 --- a/config/routing.go +++ b/config/routing.go @@ -4,4 +4,8 @@ package config type Routing struct { // Type sets default daemon routing mode. Type string + + // PrivateType sets the routing mode for private networks. If unset, + // Type will be used. + PrivateType string } From 7b9225113ff63e4fba08c81c6372a52566181914 Mon Sep 17 00:00:00 2001 From: Steven Allen Date: Mon, 6 Apr 2020 17:32:07 -0700 Subject: [PATCH 193/414] go-ipfs-config: doc: add a bit of documentation. --- config/routing.go | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/config/routing.go b/config/routing.go index d63140aa108..341e2653a61 100644 --- a/config/routing.go +++ b/config/routing.go @@ -3,9 +3,11 @@ package config // Routing defines configuration options for libp2p routing type Routing struct { // Type sets default daemon routing mode. + // + // Can be one of "dht", "dhtclient", "dhtserver", "none", or unset. Type string - // PrivateType sets the routing mode for private networks. If unset, - // Type will be used. + // PrivateType sets the routing mode for private networks. Can take the + // same values as Type and defaults to Type if unset. PrivateType string } From ab3a78d78e80263c80b0fbd8e350b3ddc3a6a2b4 Mon Sep 17 00:00:00 2001 From: Steven Allen Date: Thu, 9 Apr 2020 13:24:03 -0700 Subject: [PATCH 194/414] go-ipfs-config: feat: remove Routing.PrivateType This can't be set independently at this point. We can add something back when we know the form this option should take. --- config/routing.go | 4 ---- 1 file changed, 4 deletions(-) diff --git a/config/routing.go b/config/routing.go index 341e2653a61..c6157ec9637 100644 --- a/config/routing.go +++ b/config/routing.go @@ -6,8 +6,4 @@ type Routing struct { // // Can be one of "dht", "dhtclient", "dhtserver", "none", or unset. Type string - - // PrivateType sets the routing mode for private networks. Can take the - // same values as Type and defaults to Type if unset. - PrivateType string } From 4554fc924679f7e8e250b53ab738c3766da08604 Mon Sep 17 00:00:00 2001 From: Steven Allen Date: Tue, 14 Apr 2020 18:40:16 -0700 Subject: [PATCH 195/414] go-ipfs-config: feat: add an autonat config section And remove the current EnableAutoNATService option from the swarm config. While a breaking change, this shouldn't cause _too_ much trouble given that we're going to enable AutoNAT everywhere by default anyways. --- config/autonat.go | 79 +++++++++++++++++++++++++++++++++++++++++++++++ config/config.go | 1 + config/swarm.go | 2 -- 3 files changed, 80 insertions(+), 2 deletions(-) create mode 100644 config/autonat.go diff --git a/config/autonat.go b/config/autonat.go new file mode 100644 index 00000000000..05009ffc5dc --- /dev/null +++ b/config/autonat.go @@ -0,0 +1,79 @@ +package config + +import ( + "fmt" +) + +// AutoNATServiceMode configures the ipfs node's AutoNAT service. +type AutoNATServiceMode int + +const ( + // AutoNATServiceUnset indicates that the user has not set the + // AutoNATService mode. + // + // When unset, nodes configured to be public DHT nodes will _also_ + // perform limited AutoNAT dialbacks. + AutoNATServiceUnset AutoNATServiceMode = iota + // AutoNATServiceEnabled indicates that the user has enabled the + // AutoNATService. + AutoNATServiceEnabled + // AutoNATServiceDisabled indicates that the user has disabled the + // AutoNATService. + AutoNATServiceDisabled +) + +func (m *AutoNATServiceMode) UnmarshalText(text []byte) error { + switch string(text) { + case "": + *m = AutoNATServiceUnset + case "enabled": + *m = AutoNATServiceEnabled + case "disabled": + *m = AutoNATServiceDisabled + default: + return fmt.Errorf("unknown autonat mode: %s", string(text)) + } + return nil +} + +func (m AutoNATServiceMode) MarshalText() ([]byte, error) { + switch m { + case AutoNATServiceUnset: + return nil, nil + case AutoNATServiceEnabled: + return []byte("enabled"), nil + case AutoNATServiceDisabled: + return []byte("disabled"), nil + default: + return nil, fmt.Errorf("unknown autonat mode: %d", m) + } +} + +// AutoNATConfig configures the node's AutoNAT subsystem. +type AutoNATConfig struct { + // ServiceMode configures the node's AutoNAT service mode. + ServiceMode AutoNATServiceMode `json:",omitempty"` + + // Throttle configures AutoNAT dialback throttling. + // + // If unset, the conservative libp2p defaults will be unset. To help the + // network, please consider setting this and increasing the limits. + // + // By default, the limits will be a total of 30 dialbacks, with a + // per-peer max of 3 peer, resetting every minute. + Throttle *AutoNATThrottleConfig `json:",omitempty"` +} + +// AutoNATThrottleConfig configures the throttle limites +type AutoNATThrottleConfig struct { + // GlobalLimit and PeerLimit sets the global and per-peer dialback + // limits. The AutoNAT service will only perform the specified number of + // dialbacks per interval. + // + // Setting either to 0 will disable the appropriate limit. + GlobalLimit, PeerLimit int + + // Interval specifies how frequently this node should reset the + // global/peer dialback limits. + Interval string +} diff --git a/config/config.go b/config/config.go index 3f140474566..9af0cf68f19 100644 --- a/config/config.go +++ b/config/config.go @@ -25,6 +25,7 @@ type Config struct { Gateway Gateway // local node's gateway server options API API // local node's API settings Swarm SwarmConfig + AutoNAT AutoNATConfig Pubsub PubsubConfig Provider Provider diff --git a/config/swarm.go b/config/swarm.go index 16dc54d9cba..86060299623 100644 --- a/config/swarm.go +++ b/config/swarm.go @@ -10,8 +10,6 @@ type SwarmConfig struct { // autorelay functionality // if true, then the libp2p host will be constructed with autorelay functionality. EnableAutoRelay bool - // if true, then an AutoNATService will be instantiated to facilitate autorelay - EnableAutoNATService bool ConnMgr ConnMgr } From 25a96cfb1bdcfcd6ee0090a28bbd5df051f67345 Mon Sep 17 00:00:00 2001 From: Steven Allen Date: Tue, 14 Apr 2020 19:55:26 -0700 Subject: [PATCH 196/414] go-ipfs-config: feat: add and use a duration helper type --- config/autonat.go | 4 +++- config/types.go | 20 ++++++++++++++++++++ config/types_test.go | 32 ++++++++++++++++++++++++++++++++ 3 files changed, 55 insertions(+), 1 deletion(-) diff --git a/config/autonat.go b/config/autonat.go index 05009ffc5dc..a1a3f699cda 100644 --- a/config/autonat.go +++ b/config/autonat.go @@ -75,5 +75,7 @@ type AutoNATThrottleConfig struct { // Interval specifies how frequently this node should reset the // global/peer dialback limits. - Interval string + // + // When unset, this defaults to 1 minute. + Interval Duration `json:",omitempty"` } diff --git a/config/types.go b/config/types.go index 58451c68f12..90363e30dc4 100644 --- a/config/types.go +++ b/config/types.go @@ -2,6 +2,7 @@ package config import ( "encoding/json" + "time" ) // Strings is a helper type that (un)marshals a single string to/from a single @@ -39,3 +40,22 @@ func (o Strings) MarshalJSON() ([]byte, error) { var _ json.Unmarshaler = (*Strings)(nil) var _ json.Marshaler = (*Strings)(nil) + +// Duration wraps time.Duration to provide json serialization and deserialization. +// +// NOTE: the zero value encodes to an empty string. +type Duration time.Duration + +func (d *Duration) UnmarshalText(text []byte) error { + dur, err := time.ParseDuration(string(text)) + *d = Duration(dur) + return err +} + +func (d Duration) MarshalText() ([]byte, error) { + return []byte(time.Duration(d).String()), nil +} + +func (d Duration) String() string { + return time.Duration(d).String() +} diff --git a/config/types_test.go b/config/types_test.go index 7523962ae83..295ce922995 100644 --- a/config/types_test.go +++ b/config/types_test.go @@ -3,8 +3,40 @@ package config import ( "encoding/json" "testing" + "time" ) +func TestDuration(t *testing.T) { + out, err := json.Marshal(Duration(time.Second)) + if err != nil { + t.Fatal(err) + + } + expected := "\"1s\"" + if string(out) != expected { + t.Fatalf("expected %s, got %s", expected, string(out)) + } + var d Duration + err = json.Unmarshal(out, &d) + if err != nil { + t.Fatal(err) + } + if time.Duration(d) != time.Second { + t.Fatal("expected a second") + } + type Foo struct { + D Duration `json:",omitempty"` + } + out, err = json.Marshal(new(Foo)) + if err != nil { + t.Fatal(err) + } + expected = "{}" + if string(out) != expected { + t.Fatal("expected omitempty to omit the duration") + } +} + func TestOneStrings(t *testing.T) { out, err := json.Marshal(Strings{"one"}) if err != nil { From cf3fa1bdb60a2bd4d36b965e16b926bc5bf93ea9 Mon Sep 17 00:00:00 2001 From: Steven Allen Date: Tue, 14 Apr 2020 20:29:05 -0700 Subject: [PATCH 197/414] go-ipfs-config: feat: disable autonat service when in lowpower mode --- config/profile.go | 1 + 1 file changed, 1 insertion(+) diff --git a/config/profile.go b/config/profile.go index 3f339dbf0e5..a95ba0f1fe9 100644 --- a/config/profile.go +++ b/config/profile.go @@ -163,6 +163,7 @@ fetching may be degraded. `, Transform: func(c *Config) error { c.Routing.Type = "dhtclient" + c.AutoNAT.ServiceMode = AutoNATServiceDisabled c.Reprovider.Interval = "0" c.Swarm.ConnMgr.LowWater = 20 From d02cdb3963957867b1e93edbb4ccf91a8290dec7 Mon Sep 17 00:00:00 2001 From: Will Scott Date: Mon, 20 Apr 2020 17:37:46 -0700 Subject: [PATCH 198/414] go-ipfs-config: Add Init Alternative allowing specification of ED25519 key --- config/init.go | 45 ++++++++++++++++++++++++++++++++++++++------- 1 file changed, 38 insertions(+), 7 deletions(-) diff --git a/config/init.go b/config/init.go index ea1530c224d..22c95107710 100644 --- a/config/init.go +++ b/config/init.go @@ -1,17 +1,23 @@ package config import ( + "crypto/rand" "encoding/base64" "fmt" "io" "time" + "github.com/ipfs/interface-go-ipfs-core/options" ci "github.com/libp2p/go-libp2p-core/crypto" peer "github.com/libp2p/go-libp2p-core/peer" ) func Init(out io.Writer, nBitsForKeypair int) (*Config, error) { - identity, err := identityConfig(out, nBitsForKeypair) + return InitWithOptions(out, []options.KeyGenerateOption{options.Key.Size(nBitsForKeypair)}) +} + +func InitWithOptions(out io.Writer, opts []options.KeyGenerateOption) (*Config, error) { + identity, err := identityConfig(out, opts) if err != nil { return nil, err } @@ -165,18 +171,43 @@ func flatfsSpec() map[string]interface{} { } // identityConfig initializes a new identity. -func identityConfig(out io.Writer, nbits int) (Identity, error) { +func identityConfig(out io.Writer, opts []options.KeyGenerateOption) (Identity, error) { // TODO guard higher up ident := Identity{} - if nbits < ci.MinRsaKeyBits { - return ident, ci.ErrRsaKeyTooSmall - } - fmt.Fprintf(out, "generating %v-bit RSA keypair...", nbits) - sk, pk, err := ci.GenerateKeyPair(ci.RSA, nbits) + settings, err := options.KeyGenerateOptions(opts...) if err != nil { return ident, err } + + var sk ci.PrivKey + var pk ci.PubKey + + fmt.Fprintf(out, "generating %s keypair...", settings.Algorithm) + switch settings.Algorithm { + case "rsa": + if settings.Size == -1 { + settings.Size = options.DefaultRSALen + } + + priv, pub, err := ci.GenerateKeyPair(ci.RSA, settings.Size) + if err != nil { + return ident, err + } + + sk = priv + pk = pub + case "ed25519": + priv, pub, err := ci.GenerateEd25519Key(rand.Reader) + if err != nil { + return ident, err + } + + sk = priv + pk = pub + default: + return ident, fmt.Errorf("unrecognized key type: %s", settings.Algorithm) + } fmt.Fprintf(out, "done\n") // currently storing key unencrypted. in the future we need to encrypt it. From c6336c3303df300e88b592029390b0af6772afca Mon Sep 17 00:00:00 2001 From: Will Scott Date: Tue, 21 Apr 2020 08:08:21 -0700 Subject: [PATCH 199/414] go-ipfs-config: interface --- config/init.go | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/config/init.go b/config/init.go index 22c95107710..2a9c631d62a 100644 --- a/config/init.go +++ b/config/init.go @@ -13,15 +13,15 @@ import ( ) func Init(out io.Writer, nBitsForKeypair int) (*Config, error) { - return InitWithOptions(out, []options.KeyGenerateOption{options.Key.Size(nBitsForKeypair)}) -} - -func InitWithOptions(out io.Writer, opts []options.KeyGenerateOption) (*Config, error) { - identity, err := identityConfig(out, opts) + identity, err := CreateIdentity(out, []options.KeyGenerateOption{options.Key.Size(nBitsForKeypair)}) if err != nil { return nil, err } + return InitWithIdentity(identity) +} + +func InitWithIdentity(identity Identity) (*Config, error) { bootstrapPeers, err := DefaultBootstrapPeers() if err != nil { return nil, err @@ -170,8 +170,8 @@ func flatfsSpec() map[string]interface{} { } } -// identityConfig initializes a new identity. -func identityConfig(out io.Writer, opts []options.KeyGenerateOption) (Identity, error) { +// CreateIdentity initializes a new identity. +func CreateIdentity(out io.Writer, opts []options.KeyGenerateOption) (Identity, error) { // TODO guard higher up ident := Identity{} From 515d6905e38e4593a730c54725d43873ee2b2200 Mon Sep 17 00:00:00 2001 From: Steven Allen Date: Mon, 27 Apr 2020 14:34:28 -0700 Subject: [PATCH 200/414] go-ipfs-config: fix: correct the default-datastore config profile And use an actual profile instead of just aliasing. --- config/profile.go | 18 ++++++++++++++---- 1 file changed, 14 insertions(+), 4 deletions(-) diff --git a/config/profile.go b/config/profile.go index a95ba0f1fe9..697ca305aea 100644 --- a/config/profile.go +++ b/config/profile.go @@ -110,6 +110,20 @@ Inverse profile of the test profile.`, return nil }, }, + "default-datastore": { + Description: `Configures the node to use the default datastore (flatfs). + +Read the "flatfs" profile description for more information on this datastore. + +This profile may only be applied when first initializing the node. +`, + + InitOnly: true, + Transform: func(c *Config) error { + c.Datastore.Spec = flatfsSpec() + return nil + }, + }, "flatfs": { Description: `Configures the node to use the flatfs datastore. @@ -189,10 +203,6 @@ fetching may be degraded. }, } -func init() { - Profiles["default-datatore"] = Profiles["badgerds"] -} - func getAvailablePort() (port int, err error) { ln, err := net.Listen("tcp", "[::]:0") if err != nil { From a70d82e4ba8cefefc7829d10faf69049d79b7d7d Mon Sep 17 00:00:00 2001 From: Will Scott Date: Tue, 28 Apr 2020 09:40:59 -0700 Subject: [PATCH 201/414] go-ipfs-config: add test validating that createIdentity follows algorithm preference --- config/init_test.go | 36 ++++++++++++++++++++++++++++++++++++ 1 file changed, 36 insertions(+) create mode 100644 config/init_test.go diff --git a/config/init_test.go b/config/init_test.go new file mode 100644 index 00000000000..635c78afc5c --- /dev/null +++ b/config/init_test.go @@ -0,0 +1,36 @@ +package config + +import ( + "bytes" + "testing" + + "github.com/ipfs/interface-go-ipfs-core/options" + crypto_pb "github.com/libp2p/go-libp2p-core/crypto/pb" +) + +func TestCreateIdentity(t *testing.T) { + writer := bytes.NewBuffer(nil) + id, err := CreateIdentity(writer, []options.KeyGenerateOption{options.Key.Type(options.Ed25519Key)}) + if err != nil { + t.Fatal(err) + } + pk, err := id.DecodePrivateKey("") + if err != nil { + t.Fatal(err) + } + if pk.Type() != crypto_pb.KeyType_Ed25519 { + t.Fatal("unexpected type:", pk.Type()) + } + + id, err = CreateIdentity(writer, []options.KeyGenerateOption{options.Key.Type(options.RSAKey)}) + if err != nil { + t.Fatal(err) + } + pk, err = id.DecodePrivateKey("") + if err != nil { + t.Fatal(err) + } + if pk.Type() != crypto_pb.KeyType_RSA { + t.Fatal("unexpected type:", pk.Type()) + } +} From ed0f306c2cccc5ac484a303f66fa978489723ae0 Mon Sep 17 00:00:00 2001 From: Steven Allen Date: Tue, 19 May 2020 19:05:59 -0700 Subject: [PATCH 202/414] go-ipfs-config: feat: remove strict signing pubsub option. It's still possible to disable signing. However, it's no longer possible to enable signing _and_ disable strict signature verification. --- config/pubsub.go | 7 ------- 1 file changed, 7 deletions(-) diff --git a/config/pubsub.go b/config/pubsub.go index 94e03e28b82..bed6058478f 100644 --- a/config/pubsub.go +++ b/config/pubsub.go @@ -8,11 +8,4 @@ type PubsubConfig struct { // DisableSigning disables message signing. Message signing is *enabled* // by default. DisableSigning bool - - // StrictSignatureVerification enables strict signature verification. - // When enabled, unsigned messages will be rejected. Eventually, this - // will be made the default and this option will disappear. Once this - // happens, networks will either need to completely disable or - // completely enable message signing. - StrictSignatureVerification bool } From ca7098926ffcdb0cf067c90542899238587b4a1c Mon Sep 17 00:00:00 2001 From: "@RubenKelevra" Date: Thu, 21 May 2020 23:45:44 +0200 Subject: [PATCH 203/414] go-ipfs-config: default config: add QUIC listening ports + quic to mars.i.ipfs.io fixes 1) of https://github.com/ipfs/go-ipfs/issues/7343 --- config/bootstrap_peers.go | 3 ++- config/init.go | 3 ++- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/config/bootstrap_peers.go b/config/bootstrap_peers.go index 91d01457307..a8064d255a7 100644 --- a/config/bootstrap_peers.go +++ b/config/bootstrap_peers.go @@ -19,7 +19,8 @@ var DefaultBootstrapAddresses = []string{ "/dnsaddr/bootstrap.libp2p.io/p2p/QmQCU2EcMqAqQPR2i9bChDtGNJchTbq5TbXJJ16u19uLTa", "/dnsaddr/bootstrap.libp2p.io/p2p/QmbLHAnMoJPWSCR5Zhtx6BHJX9KiKNN6tpvbUcqanj75Nb", "/dnsaddr/bootstrap.libp2p.io/p2p/QmcZf59bWwK5XFi76CZX8cbJ4BhTzzA3gU1ZjYZcYW3dwt", - "/ip4/104.131.131.82/tcp/4001/p2p/QmaCpDMGvV2BGHeYERUEnRQAwe3N8SzbUtfsmvsqQLuvuJ", // mars.i.ipfs.io + "/ip4/104.131.131.82/tcp/4001/p2p/QmaCpDMGvV2BGHeYERUEnRQAwe3N8SzbUtfsmvsqQLuvuJ", // mars.i.ipfs.io + "/ip4/104.131.131.82/quic/4001/quic/p2p/QmaCpDMGvV2BGHeYERUEnRQAwe3N8SzbUtfsmvsqQLuvuJ", // mars.i.ipfs.io } // ErrInvalidPeerAddr signals an address is not a valid peer address. diff --git a/config/init.go b/config/init.go index 2a9c631d62a..f43b4fe1ec8 100644 --- a/config/init.go +++ b/config/init.go @@ -107,8 +107,9 @@ func addressesConfig() Addresses { return Addresses{ Swarm: []string{ "/ip4/0.0.0.0/tcp/4001", - // "/ip4/0.0.0.0/udp/4002/utp", // disabled for now. "/ip6/::/tcp/4001", + "/ip4/0.0.0.0/udp/4001/quic", + "/ip6/::/udp/4001/quic", }, Announce: []string{}, NoAnnounce: []string{}, From 7f51e84a5509d9e14ee41826c11660920afc5c80 Mon Sep 17 00:00:00 2001 From: "@RubenKelevra" Date: Fri, 22 May 2020 03:11:41 +0200 Subject: [PATCH 204/414] go-ipfs-config: QUIC: remove experimental config option --- config/experiments.go | 1 - 1 file changed, 1 deletion(-) diff --git a/config/experiments.go b/config/experiments.go index 5a27bab5bf0..d63580f26c0 100644 --- a/config/experiments.go +++ b/config/experiments.go @@ -7,6 +7,5 @@ type Experiments struct { GraphsyncEnabled bool Libp2pStreamMounting bool P2pHttpProxy bool - QUIC bool StrategicProviding bool } From 5f248ac78cb12ec5805b7a1e6630c6a65b94a473 Mon Sep 17 00:00:00 2001 From: "@RubenKelevra" Date: Fri, 22 May 2020 04:28:17 +0200 Subject: [PATCH 205/414] go-ipfs-config: fix boostrap peers --- config/bootstrap_peers.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/config/bootstrap_peers.go b/config/bootstrap_peers.go index a8064d255a7..55d0f3b822f 100644 --- a/config/bootstrap_peers.go +++ b/config/bootstrap_peers.go @@ -20,7 +20,7 @@ var DefaultBootstrapAddresses = []string{ "/dnsaddr/bootstrap.libp2p.io/p2p/QmbLHAnMoJPWSCR5Zhtx6BHJX9KiKNN6tpvbUcqanj75Nb", "/dnsaddr/bootstrap.libp2p.io/p2p/QmcZf59bWwK5XFi76CZX8cbJ4BhTzzA3gU1ZjYZcYW3dwt", "/ip4/104.131.131.82/tcp/4001/p2p/QmaCpDMGvV2BGHeYERUEnRQAwe3N8SzbUtfsmvsqQLuvuJ", // mars.i.ipfs.io - "/ip4/104.131.131.82/quic/4001/quic/p2p/QmaCpDMGvV2BGHeYERUEnRQAwe3N8SzbUtfsmvsqQLuvuJ", // mars.i.ipfs.io + "/ip4/104.131.131.82/udp/4001/quic/p2p/QmaCpDMGvV2BGHeYERUEnRQAwe3N8SzbUtfsmvsqQLuvuJ", // mars.i.ipfs.io } // ErrInvalidPeerAddr signals an address is not a valid peer address. From ba2e10aecc06329f182d798ead57ef6ff5bb0cd0 Mon Sep 17 00:00:00 2001 From: Steven Allen Date: Fri, 22 May 2020 16:37:25 -0700 Subject: [PATCH 206/414] go-ipfs-config: fix: include key size in key init method --- config/init.go | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/config/init.go b/config/init.go index f43b4fe1ec8..2d2e2e6ef9d 100644 --- a/config/init.go +++ b/config/init.go @@ -184,13 +184,14 @@ func CreateIdentity(out io.Writer, opts []options.KeyGenerateOption) (Identity, var sk ci.PrivKey var pk ci.PubKey - fmt.Fprintf(out, "generating %s keypair...", settings.Algorithm) switch settings.Algorithm { case "rsa": if settings.Size == -1 { settings.Size = options.DefaultRSALen } + fmt.Fprintf(out, "generating %d-bit RSA keypair...", settings.Size) + priv, pub, err := ci.GenerateKeyPair(ci.RSA, settings.Size) if err != nil { return ident, err @@ -199,6 +200,7 @@ func CreateIdentity(out io.Writer, opts []options.KeyGenerateOption) (Identity, sk = priv pk = pub case "ed25519": + fmt.Fprintf(out, "generating ED25519 keypair...") priv, pub, err := ci.GenerateEd25519Key(rand.Reader) if err != nil { return ident, err From 13bcc4da44446d837c2fec15588ac9d1f994ba58 Mon Sep 17 00:00:00 2001 From: Steven Allen Date: Mon, 25 May 2020 14:05:24 -0700 Subject: [PATCH 207/414] go-ipfs-config: feat: add peering service config section --- config/config.go | 1 + config/peering.go | 9 +++++++++ 2 files changed, 10 insertions(+) create mode 100644 config/peering.go diff --git a/config/config.go b/config/config.go index 9af0cf68f19..5f6be8e5ac5 100644 --- a/config/config.go +++ b/config/config.go @@ -27,6 +27,7 @@ type Config struct { Swarm SwarmConfig AutoNAT AutoNATConfig Pubsub PubsubConfig + Peering Peering Provider Provider Reprovider Reprovider diff --git a/config/peering.go b/config/peering.go new file mode 100644 index 00000000000..21724686629 --- /dev/null +++ b/config/peering.go @@ -0,0 +1,9 @@ +package config + +import "github.com/libp2p/go-libp2p-core/peer" + +// Peering configures the peering service. +type Peering struct { + // Peer lists all peers with which this peer peers. + Peers []peer.AddrInfo +} From 75bde89788a3feac84fb258b9edc2d09ac24ce0b Mon Sep 17 00:00:00 2001 From: Steven Allen Date: Mon, 25 May 2020 19:14:40 -0700 Subject: [PATCH 208/414] go-ipfs-config: doc: improve wording for peering config Co-authored-by: Will --- config/peering.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/config/peering.go b/config/peering.go index 21724686629..242ce2d9898 100644 --- a/config/peering.go +++ b/config/peering.go @@ -4,6 +4,6 @@ import "github.com/libp2p/go-libp2p-core/peer" // Peering configures the peering service. type Peering struct { - // Peer lists all peers with which this peer peers. + // Peers lists the nodes to attempt to stay connected with. Peers []peer.AddrInfo } From e69fcd9d01416aacd704d224298229d6a194ac10 Mon Sep 17 00:00:00 2001 From: Steven Allen Date: Mon, 25 May 2020 23:06:42 -0700 Subject: [PATCH 209/414] go-ipfs-config: feat: add an option for security transport experiments We should have a more permanent way to configure security transports, but experimental flags are a quick and unstable way to do this without making any promises. --- config/experiments.go | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/config/experiments.go b/config/experiments.go index d63580f26c0..22e87a65950 100644 --- a/config/experiments.go +++ b/config/experiments.go @@ -8,4 +8,11 @@ type Experiments struct { Libp2pStreamMounting bool P2pHttpProxy bool StrategicProviding bool + + // OverrideSecurityTransports overrides the set of available security + // transports when non-empty. This option should eventually migrate some + // place more stable. + // + // Default: ["tls", "secio", "noise"]. + OverrideSecurityTransports []string `json:",omitempty"` } From 9ebfb4953020a09b94664c4a74a7d87f86427797 Mon Sep 17 00:00:00 2001 From: Steven Allen Date: Wed, 3 Jun 2020 09:03:56 -0700 Subject: [PATCH 210/414] go-ipfs-config: fix: remove group permissions There's no reason to give the group access to these files by default. --- config/serialize/serialize.go | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/config/serialize/serialize.go b/config/serialize/serialize.go index af11774b409..04492c5f38f 100644 --- a/config/serialize/serialize.go +++ b/config/serialize/serialize.go @@ -35,12 +35,12 @@ func ReadConfigFile(filename string, cfg interface{}) error { // WriteConfigFile writes the config from `cfg` into `filename`. func WriteConfigFile(filename string, cfg interface{}) error { - err := os.MkdirAll(filepath.Dir(filename), 0775) + err := os.MkdirAll(filepath.Dir(filename), 0755) if err != nil { return err } - f, err := atomicfile.New(filename, 0660) + f, err := atomicfile.New(filename, 0600) if err != nil { return err } From dfe53cd5b62fff8d81f74bb6a33ab4d91d9e398c Mon Sep 17 00:00:00 2001 From: Steven Allen Date: Mon, 15 Jun 2020 13:17:26 -0700 Subject: [PATCH 211/414] go-ipfs-config: feat: add flag and priority types These let us zero-encode "default" to "null" (and omit it with "omitempty") so we don't have to hard code the default in the config. --- config/types.go | 127 +++++++++++++++++++++++++++++++++++++++++++ config/types_test.go | 99 +++++++++++++++++++++++++++++++++ 2 files changed, 226 insertions(+) diff --git a/config/types.go b/config/types.go index 90363e30dc4..60c4c77d5f7 100644 --- a/config/types.go +++ b/config/types.go @@ -1,7 +1,9 @@ package config import ( + "encoding" "encoding/json" + "fmt" "time" ) @@ -41,6 +43,128 @@ func (o Strings) MarshalJSON() ([]byte, error) { var _ json.Unmarshaler = (*Strings)(nil) var _ json.Marshaler = (*Strings)(nil) +// Flag represents a ternary value: false (-1), default (0), or true (+1). +// +// When encoded in json, False is "false", Default is "null" (or empty), and True +// is "true". +type Flag int8 + +const ( + False Flag = -1 + Default Flag = 0 + True Flag = 1 +) + +func (f Flag) MarshalJSON() ([]byte, error) { + switch f { + case Default: + return json.Marshal(nil) + case True: + return json.Marshal(true) + case False: + return json.Marshal(false) + default: + return nil, fmt.Errorf("invalid flag value: %d", f) + } +} + +func (f *Flag) UnmarshalJSON(input []byte) error { + switch string(input) { + case "null", "undefined": + *f = Default + case "false": + *f = False + case "true": + *f = True + default: + return fmt.Errorf("failed to unmarshal %q into a flag: must be null/undefined, true, or false", string(input)) + } + return nil +} + +func (f Flag) String() string { + switch f { + case Default: + return "default" + case True: + return "true" + case False: + return "false" + default: + return fmt.Sprintf("", f) + } +} + +var _ json.Unmarshaler = (*Flag)(nil) +var _ json.Marshaler = (*Flag)(nil) + +// Priority represents a value with a priority where 0 means "default" and -11 +// means "disabled". +// +// When encoded in json, Default is encoded as "null" and Disabled is encoded as +// "false". +type Priority int64 + +const ( + DefaultPriority Priority = 0 + Disabled Priority = -1 +) + +func (p Priority) MarshalJSON() ([]byte, error) { + // > 0 == Priority + if p > 0 { + return json.Marshal(int64(p)) + } + // <= 0 == special + switch p { + case DefaultPriority: + return json.Marshal(nil) + case Disabled: + return json.Marshal(false) + default: + return nil, fmt.Errorf("invalid priority value: %d", p) + } +} + +func (p *Priority) UnmarshalJSON(input []byte) error { + switch string(input) { + case "null", "undefined": + *p = DefaultPriority + case "false": + *p = Disabled + case "true": + return fmt.Errorf("'true' is not a valid priority") + default: + var priority int64 + err := json.Unmarshal(input, &priority) + if err != nil { + return err + } + if priority <= 0 { + return fmt.Errorf("priority must be positive: %d <= 0", priority) + } + *p = Priority(priority) + } + return nil +} + +func (p Priority) String() string { + if p > 0 { + return fmt.Sprintf("%d", p) + } + switch p { + case DefaultPriority: + return "default" + case Disabled: + return "false" + default: + return fmt.Sprintf("", p) + } +} + +var _ json.Unmarshaler = (*Flag)(nil) +var _ json.Marshaler = (*Flag)(nil) + // Duration wraps time.Duration to provide json serialization and deserialization. // // NOTE: the zero value encodes to an empty string. @@ -59,3 +183,6 @@ func (d Duration) MarshalText() ([]byte, error) { func (d Duration) String() string { return time.Duration(d).String() } + +var _ encoding.TextUnmarshaler = (*Duration)(nil) +var _ encoding.TextMarshaler = (*Duration)(nil) diff --git a/config/types_test.go b/config/types_test.go index 295ce922995..dbc08cb888f 100644 --- a/config/types_test.go +++ b/config/types_test.go @@ -83,3 +83,102 @@ func TestFunkyStrings(t *testing.T) { t.Fatalf("unexpected result: %v", s) } } + +func TestFlag(t *testing.T) { + // make sure we have the right zero value. + var defaultFlag Flag + if defaultFlag != Default { + t.Errorf("expected default flag to be %q, got %q", Default, defaultFlag) + } + + for jsonStr, goValue := range map[string]Flag{ + "null": Default, + "true": True, + "false": False, + } { + var d Flag + err := json.Unmarshal([]byte(jsonStr), &d) + if err != nil { + t.Fatal(err) + } + if d != goValue { + t.Fatalf("expected %s, got %s", goValue, d) + } + + // Reverse + out, err := json.Marshal(goValue) + if err != nil { + t.Fatal(err) + } + if string(out) != jsonStr { + t.Fatalf("expected %s, got %s", jsonStr, string(out)) + } + } + + type Foo struct { + F Flag `json:",omitempty"` + } + out, err := json.Marshal(new(Foo)) + if err != nil { + t.Fatal(err) + } + expected := "{}" + if string(out) != expected { + t.Fatal("expected omitempty to omit the flag") + } +} + +func TestPriority(t *testing.T) { + // make sure we have the right zero value. + var defaultPriority Priority + if defaultPriority != DefaultPriority { + t.Errorf("expected default priority to be %q, got %q", DefaultPriority, defaultPriority) + } + + for jsonStr, goValue := range map[string]Priority{ + "null": DefaultPriority, + "false": Disabled, + "1": 1, + "2": 2, + "100": 100, + } { + var d Priority + err := json.Unmarshal([]byte(jsonStr), &d) + if err != nil { + t.Fatal(err) + } + if d != goValue { + t.Fatalf("expected %s, got %s", goValue, d) + } + + // Reverse + out, err := json.Marshal(goValue) + if err != nil { + t.Fatal(err) + } + if string(out) != jsonStr { + t.Fatalf("expected %s, got %s", jsonStr, string(out)) + } + } + + type Foo struct { + P Priority `json:",omitempty"` + } + out, err := json.Marshal(new(Foo)) + if err != nil { + t.Fatal(err) + } + expected := "{}" + if string(out) != expected { + t.Fatal("expected omitempty to omit the flag") + } + for _, invalid := range []string{ + "0", "-1", "-2", "1.1", "0.0", + } { + var p Priority + err := json.Unmarshal([]byte(invalid), &p) + if err == nil { + t.Errorf("expected to fail to decode %s as a priority", invalid) + } + } +} From 4f3aeb74286ae89137af690f2ea0aec989639c7b Mon Sep 17 00:00:00 2001 From: Steven Allen Date: Mon, 15 Jun 2020 13:41:37 -0700 Subject: [PATCH 212/414] go-ipfs-config: feat: add a transports section for enabling/disabling/prioritizing transports --- config/swarm.go | 67 ++++++++++++++++++++++++++++++++++++++++++++----- 1 file changed, 61 insertions(+), 6 deletions(-) diff --git a/config/swarm.go b/config/swarm.go index 86060299623..dc54ae902b2 100644 --- a/config/swarm.go +++ b/config/swarm.go @@ -1,19 +1,74 @@ package config type SwarmConfig struct { - AddrFilters []string + // AddrFilters specifies a set libp2p addresses that we should never + // dial or receive connections from. + AddrFilters []string + + // DisableBandwidthMetrics disables recording of bandwidth metrics for a + // slight reduction in memory usage. You probably don't need to set this + // flag. DisableBandwidthMetrics bool - DisableNatPortMap bool - DisableRelay bool - EnableRelayHop bool - // autorelay functionality - // if true, then the libp2p host will be constructed with autorelay functionality. + // DisableNatPortMap turns off NAT port mapping (UPnP, etc.). + DisableNatPortMap bool + + // DisableRelay explicitly disables the relay transport. + // + // Deprecated: This flag is deprecated and is overridden by + // `Transports.Relay` if specified. + DisableRelay bool `json:",omitempty"` + + // EnableRelayHop makes this node act as a public relay, relaying + // traffic between other nodes. + EnableRelayHop bool + + // EnableAutoRelay enables the "auto relay" feature. + // + // When both EnableAutoRelay and RelayHop are set, this go-ipfs node + // will advertise itself as a public relay, instead of finding and using + // advertised public relays. EnableAutoRelay bool + // Transports contains flags to enable/disable libp2p transports. + Transports Transports + + // ConnMgr configures the connection manager. ConnMgr ConnMgr } +type Transports struct { + // Network specifies the base transports we'll use for dialing. To + // listen on a transport, add the transport to your Addresses.Swarm. + Network struct { + // All default to on. + QUIC Flag `json:",omitempty"` + TCP Flag `json:",omitempty"` + Websocket Flag `json:",omitempty"` + Relay Flag `json:",omitempty"` + } + + // Security specifies the transports used to encrypt insecure network + // transports. + Security struct { + // Defaults to 100. + TLS Priority `json:",omitempty"` + // Defaults to 200. + SECIO Priority `json:",omitempty"` + // Defaults to 300. + Noise Priority `json:",omitempty"` + } + + // Multiplexers specifies the transports used to multiplex multiple + // connections over a single duplex connection. + Multiplex struct { + // Defaults to 100. + Yamux Priority `json:",omitempty"` + // Defaults to 200. + Mplex Priority `json:",omitempty"` + } +} + // ConnMgr defines configuration options for the libp2p connection manager type ConnMgr struct { Type string From 57089fd66bffc38285de36b37b091a1e664d4d88 Mon Sep 17 00:00:00 2001 From: Steven Allen Date: Mon, 15 Jun 2020 15:24:41 -0700 Subject: [PATCH 213/414] go-ipfs-config: feat: remove OverrideSecurityTransports This was never included in a release, and has been replaced by a flexible transport prioritization system. --- config/experiments.go | 7 ------- 1 file changed, 7 deletions(-) diff --git a/config/experiments.go b/config/experiments.go index 22e87a65950..d63580f26c0 100644 --- a/config/experiments.go +++ b/config/experiments.go @@ -8,11 +8,4 @@ type Experiments struct { Libp2pStreamMounting bool P2pHttpProxy bool StrategicProviding bool - - // OverrideSecurityTransports overrides the set of available security - // transports when non-empty. This option should eventually migrate some - // place more stable. - // - // Default: ["tls", "secio", "noise"]. - OverrideSecurityTransports []string `json:",omitempty"` } From 7ce67b895457339b33b0560bd3f5cc346da432e1 Mon Sep 17 00:00:00 2001 From: Steven Allen Date: Mon, 15 Jun 2020 19:19:01 -0700 Subject: [PATCH 214/414] go-ipfs-config: feat: add WithDefault for flag/priority This makes it easier to resolve these fields. --- config/types.go | 30 ++++++++++++++++++++++++++++++ config/types_test.go | 36 ++++++++++++++++++++++++++++++++++++ 2 files changed, 66 insertions(+) diff --git a/config/types.go b/config/types.go index 60c4c77d5f7..57d8a59ec81 100644 --- a/config/types.go +++ b/config/types.go @@ -55,6 +55,19 @@ const ( True Flag = 1 ) +func (f Flag) WithDefault(defaultValue bool) bool { + switch f { + case False: + return false + case Default: + return defaultValue + case True: + return true + default: + panic(fmt.Sprintf("invalid flag value %d", f)) + } +} + func (f Flag) MarshalJSON() ([]byte, error) { switch f { case Default: @@ -110,6 +123,23 @@ const ( Disabled Priority = -1 ) +// WithDefault resolves the priority with the given default. +// +// If `defaultPriority` is Default/0, this function will return 0. +func (p Priority) WithDefault(defaultPriority Priority) (priority int64, enabled bool) { + switch p { + case Disabled: + return 0, false + case DefaultPriority: + if defaultPriority < 0 { + return 0, false + } + return int64(defaultPriority), true + default: + return int64(p), true + } +} + func (p Priority) MarshalJSON() ([]byte, error) { // > 0 == Priority if p > 0 { diff --git a/config/types_test.go b/config/types_test.go index dbc08cb888f..8d4c62fd2aa 100644 --- a/config/types_test.go +++ b/config/types_test.go @@ -91,6 +91,30 @@ func TestFlag(t *testing.T) { t.Errorf("expected default flag to be %q, got %q", Default, defaultFlag) } + if defaultFlag.WithDefault(true) != true { + t.Error("expected default & true to be true") + } + + if defaultFlag.WithDefault(false) != false { + t.Error("expected default & false to be false") + } + + if True.WithDefault(false) != true { + t.Error("default should only apply to default") + } + + if False.WithDefault(true) != false { + t.Error("default should only apply to default") + } + + if True.WithDefault(true) != true { + t.Error("true & true is true") + } + + if False.WithDefault(true) != false { + t.Error("false & false is false") + } + for jsonStr, goValue := range map[string]Flag{ "null": Default, "true": True, @@ -135,6 +159,18 @@ func TestPriority(t *testing.T) { t.Errorf("expected default priority to be %q, got %q", DefaultPriority, defaultPriority) } + if _, ok := defaultPriority.WithDefault(Disabled); ok { + t.Error("should have been disabled") + } + + if p, ok := defaultPriority.WithDefault(1); !ok || p != 1 { + t.Errorf("priority should have been 1, got %d", p) + } + + if p, ok := defaultPriority.WithDefault(DefaultPriority); !ok || p != 0 { + t.Errorf("priority should have been 0, got %d", p) + } + for jsonStr, goValue := range map[string]Priority{ "null": DefaultPriority, "false": Disabled, From 0f17ef601f60da9e358cc6604a0de3329e865ca2 Mon Sep 17 00:00:00 2001 From: Steven Allen Date: Mon, 15 Jun 2020 19:55:50 -0700 Subject: [PATCH 215/414] go-ipfs-config: doc(swarm): fix autorelay description Co-authored-by: Adin Schmahmann --- config/swarm.go | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/config/swarm.go b/config/swarm.go index dc54ae902b2..bc01e88efd4 100644 --- a/config/swarm.go +++ b/config/swarm.go @@ -25,8 +25,8 @@ type SwarmConfig struct { // EnableAutoRelay enables the "auto relay" feature. // - // When both EnableAutoRelay and RelayHop are set, this go-ipfs node - // will advertise itself as a public relay, instead of finding and using + // When both EnableAutoRelay and EnableRelayHop are set, this go-ipfs node + // will advertise itself as a public relay. Otherwise it will find and use // advertised public relays. EnableAutoRelay bool From f74d15eacfe0ec256b3bc631217e1df5744b6959 Mon Sep 17 00:00:00 2001 From: Steven Allen Date: Mon, 15 Jun 2020 19:56:38 -0700 Subject: [PATCH 216/414] go-ipfs-config: fix: fix type name typo --- config/swarm.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/config/swarm.go b/config/swarm.go index bc01e88efd4..7ce55bec855 100644 --- a/config/swarm.go +++ b/config/swarm.go @@ -61,7 +61,7 @@ type Transports struct { // Multiplexers specifies the transports used to multiplex multiple // connections over a single duplex connection. - Multiplex struct { + Multiplexers struct { // Defaults to 100. Yamux Priority `json:",omitempty"` // Defaults to 200. From f55b515255aeffef58ada9eb399396e7c2bff4d2 Mon Sep 17 00:00:00 2001 From: Steven Allen Date: Mon, 15 Jun 2020 19:57:41 -0700 Subject: [PATCH 217/414] go-ipfs-config: doc(swarm): extend autorelay docs --- config/swarm.go | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/config/swarm.go b/config/swarm.go index 7ce55bec855..d662bb30d44 100644 --- a/config/swarm.go +++ b/config/swarm.go @@ -27,7 +27,8 @@ type SwarmConfig struct { // // When both EnableAutoRelay and EnableRelayHop are set, this go-ipfs node // will advertise itself as a public relay. Otherwise it will find and use - // advertised public relays. + // advertised public relays when it determines that it's not reachable + // from the public internet. EnableAutoRelay bool // Transports contains flags to enable/disable libp2p transports. From e26444e4c78eff5c311f5a245717ee34f871d4c0 Mon Sep 17 00:00:00 2001 From: Steven Allen Date: Mon, 15 Jun 2020 20:00:51 -0700 Subject: [PATCH 218/414] go-ipfs-config: fix typo Co-authored-by: Adin Schmahmann --- config/types.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/config/types.go b/config/types.go index 57d8a59ec81..3d5418a2c88 100644 --- a/config/types.go +++ b/config/types.go @@ -111,7 +111,7 @@ func (f Flag) String() string { var _ json.Unmarshaler = (*Flag)(nil) var _ json.Marshaler = (*Flag)(nil) -// Priority represents a value with a priority where 0 means "default" and -11 +// Priority represents a value with a priority where 0 means "default" and -1 // means "disabled". // // When encoded in json, Default is encoded as "null" and Disabled is encoded as From 5c1b4cd0e686cd41d6cbf48a324b45e5209f3407 Mon Sep 17 00:00:00 2001 From: Steven Allen Date: Mon, 15 Jun 2020 20:01:33 -0700 Subject: [PATCH 219/414] go-ipfs-config: doc: document Flag.WithDefault --- config/types.go | 1 + 1 file changed, 1 insertion(+) diff --git a/config/types.go b/config/types.go index 3d5418a2c88..979182233bd 100644 --- a/config/types.go +++ b/config/types.go @@ -55,6 +55,7 @@ const ( True Flag = 1 ) +// WithDefault resolves the value of the flag given the provided default value. func (f Flag) WithDefault(defaultValue bool) bool { switch f { case False: From 38ad98d84d1d00b02ad64fbf53cc6bd1612e1fc8 Mon Sep 17 00:00:00 2001 From: Steven Allen Date: Tue, 16 Jun 2020 00:45:58 -0700 Subject: [PATCH 220/414] go-ipfs-config: fix: remove undefined support from unmarshal It's not a part of the JSON spec. --- config/types.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/config/types.go b/config/types.go index 979182233bd..2ca65540882 100644 --- a/config/types.go +++ b/config/types.go @@ -84,7 +84,7 @@ func (f Flag) MarshalJSON() ([]byte, error) { func (f *Flag) UnmarshalJSON(input []byte) error { switch string(input) { - case "null", "undefined": + case "null": *f = Default case "false": *f = False From 44e005e57709ee7e1b95270476d8a32aa0d23076 Mon Sep 17 00:00:00 2001 From: Steven Allen Date: Tue, 16 Jun 2020 10:17:06 -0700 Subject: [PATCH 221/414] go-ipfs-config: fix: panic on invalid priority/flag values --- config/types.go | 21 ++++++++++++++++++--- 1 file changed, 18 insertions(+), 3 deletions(-) diff --git a/config/types.go b/config/types.go index 2ca65540882..d22fd5dfad5 100644 --- a/config/types.go +++ b/config/types.go @@ -56,6 +56,8 @@ const ( ) // WithDefault resolves the value of the flag given the provided default value. +// +// Panics if Flag is an invalid value. func (f Flag) WithDefault(defaultValue bool) bool { switch f { case False: @@ -126,17 +128,30 @@ const ( // WithDefault resolves the priority with the given default. // -// If `defaultPriority` is Default/0, this function will return 0. +// If defaultPriority is Default/0, this function will return 0. +// +// Panics if the priority has an invalid value (e.g., not DefaultPriority, +// Disabled, or > 0). func (p Priority) WithDefault(defaultPriority Priority) (priority int64, enabled bool) { switch p { case Disabled: return 0, false case DefaultPriority: - if defaultPriority < 0 { + switch defaultPriority { + case Disabled: return 0, false + case DefaultPriority: + return 0, true + default: + if defaultPriority <= 0 { + panic(fmt.Sprintf("invalid priority %d < 0", int64(defaultPriority))) + } + return int64(defaultPriority), true } - return int64(defaultPriority), true default: + if p <= 0 { + panic(fmt.Sprintf("invalid priority %d < 0", int64(p))) + } return int64(p), true } } From da979299da9b12a2808c28af5650cae53708d4cf Mon Sep 17 00:00:00 2001 From: Petar Maymounkov Date: Tue, 14 Jul 2020 09:50:10 -0700 Subject: [PATCH 222/414] go-ipfs-config: error if bit size specified with ed25519 keys (#105) --- config/init.go | 3 +++ config/init_test.go | 13 +++++++++++++ 2 files changed, 16 insertions(+) diff --git a/config/init.go b/config/init.go index 2d2e2e6ef9d..448fffa73c1 100644 --- a/config/init.go +++ b/config/init.go @@ -200,6 +200,9 @@ func CreateIdentity(out io.Writer, opts []options.KeyGenerateOption) (Identity, sk = priv pk = pub case "ed25519": + if settings.Size != -1 { + return ident, fmt.Errorf("number of key bits does not apply when using ed25519 keys") + } fmt.Fprintf(out, "generating ED25519 keypair...") priv, pub, err := ci.GenerateEd25519Key(rand.Reader) if err != nil { diff --git a/config/init_test.go b/config/init_test.go index 635c78afc5c..3e66e60cd2c 100644 --- a/config/init_test.go +++ b/config/init_test.go @@ -34,3 +34,16 @@ func TestCreateIdentity(t *testing.T) { t.Fatal("unexpected type:", pk.Type()) } } + +func TestCreateIdentityOptions(t *testing.T) { + var w bytes.Buffer + + // ed25519 keys with bit size must fail. + _, err := CreateIdentity(&w, []options.KeyGenerateOption{ + options.Key.Type(options.Ed25519Key), + options.Key.Size(2048), + }) + if err == nil { + t.Errorf("ed25519 keys cannot have a custom bit size") + } +} From 1ec9262cdaac5547b88bb6b5f600a75a327f5456 Mon Sep 17 00:00:00 2001 From: gammazero Date: Thu, 24 Sep 2020 05:21:22 -0700 Subject: [PATCH 223/414] go-ipfs-config: Add badger2 profile and config spec --- config/init.go | 13 +++++++++++++ config/profile.go | 25 +++++++++++++++++++++++-- 2 files changed, 36 insertions(+), 2 deletions(-) diff --git a/config/init.go b/config/init.go index 448fffa73c1..32d5a1f222b 100644 --- a/config/init.go +++ b/config/init.go @@ -142,6 +142,19 @@ func badgerSpec() map[string]interface{} { } } +func badger2Spec() map[string]interface{} { + return map[string]interface{}{ + "type": "measure", + "prefix": "badger2.datastore", + "child": map[string]interface{}{ + "type": "badger2ds", + "path": "badger2ds", + "syncWrites": false, + "truncate": true, + }, + } +} + func flatfsSpec() map[string]interface{} { return map[string]interface{}{ "type": "mount", diff --git a/config/profile.go b/config/profile.go index 697ca305aea..ba101331629 100644 --- a/config/profile.go +++ b/config/profile.go @@ -130,7 +130,7 @@ This profile may only be applied when first initializing the node. This is the most battle-tested and reliable datastore, but it's significantly slower than the badger datastore. You should use this datastore if: -* You need a very simple and very reliable datastore you and trust your +* You need a very simple and very reliable datastore and you trust your filesystem. This datastore stores each block as a separate file in the underlying filesystem so it's unlikely to loose data unless there's an issue with the underlying file system. @@ -152,7 +152,7 @@ This profile may only be applied when first initializing the node. "badgerds": { Description: `Configures the node to use the badger datastore. -This is the fastest datastore. Use this datastore if performance, especially +This is a fast datastore. Use this datastore if performance, especially when adding many gigabytes of files, is critical. However: * This datastore will not properly reclaim space when your datastore is @@ -170,6 +170,27 @@ This profile may only be applied when first initializing the node.`, return nil }, }, + "badger2ds": { + Description: `Configures the node to use the badger2 datastore. + +This is the fastest datastore. Use this datastore if performance, especially +when adding many gigabytes of files, is critical. However: + +* This datastore will not properly reclaim space when your datastore is + smaller than several gigabytes. If you run IPFS with '--enable-gc' (you have + enabled block-level garbage collection), you plan on storing very little data in + your IPFS node, and disk usage is more critical than performance, consider using + flatfs. +* This datastore uses up to several gigabytes of memory. + +This profile may only be applied when first initializing the node.`, + + InitOnly: true, + Transform: func(c *Config) error { + c.Datastore.Spec = badger2Spec() + return nil + }, + }, "lowpower": { Description: `Reduces daemon overhead on the system. May affect node functionality - performance of content discovery and data From 74dcf427fcbb9389574294a7e3ec6ed6a9dcaed7 Mon Sep 17 00:00:00 2001 From: gammazero Date: Mon, 23 Nov 2020 17:09:21 -0800 Subject: [PATCH 224/414] go-ipfs-config: Remove badger2 profile This is needed for the upcoming release since there is not yet an official badger2 release with the items needed for use by IPFS. --- config/init.go | 13 ------------- config/profile.go | 23 +---------------------- 2 files changed, 1 insertion(+), 35 deletions(-) diff --git a/config/init.go b/config/init.go index 32d5a1f222b..448fffa73c1 100644 --- a/config/init.go +++ b/config/init.go @@ -142,19 +142,6 @@ func badgerSpec() map[string]interface{} { } } -func badger2Spec() map[string]interface{} { - return map[string]interface{}{ - "type": "measure", - "prefix": "badger2.datastore", - "child": map[string]interface{}{ - "type": "badger2ds", - "path": "badger2ds", - "syncWrites": false, - "truncate": true, - }, - } -} - func flatfsSpec() map[string]interface{} { return map[string]interface{}{ "type": "mount", diff --git a/config/profile.go b/config/profile.go index ba101331629..c0fa947f164 100644 --- a/config/profile.go +++ b/config/profile.go @@ -152,27 +152,6 @@ This profile may only be applied when first initializing the node. "badgerds": { Description: `Configures the node to use the badger datastore. -This is a fast datastore. Use this datastore if performance, especially -when adding many gigabytes of files, is critical. However: - -* This datastore will not properly reclaim space when your datastore is - smaller than several gigabytes. If you run IPFS with '--enable-gc' (you have - enabled block-level garbage collection), you plan on storing very little data in - your IPFS node, and disk usage is more critical than performance, consider using - flatfs. -* This datastore uses up to several gigabytes of memory. - -This profile may only be applied when first initializing the node.`, - - InitOnly: true, - Transform: func(c *Config) error { - c.Datastore.Spec = badgerSpec() - return nil - }, - }, - "badger2ds": { - Description: `Configures the node to use the badger2 datastore. - This is the fastest datastore. Use this datastore if performance, especially when adding many gigabytes of files, is critical. However: @@ -187,7 +166,7 @@ This profile may only be applied when first initializing the node.`, InitOnly: true, Transform: func(c *Config) error { - c.Datastore.Spec = badger2Spec() + c.Datastore.Spec = badgerSpec() return nil }, }, From 06fe9679550d1cb5b5e19cca2b87ede7aa1e9a91 Mon Sep 17 00:00:00 2001 From: Adin Schmahmann Date: Fri, 4 Dec 2020 15:51:38 -0500 Subject: [PATCH 225/414] go-ipfs-config: add remote pinning services config --- config/config.go | 1 + config/remotepin.go | 20 ++++++++++++++++++++ 2 files changed, 21 insertions(+) create mode 100644 config/remotepin.go diff --git a/config/config.go b/config/config.go index 5f6be8e5ac5..7d44316abd3 100644 --- a/config/config.go +++ b/config/config.go @@ -33,6 +33,7 @@ type Config struct { Reprovider Reprovider Experimental Experiments Plugins Plugins + Pinning Pinning } const ( diff --git a/config/remotepin.go b/config/remotepin.go new file mode 100644 index 00000000000..9da2af1bf0b --- /dev/null +++ b/config/remotepin.go @@ -0,0 +1,20 @@ +package config + +const ( + PinningTag = "Pinning" + RemoteServicesTag = "RemoteServices" + RemoteServicesSelector = PinningTag + "." + RemoteServicesTag +) + +type Pinning struct { + RemoteServices map[string]RemotePinningService +} + +type RemotePinningService struct { + Api RemotePinningServiceApi +} + +type RemotePinningServiceApi struct { + Endpoint string + Key string +} From d643a2bce4e92b5ec980588c9d58def491008e6e Mon Sep 17 00:00:00 2001 From: Adin Schmahmann Date: Fri, 4 Dec 2020 15:52:59 -0500 Subject: [PATCH 226/414] go-ipfs-config: go fmt --- config/bootstrap_peers.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/config/bootstrap_peers.go b/config/bootstrap_peers.go index 55d0f3b822f..27715843da0 100644 --- a/config/bootstrap_peers.go +++ b/config/bootstrap_peers.go @@ -19,7 +19,7 @@ var DefaultBootstrapAddresses = []string{ "/dnsaddr/bootstrap.libp2p.io/p2p/QmQCU2EcMqAqQPR2i9bChDtGNJchTbq5TbXJJ16u19uLTa", "/dnsaddr/bootstrap.libp2p.io/p2p/QmbLHAnMoJPWSCR5Zhtx6BHJX9KiKNN6tpvbUcqanj75Nb", "/dnsaddr/bootstrap.libp2p.io/p2p/QmcZf59bWwK5XFi76CZX8cbJ4BhTzzA3gU1ZjYZcYW3dwt", - "/ip4/104.131.131.82/tcp/4001/p2p/QmaCpDMGvV2BGHeYERUEnRQAwe3N8SzbUtfsmvsqQLuvuJ", // mars.i.ipfs.io + "/ip4/104.131.131.82/tcp/4001/p2p/QmaCpDMGvV2BGHeYERUEnRQAwe3N8SzbUtfsmvsqQLuvuJ", // mars.i.ipfs.io "/ip4/104.131.131.82/udp/4001/quic/p2p/QmaCpDMGvV2BGHeYERUEnRQAwe3N8SzbUtfsmvsqQLuvuJ", // mars.i.ipfs.io } From 2690c10bcacc6c5c286dcc6f2f3137dc1cf879a5 Mon Sep 17 00:00:00 2001 From: Adin Schmahmann Date: Thu, 28 Jan 2021 18:05:47 -0500 Subject: [PATCH 227/414] go-ipfs-config: add support for pinning mfs (#116) * add support for pinning mfs * add pin conceal selector * add RemoteServicesPath Co-authored-by: Petar Maymounkov --- config/init.go | 3 +++ config/remotepin.go | 25 +++++++++++++++++++------ 2 files changed, 22 insertions(+), 6 deletions(-) diff --git a/config/init.go b/config/init.go index 448fffa73c1..ecda3047ddb 100644 --- a/config/init.go +++ b/config/init.go @@ -86,6 +86,9 @@ func InitWithIdentity(identity Identity) (*Config, error) { Type: "basic", }, }, + Pinning: Pinning{ + RemoteServices: map[string]RemotePinningService{}, + }, } return conf, nil diff --git a/config/remotepin.go b/config/remotepin.go index 9da2af1bf0b..135aa664d17 100644 --- a/config/remotepin.go +++ b/config/remotepin.go @@ -1,9 +1,8 @@ package config -const ( - PinningTag = "Pinning" - RemoteServicesTag = "RemoteServices" - RemoteServicesSelector = PinningTag + "." + RemoteServicesTag +var ( + RemoteServicesPath = "Pinning.RemoteServices" + PinningConcealSelector = []string{"Pinning", "RemoteServices", "*", "API", "Key"} ) type Pinning struct { @@ -11,10 +10,24 @@ type Pinning struct { } type RemotePinningService struct { - Api RemotePinningServiceApi + API RemotePinningServiceAPI + Policies RemotePinningServicePolicies } -type RemotePinningServiceApi struct { +type RemotePinningServiceAPI struct { Endpoint string Key string } + +type RemotePinningServicePolicies struct { + MFS RemotePinningServiceMFSPolicy +} + +type RemotePinningServiceMFSPolicy struct { + // Enable enables watching for changes in MFS and re-pinning the MFS root cid whenever a change occurs. + Enable bool + // Name is the pin name for MFS. + PinName string + // RepinInterval determines the repin interval when the policy is enabled. In ns, us, ms, s, m, h. + RepinInterval string +} From f5fb70ee0faf3d5891c4292d6cc734f5a7eb9983 Mon Sep 17 00:00:00 2001 From: "@RubenKelevra" Date: Wed, 24 Mar 2021 12:44:46 +0100 Subject: [PATCH 228/414] go-ipfs-config: remove duplicate entries in defaultServerFilters --- config/profile.go | 4 ---- 1 file changed, 4 deletions(-) diff --git a/config/profile.go b/config/profile.go index c0fa947f164..1d379d97db0 100644 --- a/config/profile.go +++ b/config/profile.go @@ -30,10 +30,6 @@ var defaultServerFilters = []string{ "/ip4/169.254.0.0/ipcidr/16", "/ip4/172.16.0.0/ipcidr/12", "/ip4/192.0.0.0/ipcidr/24", - "/ip4/192.0.0.0/ipcidr/29", - "/ip4/192.0.0.8/ipcidr/32", - "/ip4/192.0.0.170/ipcidr/32", - "/ip4/192.0.0.171/ipcidr/32", "/ip4/192.0.2.0/ipcidr/24", "/ip4/192.168.0.0/ipcidr/16", "/ip4/198.18.0.0/ipcidr/15", From 8a8b161da461c8e340f7a37178df3e1ea882fad9 Mon Sep 17 00:00:00 2001 From: vyzo Date: Mon, 12 Apr 2021 13:53:19 +0300 Subject: [PATCH 229/414] go-ipfs-config: add custom DNS Resolver configuration --- config/config.go | 1 + config/dns.go | 10 ++++++++++ 2 files changed, 11 insertions(+) create mode 100644 config/dns.go diff --git a/config/config.go b/config/config.go index 7d44316abd3..d9b060e64b8 100644 --- a/config/config.go +++ b/config/config.go @@ -28,6 +28,7 @@ type Config struct { AutoNAT AutoNATConfig Pubsub PubsubConfig Peering Peering + DNS DNSConfig Provider Provider Reprovider Reprovider diff --git a/config/dns.go b/config/dns.go new file mode 100644 index 00000000000..5f18a9c6940 --- /dev/null +++ b/config/dns.go @@ -0,0 +1,10 @@ +package config + +// DNSConfig specifies custom resolvers using DoH +type DNSConfig struct { + // DefaultResolver, if present, is a URL for the default DoH resolver. + // If empty, DNS resolution will use the system resolver. + DefaultResolver string `json:",omitempty"` + // CustomResolvers is a map of domains to URLs for custom DoH resolution. + CustomResolvers map[string]string `json:",omitempty"` +} From 28553d793ad0e52129102d094b249a0893ee96c5 Mon Sep 17 00:00:00 2001 From: vyzo Date: Tue, 13 Apr 2021 17:32:15 +0300 Subject: [PATCH 230/414] go-ipfs-config: simplify DNS config --- config/dns.go | 9 +++------ 1 file changed, 3 insertions(+), 6 deletions(-) diff --git a/config/dns.go b/config/dns.go index 5f18a9c6940..ae390d91c62 100644 --- a/config/dns.go +++ b/config/dns.go @@ -1,10 +1,7 @@ package config -// DNSConfig specifies custom resolvers using DoH +// DNSConfig specifies DNS resolution rules using custom resolvers type DNSConfig struct { - // DefaultResolver, if present, is a URL for the default DoH resolver. - // If empty, DNS resolution will use the system resolver. - DefaultResolver string `json:",omitempty"` - // CustomResolvers is a map of domains to URLs for custom DoH resolution. - CustomResolvers map[string]string `json:",omitempty"` + // CustomResolvers is a map of FQDNs to URLs for custom DNS resolution. + Resolvers map[string]string } From f264de41392227173da5ec44d929831d37d60161 Mon Sep 17 00:00:00 2001 From: vyzo Date: Tue, 13 Apr 2021 17:53:47 +0300 Subject: [PATCH 231/414] go-ipfs-config: update comments Co-authored-by: Marcin Rataj --- config/dns.go | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/config/dns.go b/config/dns.go index ae390d91c62..aadea8904c0 100644 --- a/config/dns.go +++ b/config/dns.go @@ -2,6 +2,14 @@ package config // DNSConfig specifies DNS resolution rules using custom resolvers type DNSConfig struct { - // CustomResolvers is a map of FQDNs to URLs for custom DNS resolution. + // Resolvers is a map of FQDNs to URLs for custom DNS resolution. + // URLs starting with `https://` indicate DoH endpoints. + // Support for other resolver types can be added in the future. + // https://en.wikipedia.org/wiki/Fully_qualified_domain_name + // https://en.wikipedia.org/wiki/DNS_over_HTTPS + // + // Example: + // - Custom resolver for ENS: `eth.` → `https://eth.link/dns-query` + // - Override the default OS resolver: `.` → `https://doh.applied-privacy.net/query` Resolvers map[string]string } From c932e6b7008901e2dea8e8dd4e4bafa9fb2fe77d Mon Sep 17 00:00:00 2001 From: vyzo Date: Wed, 14 Apr 2021 18:46:35 +0300 Subject: [PATCH 232/414] go-ipfs-config: add default empty config for DNS, rename struct from DNSConfig to DNS --- config/config.go | 2 +- config/dns.go | 10 +++++----- config/init.go | 3 +++ 3 files changed, 9 insertions(+), 6 deletions(-) diff --git a/config/config.go b/config/config.go index d9b060e64b8..b593e7a7e36 100644 --- a/config/config.go +++ b/config/config.go @@ -28,7 +28,7 @@ type Config struct { AutoNAT AutoNATConfig Pubsub PubsubConfig Peering Peering - DNS DNSConfig + DNS DNS Provider Provider Reprovider Reprovider diff --git a/config/dns.go b/config/dns.go index aadea8904c0..5c4e62da0cc 100644 --- a/config/dns.go +++ b/config/dns.go @@ -1,13 +1,13 @@ package config -// DNSConfig specifies DNS resolution rules using custom resolvers -type DNSConfig struct { - // Resolvers is a map of FQDNs to URLs for custom DNS resolution. +// DNS specifies DNS resolution rules using custom resolvers +type DNS struct { + // Resolvers is a map of FQDNs to URLs for custom DNS resolution. // URLs starting with `https://` indicate DoH endpoints. // Support for other resolver types can be added in the future. // https://en.wikipedia.org/wiki/Fully_qualified_domain_name - // https://en.wikipedia.org/wiki/DNS_over_HTTPS - // + // https://en.wikipedia.org/wiki/DNS_over_HTTPS + // // Example: // - Custom resolver for ENS: `eth.` → `https://eth.link/dns-query` // - Override the default OS resolver: `.` → `https://doh.applied-privacy.net/query` diff --git a/config/init.go b/config/init.go index ecda3047ddb..56a99884fa8 100644 --- a/config/init.go +++ b/config/init.go @@ -89,6 +89,9 @@ func InitWithIdentity(identity Identity) (*Config, error) { Pinning: Pinning{ RemoteServices: map[string]RemotePinningService{}, }, + DNS: DNS{ + Resolvers: map[string]string{}, + }, } return conf, nil From 67456e2e647a28080259b6f38eb59b0a911070b4 Mon Sep 17 00:00:00 2001 From: gammazero Date: Fri, 16 Apr 2021 17:22:03 -0700 Subject: [PATCH 233/414] go-ipfs-config: Add config for downloading repo migrations --- config/config.go | 1 + config/init.go | 4 ++++ config/migration.go | 22 ++++++++++++++++++++++ 3 files changed, 27 insertions(+) create mode 100644 config/migration.go diff --git a/config/config.go b/config/config.go index b593e7a7e36..5a603015ce8 100644 --- a/config/config.go +++ b/config/config.go @@ -29,6 +29,7 @@ type Config struct { Pubsub PubsubConfig Peering Peering DNS DNS + Migration Migration Provider Provider Reprovider Reprovider diff --git a/config/init.go b/config/init.go index 56a99884fa8..db0eff5f284 100644 --- a/config/init.go +++ b/config/init.go @@ -92,6 +92,10 @@ func InitWithIdentity(identity Identity) (*Config, error) { DNS: DNS{ Resolvers: map[string]string{}, }, + Migration: Migration{ + DownloadSources: DefaultMigrationDownloadSources, + Keep: DefaultMigrationKeep, + }, } return conf, nil diff --git a/config/migration.go b/config/migration.go new file mode 100644 index 00000000000..e55734f88c7 --- /dev/null +++ b/config/migration.go @@ -0,0 +1,22 @@ +package config + +import "github.com/libp2p/go-libp2p-core/peer" + +const DefaultMigrationKeep = "cache" + +var DefaultMigrationDownloadSources = []string{"HTTPS", "IPFS"} + +// Migration configures how migrations are downloaded and if the downloads are +// added to IPFS locally +type Migration struct { + // Sources in order of preference where "HTTPS" means our gateways and + // "IPFS" means over IPFS. Any other values are interpretes as hostnames + // for custom gateways. An empty list means "do the default thing" + DownloadSources []string + // Whether or not to keep the migration after downloading it. + // Options are "discard", "cache", "pin". Empty string for default. + Keep string + // Peers lists the nodes to attempt to connect with when downloading + // migrations. + Peers []peer.AddrInfo +} From 5e6df6f54a5467f540e15624909487776cb77508 Mon Sep 17 00:00:00 2001 From: gammazero Date: Sat, 17 Apr 2021 18:19:05 -0700 Subject: [PATCH 234/414] go-ipfs-config: unit test for migration config --- config/migration_test.go | 70 ++++++++++++++++++++++++++++++++++++++++ 1 file changed, 70 insertions(+) create mode 100644 config/migration_test.go diff --git a/config/migration_test.go b/config/migration_test.go new file mode 100644 index 00000000000..47e2bed2aca --- /dev/null +++ b/config/migration_test.go @@ -0,0 +1,70 @@ +package config + +import ( + "encoding/json" + "testing" +) + +func TestMigrationDecode(t *testing.T) { + str := ` + { + "DownloadSources": ["IPFS", "HTTP", "127.0.0.1"], + "Keep": "cache", + "Peers": [ + { + "ID": "12D3KooWGC6TvWhfapngX6wvJHMYvKpDMXPb3ZnCZ6dMoaMtimQ5", + "Addrs": ["/ip4/127.0.0.1/tcp/4001", "/ip4/127.0.0.1/udp/4001/quic"] + }, + { + "ID": "12D3KooWGC6TvWhfajpgX6wvJHMYvKpDMXPb3ZnCZ6dMoaMtimQ7", + "Addrs": ["/ip4/10.0.0.2/tcp/4001"] + } + ] + } + ` + + var cfg Migration + if err := json.Unmarshal([]byte(str), &cfg); err != nil { + t.Errorf("failed while unmarshalling migration struct: %s", err) + } + + if len(cfg.DownloadSources) != 3 { + t.Fatal("wrong number of DownloadSources") + } + expect := []string{"IPFS", "HTTP", "127.0.0.1"} + for i := range expect { + if cfg.DownloadSources[i] != expect[i] { + t.Errorf("wrong DownloadSource at %d", i) + } + } + + if cfg.Keep != "cache" { + t.Error("wrong value for Keep") + } + + if len(cfg.Peers) != 2 { + t.Fatal("wrong number of peers") + } + + peer := cfg.Peers[0] + if peer.ID.String() != "12D3KooWGC6TvWhfapngX6wvJHMYvKpDMXPb3ZnCZ6dMoaMtimQ5" { + t.Errorf("wrong ID for first peer") + } + if len(peer.Addrs) != 2 { + t.Error("wrong number of addrs for first peer") + } + if peer.Addrs[0].String() != "/ip4/127.0.0.1/tcp/4001" { + t.Error("wrong first addr for first peer") + } + if peer.Addrs[1].String() != "/ip4/127.0.0.1/udp/4001/quic" { + t.Error("wrong second addr for first peer") + } + + peer = cfg.Peers[1] + if len(peer.Addrs) != 1 { + t.Fatal("wrong number of addrs for second peer") + } + if peer.Addrs[0].String() != "/ip4/10.0.0.2/tcp/4001" { + t.Error("wrong first addr for second peer") + } +} From ec1659d79ace0c8688c348b0946c20ff408112e4 Mon Sep 17 00:00:00 2001 From: gammazero Date: Mon, 19 Apr 2021 23:41:54 -0700 Subject: [PATCH 235/414] go-ipfs-config: Init migration config with empty values --- config/init.go | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/config/init.go b/config/init.go index db0eff5f284..be07eec2404 100644 --- a/config/init.go +++ b/config/init.go @@ -93,8 +93,8 @@ func InitWithIdentity(identity Identity) (*Config, error) { Resolvers: map[string]string{}, }, Migration: Migration{ - DownloadSources: DefaultMigrationDownloadSources, - Keep: DefaultMigrationKeep, + DownloadSources: []string{}, + Keep: "", }, } From dbb5fa78a59e09addf7368eff6aaefbbbf08c741 Mon Sep 17 00:00:00 2001 From: gammazero Date: Tue, 20 Apr 2021 00:29:38 -0700 Subject: [PATCH 236/414] go-ipfs-config: Fix comment --- config/migration.go | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/config/migration.go b/config/migration.go index e55734f88c7..24e92f73071 100644 --- a/config/migration.go +++ b/config/migration.go @@ -9,9 +9,9 @@ var DefaultMigrationDownloadSources = []string{"HTTPS", "IPFS"} // Migration configures how migrations are downloaded and if the downloads are // added to IPFS locally type Migration struct { - // Sources in order of preference where "HTTPS" means our gateways and - // "IPFS" means over IPFS. Any other values are interpretes as hostnames - // for custom gateways. An empty list means "do the default thing" + // Sources in order of preference, where "IPFS" means use IPFS and "HTTPS" + // means use default gateways. Any other values are interpreted as + // hostnames for custom gateways. Empty list means "use default sources". DownloadSources []string // Whether or not to keep the migration after downloading it. // Options are "discard", "cache", "pin". Empty string for default. From 4b778ce3267b6e5ce5f69cf57d1217218bdf01a4 Mon Sep 17 00:00:00 2001 From: gammazero Date: Mon, 3 May 2021 09:08:16 -0700 Subject: [PATCH 237/414] go-ipfs-config: Removed Peers from migration config --- config/migration.go | 5 ----- config/migration_test.go | 38 +------------------------------------- 2 files changed, 1 insertion(+), 42 deletions(-) diff --git a/config/migration.go b/config/migration.go index 24e92f73071..27d4b3c7025 100644 --- a/config/migration.go +++ b/config/migration.go @@ -1,7 +1,5 @@ package config -import "github.com/libp2p/go-libp2p-core/peer" - const DefaultMigrationKeep = "cache" var DefaultMigrationDownloadSources = []string{"HTTPS", "IPFS"} @@ -16,7 +14,4 @@ type Migration struct { // Whether or not to keep the migration after downloading it. // Options are "discard", "cache", "pin". Empty string for default. Keep string - // Peers lists the nodes to attempt to connect with when downloading - // migrations. - Peers []peer.AddrInfo } diff --git a/config/migration_test.go b/config/migration_test.go index 47e2bed2aca..a6cbd4438e7 100644 --- a/config/migration_test.go +++ b/config/migration_test.go @@ -9,17 +9,7 @@ func TestMigrationDecode(t *testing.T) { str := ` { "DownloadSources": ["IPFS", "HTTP", "127.0.0.1"], - "Keep": "cache", - "Peers": [ - { - "ID": "12D3KooWGC6TvWhfapngX6wvJHMYvKpDMXPb3ZnCZ6dMoaMtimQ5", - "Addrs": ["/ip4/127.0.0.1/tcp/4001", "/ip4/127.0.0.1/udp/4001/quic"] - }, - { - "ID": "12D3KooWGC6TvWhfajpgX6wvJHMYvKpDMXPb3ZnCZ6dMoaMtimQ7", - "Addrs": ["/ip4/10.0.0.2/tcp/4001"] - } - ] + "Keep": "cache" } ` @@ -41,30 +31,4 @@ func TestMigrationDecode(t *testing.T) { if cfg.Keep != "cache" { t.Error("wrong value for Keep") } - - if len(cfg.Peers) != 2 { - t.Fatal("wrong number of peers") - } - - peer := cfg.Peers[0] - if peer.ID.String() != "12D3KooWGC6TvWhfapngX6wvJHMYvKpDMXPb3ZnCZ6dMoaMtimQ5" { - t.Errorf("wrong ID for first peer") - } - if len(peer.Addrs) != 2 { - t.Error("wrong number of addrs for first peer") - } - if peer.Addrs[0].String() != "/ip4/127.0.0.1/tcp/4001" { - t.Error("wrong first addr for first peer") - } - if peer.Addrs[1].String() != "/ip4/127.0.0.1/udp/4001/quic" { - t.Error("wrong second addr for first peer") - } - - peer = cfg.Peers[1] - if len(peer.Addrs) != 1 { - t.Fatal("wrong number of addrs for second peer") - } - if peer.Addrs[0].String() != "/ip4/10.0.0.2/tcp/4001" { - t.Error("wrong first addr for second peer") - } } From 22d2b6b8b83b97551db2af2da657b2365bf2a3a6 Mon Sep 17 00:00:00 2001 From: Adin Schmahmann Date: Mon, 5 Apr 2021 12:51:52 -0400 Subject: [PATCH 238/414] go-ipfs-config: add option for Accelerated DHT Client experiment --- config/experiments.go | 1 + 1 file changed, 1 insertion(+) diff --git a/config/experiments.go b/config/experiments.go index d63580f26c0..c4f906394b5 100644 --- a/config/experiments.go +++ b/config/experiments.go @@ -8,4 +8,5 @@ type Experiments struct { Libp2pStreamMounting bool P2pHttpProxy bool StrategicProviding bool + AcceleratedDHTClient bool } From e7bb833760c70227ead661be55114181d5ff1030 Mon Sep 17 00:00:00 2001 From: Michael Burns <5170+mburns@users.noreply.github.com> Date: Fri, 14 May 2021 14:31:24 -0700 Subject: [PATCH 239/414] go-ipfs-config: [LINT] error strings should not end with punctuation or a newline (ST1005) --- config/bootstrap_peers.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/config/bootstrap_peers.go b/config/bootstrap_peers.go index 27715843da0..e22c55fb8a7 100644 --- a/config/bootstrap_peers.go +++ b/config/bootstrap_peers.go @@ -37,7 +37,7 @@ func DefaultBootstrapPeers() ([]peer.AddrInfo, error) { ps, err := ParseBootstrapPeers(DefaultBootstrapAddresses) if err != nil { return nil, fmt.Errorf(`failed to parse hardcoded bootstrap peers: %s -This is a problem with the ipfs codebase. Please report it to the dev team.`, err) +This is a problem with the ipfs codebase. Please report it to the dev team`, err) } return ps, nil } From 8f09fa547f53eae317c81e0b860f253c57a624fe Mon Sep 17 00:00:00 2001 From: web3-bot Date: Mon, 17 May 2021 17:00:43 +0000 Subject: [PATCH 240/414] go-ipfs-config: run gofmt -s --- config/init.go | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/config/init.go b/config/init.go index be07eec2404..13d40b6ddb8 100644 --- a/config/init.go +++ b/config/init.go @@ -68,9 +68,9 @@ func InitWithIdentity(identity Identity) (*Config, error) { NoFetch: false, PathPrefixes: []string{}, HTTPHeaders: map[string][]string{ - "Access-Control-Allow-Origin": []string{"*"}, - "Access-Control-Allow-Methods": []string{"GET"}, - "Access-Control-Allow-Headers": []string{"X-Requested-With", "Range", "User-Agent"}, + "Access-Control-Allow-Origin": {"*"}, + "Access-Control-Allow-Methods": {"GET"}, + "Access-Control-Allow-Headers": {"X-Requested-With", "Range", "User-Agent"}, }, APICommands: []string{}, }, From c692e73f3f9c27d43414923acff972b65df07361 Mon Sep 17 00:00:00 2001 From: Steven Allen Date: Thu, 22 Jul 2021 15:54:33 -0700 Subject: [PATCH 241/414] go-ipfs-config: fix: remove deprecated calls And rename imports. --- config/init.go | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/config/init.go b/config/init.go index 13d40b6ddb8..cf0cca5929a 100644 --- a/config/init.go +++ b/config/init.go @@ -8,8 +8,8 @@ import ( "time" "github.com/ipfs/interface-go-ipfs-core/options" - ci "github.com/libp2p/go-libp2p-core/crypto" - peer "github.com/libp2p/go-libp2p-core/peer" + "github.com/libp2p/go-libp2p-core/crypto" + "github.com/libp2p/go-libp2p-core/peer" ) func Init(out io.Writer, nBitsForKeypair int) (*Config, error) { @@ -191,8 +191,8 @@ func CreateIdentity(out io.Writer, opts []options.KeyGenerateOption) (Identity, return ident, err } - var sk ci.PrivKey - var pk ci.PubKey + var sk crypto.PrivKey + var pk crypto.PubKey switch settings.Algorithm { case "rsa": @@ -202,7 +202,7 @@ func CreateIdentity(out io.Writer, opts []options.KeyGenerateOption) (Identity, fmt.Fprintf(out, "generating %d-bit RSA keypair...", settings.Size) - priv, pub, err := ci.GenerateKeyPair(ci.RSA, settings.Size) + priv, pub, err := crypto.GenerateKeyPair(crypto.RSA, settings.Size) if err != nil { return ident, err } @@ -214,7 +214,7 @@ func CreateIdentity(out io.Writer, opts []options.KeyGenerateOption) (Identity, return ident, fmt.Errorf("number of key bits does not apply when using ed25519 keys") } fmt.Fprintf(out, "generating ED25519 keypair...") - priv, pub, err := ci.GenerateEd25519Key(rand.Reader) + priv, pub, err := crypto.GenerateEd25519Key(rand.Reader) if err != nil { return ident, err } @@ -228,7 +228,7 @@ func CreateIdentity(out io.Writer, opts []options.KeyGenerateOption) (Identity, // currently storing key unencrypted. in the future we need to encrypt it. // TODO(security) - skbytes, err := sk.Bytes() + skbytes, err := crypto.MarshalPrivateKey(sk) if err != nil { return ident, err } From 7c1029c5151a8890b2e8d2404a7aae70e74361da Mon Sep 17 00:00:00 2001 From: Adin Schmahmann Date: Wed, 11 Aug 2021 17:29:54 -0400 Subject: [PATCH 242/414] go-ipfs-config: fix: make sure the Priority type properly implements the JSON marshal/unmarshal interfaces --- config/types.go | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/config/types.go b/config/types.go index d22fd5dfad5..cf6e947caeb 100644 --- a/config/types.go +++ b/config/types.go @@ -208,8 +208,8 @@ func (p Priority) String() string { } } -var _ json.Unmarshaler = (*Flag)(nil) -var _ json.Marshaler = (*Flag)(nil) +var _ json.Unmarshaler = (*Priority)(nil) +var _ json.Marshaler = (*Priority)(nil) // Duration wraps time.Duration to provide json serialization and deserialization. // From ac81804c8c4b76aa1de7358abdd45c69ed53978a Mon Sep 17 00:00:00 2001 From: Adin Schmahmann Date: Mon, 16 Aug 2021 00:01:51 -0400 Subject: [PATCH 243/414] go-ipfs-config: feat: add an OptionalInteger type --- config/types.go | 52 +++++++++++++++++++++++++ config/types_test.go | 90 ++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 142 insertions(+) diff --git a/config/types.go b/config/types.go index cf6e947caeb..14b9f7cc020 100644 --- a/config/types.go +++ b/config/types.go @@ -232,3 +232,55 @@ func (d Duration) String() string { var _ encoding.TextUnmarshaler = (*Duration)(nil) var _ encoding.TextMarshaler = (*Duration)(nil) + +// OptionalInteger represents an integer that has a default value +// +// When encoded in json, Default is encoded as "null" +type OptionalInteger struct { + value *int64 +} + +// WithDefault resolves the integer with the given default. +func (p OptionalInteger) WithDefault(defaultValue int64) (value int64) { + if p.value == nil { + return defaultValue + } + return *p.value +} + +// IsDefault returns if this is a default optional integer +func (p OptionalInteger) IsDefault() bool { + return p.value == nil +} + +func (p OptionalInteger) MarshalJSON() ([]byte, error) { + if p.value != nil { + return json.Marshal(p.value) + } + return json.Marshal(nil) +} + +func (p *OptionalInteger) UnmarshalJSON(input []byte) error { + switch string(input) { + case "null", "undefined": + *p = OptionalInteger{} + default: + var value int64 + err := json.Unmarshal(input, &value) + if err != nil { + return err + } + *p = OptionalInteger{value: &value} + } + return nil +} + +func (p OptionalInteger) String() string { + if p.value == nil { + return "default" + } + return fmt.Sprintf("%d", p.value) +} + +var _ json.Unmarshaler = (*OptionalInteger)(nil) +var _ json.Marshaler = (*OptionalInteger)(nil) diff --git a/config/types_test.go b/config/types_test.go index 8d4c62fd2aa..94a7a633d07 100644 --- a/config/types_test.go +++ b/config/types_test.go @@ -218,3 +218,93 @@ func TestPriority(t *testing.T) { } } } + +func TestOptionalInteger(t *testing.T) { + makeInt64Pointer := func(v int64) *int64 { + return &v + } + + var defaultOptionalInt OptionalInteger + if !defaultOptionalInt.IsDefault() { + t.Fatal("should be the default") + } + if val := defaultOptionalInt.WithDefault(0); val != 0 { + t.Errorf("optional integer should have been 0, got %d", val) + } + + if val := defaultOptionalInt.WithDefault(1); val != 1 { + t.Errorf("optional integer should have been 1, got %d", val) + } + + if val := defaultOptionalInt.WithDefault(-1); val != -1 { + t.Errorf("optional integer should have been -1, got %d", val) + } + + var filledInt OptionalInteger + filledInt = OptionalInteger{value: makeInt64Pointer(1)} + if filledInt.IsDefault() { + t.Fatal("should not be the default") + } + if val := filledInt.WithDefault(0); val != 1 { + t.Errorf("optional integer should have been 1, got %d", val) + } + + if val := filledInt.WithDefault(-1); val != 1 { + t.Errorf("optional integer should have been 1, got %d", val) + } + + filledInt = OptionalInteger{value: makeInt64Pointer(0)} + if val := filledInt.WithDefault(1); val != 0 { + t.Errorf("optional integer should have been 0, got %d", val) + } + + for jsonStr, goValue := range map[string]OptionalInteger{ + "null": {}, + "0": {value: makeInt64Pointer(0)}, + "1": {value: makeInt64Pointer(1)}, + "-1": {value: makeInt64Pointer(-1)}, + } { + var d OptionalInteger + err := json.Unmarshal([]byte(jsonStr), &d) + if err != nil { + t.Fatal(err) + } + + if goValue.value == nil && d.value == nil { + } else if goValue.value == nil && d.value != nil { + t.Errorf("expected default, got %s", d) + } else if *d.value != *goValue.value { + t.Fatalf("expected %s, got %s", goValue, d) + } + + // Reverse + out, err := json.Marshal(goValue) + if err != nil { + t.Fatal(err) + } + if string(out) != jsonStr { + t.Fatalf("expected %s, got %s", jsonStr, string(out)) + } + } + + type Foo struct { + I *OptionalInteger `json:",omitempty"` + } + out, err := json.Marshal(new(Foo)) + if err != nil { + t.Fatal(err) + } + expected := "{}" + if string(out) != expected { + t.Fatal("expected omitempty to omit the optional integer") + } + for _, invalid := range []string{ + "foo", "-1.1", "1.1", "0.0", "[]", + } { + var p Priority + err := json.Unmarshal([]byte(invalid), &p) + if err == nil { + t.Errorf("expected to fail to decode %s as a priority", invalid) + } + } +} From 44291176e63ee0d4b666216670f75e258cb6022c Mon Sep 17 00:00:00 2001 From: Petar Maymounkov Date: Fri, 23 Jul 2021 09:29:33 -0400 Subject: [PATCH 244/414] go-ipfs-config: feat: add Internal and Internal.Bitswap config options --- config/config.go | 2 ++ config/internal.go | 12 ++++++++++++ 2 files changed, 14 insertions(+) create mode 100644 config/internal.go diff --git a/config/config.go b/config/config.go index 5a603015ce8..419a6a71f3a 100644 --- a/config/config.go +++ b/config/config.go @@ -36,6 +36,8 @@ type Config struct { Experimental Experiments Plugins Plugins Pinning Pinning + + Internal Internal // experimental/unstable options } const ( diff --git a/config/internal.go b/config/internal.go new file mode 100644 index 00000000000..2e71ac16eb7 --- /dev/null +++ b/config/internal.go @@ -0,0 +1,12 @@ +package config + +type Internal struct { + Bitswap *InternalBitswap `json:",omitempty"` // This is omitempty since we are expecting to make changes to all subcomponents of Internal +} + +type InternalBitswap struct { + TaskWorkerCount OptionalInteger + EngineBlockstoreWorkerCount OptionalInteger + EngineTaskWorkerCount OptionalInteger + MaxOutstandingBytesPerPeer OptionalInteger +} From 2cf170d5fae00da6625bb0831beb5c67a4f71ee1 Mon Sep 17 00:00:00 2001 From: Marten Seemann Date: Wed, 27 Oct 2021 18:23:35 +0200 Subject: [PATCH 245/414] go-ipfs-config: feat: add an OptionalDuration type (#148) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * feat: make it possible to define optional durations * test: empty/default optional durations does not crash if user restores default value and sets it to empty string "" * refactor: use null in JSON * refactor(duration): use JSON null as the default Rationale: https://github.com/ipfs/go-ipfs-config/pull/148#discussion_r736975879 * refactor: Duration → OptionalDuration This makes it possible to use OptionalDuration with `json:",omitempty"` so the null is not serialized to JSON, and get working WithDefault as well. Co-authored-by: Marcin Rataj --- config/autonat.go | 2 +- config/types.go | 57 ++++++++++++----- config/types_test.go | 144 ++++++++++++++++++++++++++++++++++--------- 3 files changed, 160 insertions(+), 43 deletions(-) diff --git a/config/autonat.go b/config/autonat.go index a1a3f699cda..64856faa680 100644 --- a/config/autonat.go +++ b/config/autonat.go @@ -77,5 +77,5 @@ type AutoNATThrottleConfig struct { // global/peer dialback limits. // // When unset, this defaults to 1 minute. - Interval Duration `json:",omitempty"` + Interval OptionalDuration `json:",omitempty"` } diff --git a/config/types.go b/config/types.go index 14b9f7cc020..ac90fa9b82a 100644 --- a/config/types.go +++ b/config/types.go @@ -1,9 +1,9 @@ package config import ( - "encoding" "encoding/json" "fmt" + "strings" "time" ) @@ -211,27 +211,56 @@ func (p Priority) String() string { var _ json.Unmarshaler = (*Priority)(nil) var _ json.Marshaler = (*Priority)(nil) -// Duration wraps time.Duration to provide json serialization and deserialization. +// OptionalDuration wraps time.Duration to provide json serialization and deserialization. // -// NOTE: the zero value encodes to an empty string. -type Duration time.Duration +// NOTE: the zero value encodes to JSON nill +type OptionalDuration struct { + value *time.Duration +} -func (d *Duration) UnmarshalText(text []byte) error { - dur, err := time.ParseDuration(string(text)) - *d = Duration(dur) - return err +func (d *OptionalDuration) UnmarshalJSON(input []byte) error { + switch string(input) { + case "null", "undefined", "\"null\"", "", "default", "\"\"", "\"default\"": + *d = OptionalDuration{} + return nil + default: + text := strings.Trim(string(input), "\"") + value, err := time.ParseDuration(text) + if err != nil { + return err + } + *d = OptionalDuration{value: &value} + return nil + } } -func (d Duration) MarshalText() ([]byte, error) { - return []byte(time.Duration(d).String()), nil +func (d *OptionalDuration) IsDefault() bool { + return d == nil || d.value == nil } -func (d Duration) String() string { - return time.Duration(d).String() +func (d *OptionalDuration) WithDefault(defaultValue time.Duration) time.Duration { + if d == nil || d.value == nil { + return defaultValue + } + return *d.value +} + +func (d OptionalDuration) MarshalJSON() ([]byte, error) { + if d.value == nil { + return json.Marshal(nil) + } + return json.Marshal(d.value.String()) +} + +func (d OptionalDuration) String() string { + if d.value == nil { + return "default" + } + return d.value.String() } -var _ encoding.TextUnmarshaler = (*Duration)(nil) -var _ encoding.TextMarshaler = (*Duration)(nil) +var _ json.Unmarshaler = (*OptionalDuration)(nil) +var _ json.Marshaler = (*OptionalDuration)(nil) // OptionalInteger represents an integer that has a default value // diff --git a/config/types_test.go b/config/types_test.go index 94a7a633d07..06ea73a260c 100644 --- a/config/types_test.go +++ b/config/types_test.go @@ -1,40 +1,128 @@ package config import ( + "bytes" "encoding/json" "testing" "time" ) -func TestDuration(t *testing.T) { - out, err := json.Marshal(Duration(time.Second)) - if err != nil { - t.Fatal(err) +func TestOptionalDuration(t *testing.T) { + makeDurationPointer := func(d time.Duration) *time.Duration { return &d } - } - expected := "\"1s\"" - if string(out) != expected { - t.Fatalf("expected %s, got %s", expected, string(out)) - } - var d Duration - err = json.Unmarshal(out, &d) - if err != nil { - t.Fatal(err) - } - if time.Duration(d) != time.Second { - t.Fatal("expected a second") - } - type Foo struct { - D Duration `json:",omitempty"` - } - out, err = json.Marshal(new(Foo)) - if err != nil { - t.Fatal(err) - } - expected = "{}" - if string(out) != expected { - t.Fatal("expected omitempty to omit the duration") - } + t.Run("marshalling and unmarshalling", func(t *testing.T) { + out, err := json.Marshal(OptionalDuration{value: makeDurationPointer(time.Second)}) + if err != nil { + t.Fatal(err) + } + expected := "\"1s\"" + if string(out) != expected { + t.Fatalf("expected %s, got %s", expected, string(out)) + } + var d OptionalDuration + + if err := json.Unmarshal(out, &d); err != nil { + t.Fatal(err) + } + if *d.value != time.Second { + t.Fatal("expected a second") + } + }) + + t.Run("default value", func(t *testing.T) { + for _, jsonStr := range []string{"null", "\"null\"", "\"\"", "\"default\""} { + var d OptionalDuration + if !d.IsDefault() { + t.Fatal("expected value to be the default initially") + } + if err := json.Unmarshal([]byte(jsonStr), &d); err != nil { + t.Fatalf("%s failed to unmarshall with %s", jsonStr, err) + } + if dur := d.WithDefault(time.Hour); dur != time.Hour { + t.Fatalf("expected default value to be used, got %s", dur) + } + if !d.IsDefault() { + t.Fatal("expected value to be the default") + } + } + }) + + t.Run("omitempty with default value", func(t *testing.T) { + type Foo struct { + D *OptionalDuration `json:",omitempty"` + } + // marshall to JSON without empty field + out, err := json.Marshal(new(Foo)) + if err != nil { + t.Fatal(err) + } + if string(out) != "{}" { + t.Fatalf("expected omitempty to omit the duration, got %s", out) + } + // unmarshall missing value and get the default + var foo2 Foo + if err := json.Unmarshal(out, &foo2); err != nil { + t.Fatalf("%s failed to unmarshall with %s", string(out), err) + } + if dur := foo2.D.WithDefault(time.Hour); dur != time.Hour { + t.Fatalf("expected default value to be used, got %s", dur) + } + if !foo2.D.IsDefault() { + t.Fatal("expected value to be the default") + } + }) + + t.Run("roundtrip including the default values", func(t *testing.T) { + for jsonStr, goValue := range map[string]OptionalDuration{ + // there are various footguns user can hit, normalize them to the canonical default + "null": {}, // JSON null → default value + "\"null\"": {}, // JSON string "null" sent/set by "ipfs config" cli → default value + "\"default\"": {}, // explicit "default" as string + "\"\"": {}, // user removed custom value, empty string should also parse as default + "\"1s\"": {value: makeDurationPointer(time.Second)}, + "\"42h1m3s\"": {value: makeDurationPointer(42*time.Hour + 1*time.Minute + 3*time.Second)}, + } { + var d OptionalDuration + err := json.Unmarshal([]byte(jsonStr), &d) + if err != nil { + t.Fatal(err) + } + + if goValue.value == nil && d.value == nil { + } else if goValue.value == nil && d.value != nil { + t.Errorf("expected nil for %s, got %s", jsonStr, d) + } else if *d.value != *goValue.value { + t.Fatalf("expected %s for %s, got %s", goValue, jsonStr, d) + } + + // Test Reverse + out, err := json.Marshal(goValue) + if err != nil { + t.Fatal(err) + } + if goValue.value == nil { + if !bytes.Equal(out, []byte("null")) { + t.Fatalf("expected JSON null for %s, got %s", jsonStr, string(out)) + } + continue + } + if string(out) != jsonStr { + t.Fatalf("expected %s, got %s", jsonStr, string(out)) + } + } + }) + + t.Run("invalid duration values", func(t *testing.T) { + for _, invalid := range []string{ + "\"s\"", "\"1ę\"", "\"-1\"", "\"1H\"", "\"day\"", + } { + var d OptionalDuration + err := json.Unmarshal([]byte(invalid), &d) + if err == nil { + t.Errorf("expected to fail to decode %s as an OptionalDuration, got %s instead", invalid, d) + } + } + }) } func TestOneStrings(t *testing.T) { From 9eaf572b284cdc6408c6186b664d306c5f2ebebf Mon Sep 17 00:00:00 2001 From: jwh Date: Wed, 27 Oct 2021 21:50:10 +0200 Subject: [PATCH 246/414] go-ipfs-config: feat: pubsub and ipns pubsub flags (#145) * enable pubsub and namesys pubsub to be enable via config * rename Ipns key, switch type to Flag * omit the fields if empty --- config/ipns.go | 3 +++ config/pubsub.go | 3 +++ 2 files changed, 6 insertions(+) diff --git a/config/ipns.go b/config/ipns.go index 44a95b0990c..d5191088409 100644 --- a/config/ipns.go +++ b/config/ipns.go @@ -5,4 +5,7 @@ type Ipns struct { RecordLifetime string ResolveCacheSize int + + // Enable namesys pubsub (--enable-namesys-pubsub) + UsePubsub Flag `json:",omitempty"` } diff --git a/config/pubsub.go b/config/pubsub.go index bed6058478f..aabc35a0e0f 100644 --- a/config/pubsub.go +++ b/config/pubsub.go @@ -8,4 +8,7 @@ type PubsubConfig struct { // DisableSigning disables message signing. Message signing is *enabled* // by default. DisableSigning bool + + // Enable pubsub (--enable-pubsub-experiment) + Enabled Flag `json:",omitempty"` } From cdaa222b22424a615e16fe349bc47c1e1f47c752 Mon Sep 17 00:00:00 2001 From: Adin Schmahmann Date: Thu, 28 Oct 2021 13:55:08 -0700 Subject: [PATCH 247/414] go-ipfs-config: feat: OptionalString type and UnixFSShardingSizeThreshold (#149) * feat: add OptionalString type * test: fix OptionalInteger test * add Internal.UnixFSShardingSizeThreshold as optional string * test: OptionalString null unmarshal with default * fix: omitempty UnixFSShardingSizeThreshold Co-authored-by: Marcin Rataj --- config/internal.go | 3 +- config/types.go | 52 +++++++++++++++++++++++ config/types_test.go | 98 +++++++++++++++++++++++++++++++++++++++++++- 3 files changed, 151 insertions(+), 2 deletions(-) diff --git a/config/internal.go b/config/internal.go index 2e71ac16eb7..318bb339232 100644 --- a/config/internal.go +++ b/config/internal.go @@ -1,7 +1,8 @@ package config type Internal struct { - Bitswap *InternalBitswap `json:",omitempty"` // This is omitempty since we are expecting to make changes to all subcomponents of Internal + Bitswap *InternalBitswap `json:",omitempty"` // This is omitempty since we are expecting to make changes to all subcomponents of Internal + UnixFSShardingSizeThreshold *OptionalString `json:",omitempty"` } type InternalBitswap struct { diff --git a/config/types.go b/config/types.go index ac90fa9b82a..baa073ab460 100644 --- a/config/types.go +++ b/config/types.go @@ -313,3 +313,55 @@ func (p OptionalInteger) String() string { var _ json.Unmarshaler = (*OptionalInteger)(nil) var _ json.Marshaler = (*OptionalInteger)(nil) + +// OptionalString represents a string that has a default value +// +// When encoded in json, Default is encoded as "null" +type OptionalString struct { + value *string +} + +// WithDefault resolves the integer with the given default. +func (p *OptionalString) WithDefault(defaultValue string) (value string) { + if p == nil || p.value == nil { + return defaultValue + } + return *p.value +} + +// IsDefault returns if this is a default optional integer +func (p *OptionalString) IsDefault() bool { + return p == nil || p.value == nil +} + +func (p OptionalString) MarshalJSON() ([]byte, error) { + if p.value != nil { + return json.Marshal(p.value) + } + return json.Marshal(nil) +} + +func (p *OptionalString) UnmarshalJSON(input []byte) error { + switch string(input) { + case "null", "undefined": + *p = OptionalString{} + default: + var value string + err := json.Unmarshal(input, &value) + if err != nil { + return err + } + *p = OptionalString{value: &value} + } + return nil +} + +func (p OptionalString) String() string { + if p.value == nil { + return "default" + } + return fmt.Sprintf("%d", p.value) +} + +var _ json.Unmarshaler = (*OptionalInteger)(nil) +var _ json.Marshaler = (*OptionalInteger)(nil) diff --git a/config/types_test.go b/config/types_test.go index 06ea73a260c..2477f8bcf9a 100644 --- a/config/types_test.go +++ b/config/types_test.go @@ -389,10 +389,106 @@ func TestOptionalInteger(t *testing.T) { for _, invalid := range []string{ "foo", "-1.1", "1.1", "0.0", "[]", } { - var p Priority + var p OptionalInteger err := json.Unmarshal([]byte(invalid), &p) if err == nil { t.Errorf("expected to fail to decode %s as a priority", invalid) } } } + +func TestOptionalString(t *testing.T) { + makeStringPointer := func(v string) *string { + return &v + } + + var defaultOptionalString OptionalString + if !defaultOptionalString.IsDefault() { + t.Fatal("should be the default") + } + if val := defaultOptionalString.WithDefault(""); val != "" { + t.Errorf("optional integer should have been empty, got %s", val) + } + + if val := defaultOptionalString.WithDefault("foo"); val != "foo" { + t.Errorf("optional integer should have been foo, got %s", val) + } + + var filledStr OptionalString + filledStr = OptionalString{value: makeStringPointer("foo")} + if filledStr.IsDefault() { + t.Fatal("should not be the default") + } + if val := filledStr.WithDefault("bar"); val != "foo" { + t.Errorf("optional integer should have been foo, got %s", val) + } + + filledStr = OptionalString{value: makeStringPointer("")} + if val := filledStr.WithDefault("foo"); val != "" { + t.Errorf("optional integer should have been 0, got %s", val) + } + + for jsonStr, goValue := range map[string]OptionalString{ + "null": {}, + "\"0\"": {value: makeStringPointer("0")}, + `"1"`: {value: makeStringPointer("1")}, + `"-1"`: {value: makeStringPointer("-1")}, + `"qwerty"`: {value: makeStringPointer("qwerty")}, + } { + var d OptionalString + err := json.Unmarshal([]byte(jsonStr), &d) + if err != nil { + t.Fatal(err) + } + + if goValue.value == nil && d.value == nil { + } else if goValue.value == nil && d.value != nil { + t.Errorf("expected default, got %s", d) + } else if *d.value != *goValue.value { + t.Fatalf("expected %s, got %s", goValue, d) + } + + // Reverse + out, err := json.Marshal(goValue) + if err != nil { + t.Fatal(err) + } + if string(out) != jsonStr { + t.Fatalf("expected %s, got %s", jsonStr, string(out)) + } + } + + // marshal with omitempty + type Foo struct { + S *OptionalString `json:",omitempty"` + } + out, err := json.Marshal(new(Foo)) + if err != nil { + t.Fatal(err) + } + expected := "{}" + if string(out) != expected { + t.Fatal("expected omitempty to omit the optional integer") + } + // unmarshal from omitempty output and get default value + var foo2 Foo + if err := json.Unmarshal(out, &foo2); err != nil { + t.Fatalf("%s failed to unmarshall with %s", string(out), err) + } + if s := foo2.S.WithDefault("foo"); s != "foo" { + t.Fatalf("expected default value to be used, got %s", s) + } + if !foo2.S.IsDefault() { + t.Fatal("expected value to be the default") + } + + for _, invalid := range []string{ + "[]", "{}", "0", "a", "'b'", + } { + var p OptionalString + err := json.Unmarshal([]byte(invalid), &p) + if err == nil { + t.Errorf("expected to fail to decode %s as an optional string", invalid) + } + } +} From ba9d9f609c972b807bc98bebc42a6a9ff44f1aa4 Mon Sep 17 00:00:00 2001 From: Marten Seemann Date: Fri, 29 Oct 2021 17:21:53 +0200 Subject: [PATCH 248/414] go-ipfs-config: fix: String method on the OptionalString (#153) * fix: String method on the OptionalString * test(OptionalString): empty string is preserved Co-authored-by: Marcin Rataj --- config/types.go | 2 +- config/types_test.go | 17 +++++++++++------ 2 files changed, 12 insertions(+), 7 deletions(-) diff --git a/config/types.go b/config/types.go index baa073ab460..fccae22b5ae 100644 --- a/config/types.go +++ b/config/types.go @@ -360,7 +360,7 @@ func (p OptionalString) String() string { if p.value == nil { return "default" } - return fmt.Sprintf("%d", p.value) + return *p.value } var _ json.Unmarshaler = (*OptionalInteger)(nil) diff --git a/config/types_test.go b/config/types_test.go index 2477f8bcf9a..3a1fd6a8426 100644 --- a/config/types_test.go +++ b/config/types_test.go @@ -407,11 +407,13 @@ func TestOptionalString(t *testing.T) { t.Fatal("should be the default") } if val := defaultOptionalString.WithDefault(""); val != "" { - t.Errorf("optional integer should have been empty, got %s", val) + t.Errorf("optional string should have been empty, got %s", val) + } + if val := defaultOptionalString.String(); val != "default" { + t.Fatalf("default optional string should be the 'default' string, got %s", val) } - if val := defaultOptionalString.WithDefault("foo"); val != "foo" { - t.Errorf("optional integer should have been foo, got %s", val) + t.Errorf("optional string should have been foo, got %s", val) } var filledStr OptionalString @@ -420,17 +422,20 @@ func TestOptionalString(t *testing.T) { t.Fatal("should not be the default") } if val := filledStr.WithDefault("bar"); val != "foo" { - t.Errorf("optional integer should have been foo, got %s", val) + t.Errorf("optional string should have been foo, got %s", val) + } + if val := filledStr.String(); val != "foo" { + t.Fatalf("optional string should have been foo, got %s", val) } - filledStr = OptionalString{value: makeStringPointer("")} if val := filledStr.WithDefault("foo"); val != "" { - t.Errorf("optional integer should have been 0, got %s", val) + t.Errorf("optional string should have been 0, got %s", val) } for jsonStr, goValue := range map[string]OptionalString{ "null": {}, "\"0\"": {value: makeStringPointer("0")}, + "\"\"": {value: makeStringPointer("")}, `"1"`: {value: makeStringPointer("1")}, `"-1"`: {value: makeStringPointer("-1")}, `"qwerty"`: {value: makeStringPointer("qwerty")}, From d2268793dc0e5faa6e7424cdbbcd35180cb42738 Mon Sep 17 00:00:00 2001 From: Marten Seemann Date: Sat, 13 Nov 2021 15:07:14 +0400 Subject: [PATCH 249/414] go-ipfs-config: feat: Swarm.RelayService (circuit v2) (#146) * remove the EnableRelayHop option in the SwarmConfig * add an option to disable the limited relay * make the relay service resources configurable * refactor: use custom types This enables us to swap defaults in go-ipfs without touching the config file generated during `ipfs init` https://github.com/ipfs/go-ipfs-config/pull/146#discussion_r734728162 https://github.com/ipfs/go-ipfs-config/pull/146#discussion_r734728019 * use OptionalDuration in RelayService configuration * fix: *OptionalInteger with omitempty This removes null values from the config * fix: Flag does not need to be a pointer * refactor: flatten RelayService limits this simplifies consumer code and removes nil footgun * docs: clarify different relay types * feat: flag for ForceReachability mode in libp2p (#150) adds Internal.Libp2pForceReachability needed for sharness tests in ipfs/go-ipfs#8522 Co-authored-by: Marcin Rataj Co-authored-by: Marcin Rataj --- config/internal.go | 4 +++- config/swarm.go | 48 ++++++++++++++++++++++++++++++++++---------- config/types.go | 8 ++++---- config/types_test.go | 15 ++++++++++++++ 4 files changed, 59 insertions(+), 16 deletions(-) diff --git a/config/internal.go b/config/internal.go index 318bb339232..dcd834e701c 100644 --- a/config/internal.go +++ b/config/internal.go @@ -1,8 +1,10 @@ package config type Internal struct { - Bitswap *InternalBitswap `json:",omitempty"` // This is omitempty since we are expecting to make changes to all subcomponents of Internal + // All marked as omitempty since we are expecting to make changes to all subcomponents of Internal + Bitswap *InternalBitswap `json:",omitempty"` UnixFSShardingSizeThreshold *OptionalString `json:",omitempty"` + Libp2pForceReachability *OptionalString `json:",omitempty"` } type InternalBitswap struct { diff --git a/config/swarm.go b/config/swarm.go index d662bb30d44..95d4a3d8912 100644 --- a/config/swarm.go +++ b/config/swarm.go @@ -16,21 +16,18 @@ type SwarmConfig struct { // DisableRelay explicitly disables the relay transport. // // Deprecated: This flag is deprecated and is overridden by - // `Transports.Relay` if specified. + // `Swarm.Transports.Relay` if specified. DisableRelay bool `json:",omitempty"` - // EnableRelayHop makes this node act as a public relay, relaying - // traffic between other nodes. - EnableRelayHop bool - - // EnableAutoRelay enables the "auto relay" feature. - // - // When both EnableAutoRelay and EnableRelayHop are set, this go-ipfs node - // will advertise itself as a public relay. Otherwise it will find and use - // advertised public relays when it determines that it's not reachable - // from the public internet. + // EnableAutoRelay enables the "auto relay user" feature. + // Node will find and use advertised public relays when it determines that + // it's not reachable from the public internet. EnableAutoRelay bool + // RelayService.* controls the "auto relay service" feature. + // When enabled, node will provide a limited relay service to other peers. + RelayService RelayService + // Transports contains flags to enable/disable libp2p transports. Transports Transports @@ -38,6 +35,35 @@ type SwarmConfig struct { ConnMgr ConnMgr } +// RelayService configures the resources of the circuit v2 relay. +// For every field a reasonable default will be defined in go-ipfs. +type RelayService struct { + // Enables the limited relay (circuit v2 relay). + Enabled Flag `json:",omitempty"` + + // ConnectionDurationLimit is the time limit before resetting a relayed connection. + ConnectionDurationLimit *OptionalDuration `json:",omitempty"` + // ConnectionDataLimit is the limit of data relayed (on each direction) before resetting the connection. + ConnectionDataLimit *OptionalInteger `json:",omitempty"` + + // ReservationTTL is the duration of a new (or refreshed reservation). + ReservationTTL *OptionalDuration `json:",omitempty"` + + // MaxReservations is the maximum number of active relay slots. + MaxReservations *OptionalInteger `json:",omitempty"` + // MaxCircuits is the maximum number of open relay connections for each peer; defaults to 16. + MaxCircuits *OptionalInteger `json:",omitempty"` + // BufferSize is the size of the relayed connection buffers. + BufferSize *OptionalInteger `json:",omitempty"` + + // MaxReservationsPerPeer is the maximum number of reservations originating from the same peer. + MaxReservationsPerPeer *OptionalInteger `json:",omitempty"` + // MaxReservationsPerIP is the maximum number of reservations originating from the same IP address. + MaxReservationsPerIP *OptionalInteger `json:",omitempty"` + // MaxReservationsPerASN is the maximum number of reservations origination from the same ASN. + MaxReservationsPerASN *OptionalInteger `json:",omitempty"` +} + type Transports struct { // Network specifies the base transports we'll use for dialing. To // listen on a transport, add the transport to your Addresses.Swarm. diff --git a/config/types.go b/config/types.go index fccae22b5ae..c33689c5b2a 100644 --- a/config/types.go +++ b/config/types.go @@ -270,16 +270,16 @@ type OptionalInteger struct { } // WithDefault resolves the integer with the given default. -func (p OptionalInteger) WithDefault(defaultValue int64) (value int64) { - if p.value == nil { +func (p *OptionalInteger) WithDefault(defaultValue int64) (value int64) { + if p == nil || p.value == nil { return defaultValue } return *p.value } // IsDefault returns if this is a default optional integer -func (p OptionalInteger) IsDefault() bool { - return p.value == nil +func (p *OptionalInteger) IsDefault() bool { + return p == nil || p.value == nil } func (p OptionalInteger) MarshalJSON() ([]byte, error) { diff --git a/config/types_test.go b/config/types_test.go index 3a1fd6a8426..caef2b112c0 100644 --- a/config/types_test.go +++ b/config/types_test.go @@ -375,6 +375,7 @@ func TestOptionalInteger(t *testing.T) { } } + // marshal with omitempty type Foo struct { I *OptionalInteger `json:",omitempty"` } @@ -386,6 +387,20 @@ func TestOptionalInteger(t *testing.T) { if string(out) != expected { t.Fatal("expected omitempty to omit the optional integer") } + + // unmarshal from omitempty output and get default value + var foo2 Foo + if err := json.Unmarshal(out, &foo2); err != nil { + t.Fatalf("%s failed to unmarshall with %s", string(out), err) + } + if i := foo2.I.WithDefault(42); i != 42 { + t.Fatalf("expected default value to be used, got %d", i) + } + if !foo2.I.IsDefault() { + t.Fatal("expected value to be the default") + } + + // test invalid values for _, invalid := range []string{ "foo", "-1.1", "1.1", "0.0", "[]", } { From dcf17eb24a7e2b81b3da2a8779609fa74ddb234b Mon Sep 17 00:00:00 2001 From: Marten Seemann Date: Sun, 14 Nov 2021 16:49:10 +0400 Subject: [PATCH 250/414] go-ipfs-config: improve AutoRelay configuration, add config option for static relays --- config/swarm.go | 19 ++++++++++++++++++- 1 file changed, 18 insertions(+), 1 deletion(-) diff --git a/config/swarm.go b/config/swarm.go index 95d4a3d8912..5f02b08376d 100644 --- a/config/swarm.go +++ b/config/swarm.go @@ -22,9 +22,16 @@ type SwarmConfig struct { // EnableAutoRelay enables the "auto relay user" feature. // Node will find and use advertised public relays when it determines that // it's not reachable from the public internet. + // + // Deprecated: This flag is deprecated and is overriden by + // `Swarm.AutoRelay.Enabled` if specified. EnableAutoRelay bool - // RelayService.* controls the "auto relay service" feature. + // AutoRelay controls the "auto relay service" feature. + // When enabled, the node will use relays if it is not publicly reachable. + AutoRelay AutoRelay + + // RelayService.* controls the "relay service". // When enabled, node will provide a limited relay service to other peers. RelayService RelayService @@ -35,6 +42,16 @@ type SwarmConfig struct { ConnMgr ConnMgr } +type AutoRelay struct { + // Enables the AutoRelay. + Enabled Flag `json:",omitempty"` + + // StaticRelays configures static relays to use when this node is not + // publicly reachable. If set, auto relay will not try to find any + // other relay servers. + StaticRelays []string `json:",omitempty"` +} + // RelayService configures the resources of the circuit v2 relay. // For every field a reasonable default will be defined in go-ipfs. type RelayService struct { From bf3a2ca8de921e58c32d75f2c5f771e43ff70998 Mon Sep 17 00:00:00 2001 From: Marten Seemann Date: Mon, 15 Nov 2021 17:34:58 +0400 Subject: [PATCH 251/414] go-ipfs-config: set Swarm.EnableAutoRelay to omitempty Co-authored-by: Marcin Rataj --- config/swarm.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/config/swarm.go b/config/swarm.go index 5f02b08376d..2d2a3813377 100644 --- a/config/swarm.go +++ b/config/swarm.go @@ -25,7 +25,7 @@ type SwarmConfig struct { // // Deprecated: This flag is deprecated and is overriden by // `Swarm.AutoRelay.Enabled` if specified. - EnableAutoRelay bool + EnableAutoRelay bool `json:",omitempty"` // AutoRelay controls the "auto relay service" feature. // When enabled, the node will use relays if it is not publicly reachable. From aefce5a6cd2881d50fc56192e770c0420255d06b Mon Sep 17 00:00:00 2001 From: Marcin Rataj Date: Mon, 15 Nov 2021 15:44:27 +0100 Subject: [PATCH 252/414] =?UTF-8?q?go-ipfs-config:=20refactor:=20AutoRelay?= =?UTF-8?q?=20=E2=86=92=20RelayClient?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit https://github.com/ipfs/go-ipfs-config/pull/154#discussion_r749324695 --- config/swarm.go | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/config/swarm.go b/config/swarm.go index 2d2a3813377..e79d42c97ee 100644 --- a/config/swarm.go +++ b/config/swarm.go @@ -27,9 +27,9 @@ type SwarmConfig struct { // `Swarm.AutoRelay.Enabled` if specified. EnableAutoRelay bool `json:",omitempty"` - // AutoRelay controls the "auto relay service" feature. + // RelayClient controls the client side of "auto relay" feature. // When enabled, the node will use relays if it is not publicly reachable. - AutoRelay AutoRelay + RelayClient RelayClient // RelayService.* controls the "relay service". // When enabled, node will provide a limited relay service to other peers. @@ -42,8 +42,8 @@ type SwarmConfig struct { ConnMgr ConnMgr } -type AutoRelay struct { - // Enables the AutoRelay. +type RelayClient struct { + // Enables the auto relay feature: will use relays if it is not publicly reachable. Enabled Flag `json:",omitempty"` // StaticRelays configures static relays to use when this node is not @@ -55,7 +55,7 @@ type AutoRelay struct { // RelayService configures the resources of the circuit v2 relay. // For every field a reasonable default will be defined in go-ipfs. type RelayService struct { - // Enables the limited relay (circuit v2 relay). + // Enables the limited relay service for other peers (circuit v2 relay). Enabled Flag `json:",omitempty"` // ConnectionDurationLimit is the time limit before resetting a relayed connection. From 7fe155c287d43eab47c8324b4e4be5201fce64e1 Mon Sep 17 00:00:00 2001 From: Marten Seemann Date: Tue, 16 Nov 2021 14:55:46 +0400 Subject: [PATCH 253/414] go-ipfs-config: feat: add a flag to enable the hole punching service (#155) * add a flag to enable the hole punching service * chore: omitempty EnableHolePunching Co-authored-by: Marcin Rataj --- config/swarm.go | 3 +++ 1 file changed, 3 insertions(+) diff --git a/config/swarm.go b/config/swarm.go index e79d42c97ee..8cbeb122f13 100644 --- a/config/swarm.go +++ b/config/swarm.go @@ -35,6 +35,9 @@ type SwarmConfig struct { // When enabled, node will provide a limited relay service to other peers. RelayService RelayService + // EnableHolePunching enables the hole punching service. + EnableHolePunching Flag `json:",omitempty"` + // Transports contains flags to enable/disable libp2p transports. Transports Transports From 5ca82266102145575f03d8e2861792dfa326ca1e Mon Sep 17 00:00:00 2001 From: Marcin Rataj Date: Thu, 18 Nov 2021 01:35:49 +0100 Subject: [PATCH 254/414] go-ipfs-config: chore: update comment to match struct --- config/swarm.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/config/swarm.go b/config/swarm.go index 8cbeb122f13..33d7c53b723 100644 --- a/config/swarm.go +++ b/config/swarm.go @@ -24,7 +24,7 @@ type SwarmConfig struct { // it's not reachable from the public internet. // // Deprecated: This flag is deprecated and is overriden by - // `Swarm.AutoRelay.Enabled` if specified. + // `Swarm.RelayClient.Enabled` if specified. EnableAutoRelay bool `json:",omitempty"` // RelayClient controls the client side of "auto relay" feature. From d50960f9e3d9d3c21e48f1000dff9a64ad2a7ea2 Mon Sep 17 00:00:00 2001 From: Marcin Rataj Date: Tue, 23 Nov 2021 18:44:35 +0100 Subject: [PATCH 255/414] go-ipfs-config: chore: omitempty Experimental.ShardingEnabled (#158) We switch to autosharding setup in https://github.com/ipfs/go-ipfs/pull/8527 --- config/experiments.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/config/experiments.go b/config/experiments.go index c4f906394b5..dba0ea7139b 100644 --- a/config/experiments.go +++ b/config/experiments.go @@ -3,7 +3,7 @@ package config type Experiments struct { FilestoreEnabled bool UrlstoreEnabled bool - ShardingEnabled bool + ShardingEnabled bool `json:",omitempty"` // deprecated by autosharding: https://github.com/ipfs/go-ipfs/pull/8527 GraphsyncEnabled bool Libp2pStreamMounting bool P2pHttpProxy bool From ded27a5473d77601d03aa70a2aa785ab3397eb8f Mon Sep 17 00:00:00 2001 From: Marten Seemann Date: Tue, 23 Nov 2021 21:45:11 +0400 Subject: [PATCH 256/414] go-ipfs-config: feat: omitempty Swarm.EnableRelayHop for circuit v1 migration (#157) * re-add the Swarm.EnableRelayHop option * make Swarm.EnableRelayHop omitempty Co-authored-by: Marcin Rataj --- config/swarm.go | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/config/swarm.go b/config/swarm.go index 33d7c53b723..d03406126e0 100644 --- a/config/swarm.go +++ b/config/swarm.go @@ -19,6 +19,12 @@ type SwarmConfig struct { // `Swarm.Transports.Relay` if specified. DisableRelay bool `json:",omitempty"` + // EnableRelayHop makes this node act as a public relay v1 + // + // Deprecated: The circuit v1 protocol is deprecated. + // Use `Swarm.RelayService` to configure the circuit v2 relay. + EnableRelayHop bool `json:",omitempty"` + // EnableAutoRelay enables the "auto relay user" feature. // Node will find and use advertised public relays when it determines that // it's not reachable from the public internet. From a6008f0e36b7a70cb038a069d3e541a133e02e77 Mon Sep 17 00:00:00 2001 From: Jorropo Date: Tue, 23 Nov 2021 19:09:58 +0100 Subject: [PATCH 257/414] go-ipfs-config: feat: add Addresses.AppendAnnounce (#135) --- config/addresses.go | 11 ++++++----- config/init.go | 9 +++++---- 2 files changed, 11 insertions(+), 9 deletions(-) diff --git a/config/addresses.go b/config/addresses.go index 2d88468fdac..709b28d5847 100644 --- a/config/addresses.go +++ b/config/addresses.go @@ -2,9 +2,10 @@ package config // Addresses stores the (string) multiaddr addresses for the node. type Addresses struct { - Swarm []string // addresses for the swarm to listen on - Announce []string // swarm addresses to announce to the network - NoAnnounce []string // swarm addresses not to announce to the network - API Strings // address for the local API (RPC) - Gateway Strings // address to listen on for IPFS HTTP object gateway + Swarm []string // addresses for the swarm to listen on + Announce []string // swarm addresses to announce to the network, if len > 0 replaces auto detected addresses + AppendAnnounce []string // similar to Announce but doesn't overwride auto detected addresses, they are just appended + NoAnnounce []string // swarm addresses not to announce to the network + API Strings // address for the local API (RPC) + Gateway Strings // address to listen on for IPFS HTTP object gateway } diff --git a/config/init.go b/config/init.go index cf0cca5929a..8e54eaa5866 100644 --- a/config/init.go +++ b/config/init.go @@ -121,10 +121,11 @@ func addressesConfig() Addresses { "/ip4/0.0.0.0/udp/4001/quic", "/ip6/::/udp/4001/quic", }, - Announce: []string{}, - NoAnnounce: []string{}, - API: Strings{"/ip4/127.0.0.1/tcp/5001"}, - Gateway: Strings{"/ip4/127.0.0.1/tcp/8080"}, + Announce: []string{}, + AppendAnnounce: []string{}, + NoAnnounce: []string{}, + API: Strings{"/ip4/127.0.0.1/tcp/5001"}, + Gateway: Strings{"/ip4/127.0.0.1/tcp/8080"}, } } From da35610c1cdc86b2ae1f97eb9167a4ee10e57898 Mon Sep 17 00:00:00 2001 From: Adin Schmahmann Date: Mon, 13 Dec 2021 17:29:29 -0500 Subject: [PATCH 258/414] chore: update version to v0.13.0-dev --- version.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/version.go b/version.go index e6aa56b97d3..c29491a2745 100644 --- a/version.go +++ b/version.go @@ -4,7 +4,7 @@ package ipfs var CurrentCommit string // CurrentVersionNumber is the current application's version literal -const CurrentVersionNumber = "0.12.0-dev" +const CurrentVersionNumber = "0.13.0-dev" const ApiVersion = "/go-ipfs/" + CurrentVersionNumber + "/" From 4d94e19019137fa40f298d633f63d722c70d50eb Mon Sep 17 00:00:00 2001 From: Piotr Galar Date: Wed, 15 Dec 2021 15:56:50 +0100 Subject: [PATCH 259/414] chore: use common ipfs/*-actions in sync-release-assets (#8609) --- .github/workflows/sync-release-assets.yml | 34 ++--------------------- 1 file changed, 3 insertions(+), 31 deletions(-) diff --git a/.github/workflows/sync-release-assets.yml b/.github/workflows/sync-release-assets.yml index d1e0826ace1..df055edd2ef 100644 --- a/.github/workflows/sync-release-assets.yml +++ b/.github/workflows/sync-release-assets.yml @@ -13,38 +13,10 @@ jobs: sync-github-and-dist-ipfs-io: runs-on: "ubuntu-latest" steps: - - name: Setup go - uses: actions/setup-go@v2 + - uses: ipfs/download-ipfs-distribution-action@v1 + - uses: ipfs/start-ipfs-daemon-action@v1 with: - go-version: '1.16' - - uses: actions/cache@v2 - with: - path: | - ~/.cache/go-build - ~/go/pkg/mod - key: ${{ runner.os }}-go-${{ hashFiles('**/go.sum') }} - restore-keys: | - ${{ runner.os }}-go- - - name: Build go-ipfs binary - run: go install github.com/ipfs/go-ipfs/cmd/ipfs@latest - - name: Initialize go-ipfs and start daemon - run: | - sudo sysctl -w net.core.rmem_max=2500000 - ipfs init --profile flatfs,server - ipfs daemon --enable-gc=false & - while (! ipfs id --api "/ip4/127.0.0.1/tcp/5001"); do sleep 1; done - - name: Wait for go-ipfs to be ready - shell: pwsh - run: | - for ($i = 0; $i -lt 10; $i++) { - $addrs = ipfs id | jq .Addresses; - if ($addrs -eq "null") { - sleep 1 - } else { - echo "Successfully started the daemon" - exit 0 - } - } + args: --init --init-profile=flatfs,server --enable-gc=false - uses: actions/setup-node@v2 with: node-version: 14 From 6dfd2dafbf5871dca27cea64dd1201a26779ac0f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Nguy=E1=BB=85n=20Gia=20Phong?= Date: Sun, 26 Dec 2021 14:18:15 +0700 Subject: [PATCH 260/414] Fix typo --- CHANGELOG.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 121198c8141..f023461616c 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -47,7 +47,7 @@ Note: the limited Circuit Relay v2 provided with this release only allows low-ba Switching to v2 of the relay spec means removal or deprecation of configuration keys that were specific to v1. - Relay transport and client support circuit-relay v2: - - `Swarm.EnableAutoRelay` was replaced by `Swarm.RelayClient.Enable`. + - `Swarm.EnableAutoRelay` was replaced by `Swarm.RelayClient.Enabled`. - `Swarm.DisableRelay` is deprecated, relay transport can be now disabled globally (both client and service) by setting `Swarm.Transports.Network.Relay` to `false` - Relay v1 service provider was replaced by v2: - `Swarm.EnableRelayHop` no longer starts an unlimited v1 relay. If you have it set to `true` the node will refuse to start and display an error message. From 2a871ef0184da3b021209881dfa48e3cfdaa9d26 Mon Sep 17 00:00:00 2001 From: Gus Eggert Date: Thu, 6 Jan 2022 08:58:33 -0500 Subject: [PATCH 261/414] docs: add Snap note about customizing IPFS_PATH (#8584) --- README.md | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/README.md b/README.md index cc609152b22..8c279efe046 100644 --- a/README.md +++ b/README.md @@ -166,6 +166,12 @@ With snap, in any of the [supported Linux distributions](https://snapcraft.io/do $ sudo snap install ipfs ``` +The snap sets `IPFS_PATH` to `SNAP_USER_COMMON`, which is usually `~/snap/ipfs/common`. If you want to use `~/.ipfs` instead, you can bind-mount it to `~/snap/ipfs/common` like this: + +```sudo mount --bind ~/.ipfs ~/snap/ipfs/common``` + +If you want something more sophisticated to escape the snap confinement, we recommend using a different method to install `go-ipfs` so that it is not subject to snap confinement. + #### macOS package managers - [MacPorts](#macports) From 14046d000276c5f1c8b1aed50634f18cd2ef23d7 Mon Sep 17 00:00:00 2001 From: Marcin Rataj Date: Wed, 12 Jan 2022 19:40:21 +0100 Subject: [PATCH 262/414] test: restore ipfs-interop (#8613) * chore: ipfs@0.61.0 https://github.com/ipfs/js-ipfs/blob/master/packages/ipfs/CHANGELOG.md#0610-2021-12-15 * chore: ipfs-interop@8.0.0 --- .circleci/main.yml | 16 ++-------------- 1 file changed, 2 insertions(+), 14 deletions(-) diff --git a/.circleci/main.yml b/.circleci/main.yml index 7e197701ad2..19e6f0573e3 100644 --- a/.circleci/main.yml +++ b/.circleci/main.yml @@ -227,22 +227,13 @@ jobs: name: Installing dependencies command: | npm init -y - npm install ipfs@^0.59.1 - npm install ipfs/interop#master + npm install ipfs@^0.61.0 + npm install ipfs-interop@^8.0.0 npm install mocha-circleci-reporter@0.0.3 working_directory: ~/ipfs/go-ipfs/interop - run: name: Running tests command: | - WORKDIR=$(pwd) - cd /tmp - git clone https://github.com/ipfs/js-ipfs.git - cd js-ipfs - git checkout 1dcac76f56972fc3519526e93567e39d685033dd - npm install - npm run build - npm run link - cd $WORKDIR mkdir -p /tmp/test-results/interop/ export MOCHA_FILE="$(mktemp /tmp/test-results/interop/unit.XXXXXX.xml)" npx ipfs-interop -- -t node -f $(sed -n -e "s|^require('\(.*\)')$|test/\1|p" node_modules/ipfs-interop/test/node.js | circleci tests split) -- --reporter mocha-circleci-reporter @@ -251,9 +242,6 @@ jobs: LIBP2P_TCP_REUSEPORT: false LIBP2P_ALLOW_WEAK_RSA_KEYS: 1 IPFS_GO_EXEC: /tmp/circleci-workspace/bin/ipfs - IPFS_JS_EXEC: /tmp/js-ipfs/packages/ipfs/src/cli.js - IPFS_JS_MODULE: /tmp/js-ipfs/packages/ipfs/dist/cjs/src/index.js - IPFS_JS_HTTP_MODULE: /tmp/js-ipfs/packages/ipfs-http-client/dist/cjs/src/index.js - store_test_results: path: /tmp/test-results go-ipfs-api: From 7e4fcbb3245eed8281c832e4b3e67fd413ab8b3c Mon Sep 17 00:00:00 2001 From: Somajit Date: Sat, 4 Dec 2021 07:06:03 +0530 Subject: [PATCH 263/414] Fixed typos in docs/config.md --- docs/config.md | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/docs/config.md b/docs/config.md index fed33589712..1cc938c2753 100644 --- a/docs/config.md +++ b/docs/config.md @@ -701,7 +701,7 @@ between content roots. - `true` - enables [subdomain gateway](#https://docs.ipfs.io/how-to/address-ipfs-on-web/#subdomain-gateway) at `http://*.{hostname}/` - **Requires whitelist:** make sure respective `Paths` are set. - For example, `Paths: ["/ipfs", "/ipns"]` are required for `http://{cid}.ipfs.{hostname}` and `http://{foo}.ipns.{hostname}` to work: + For example, `Paths: ["/ipfs", "/ipns"]` are required for `http://{cid}.ipfs.{hostname}` and `http://{foo}.ipns.{hostname}` to work: ```json "Gateway": { "PublicGateways": { @@ -786,7 +786,7 @@ Below is a list of the most common public gateway setups. `http://dweb.link/ipfs/{cid}` → `http://{cid}.ipfs.dweb.link` - **X-Forwarded-Proto:** if you run go-ipfs behind a reverse proxy that provides TLS, make it add a `X-Forwarded-Proto: https` HTTP header to ensure users are redirected to `https://`, not `http://`. It will also ensure DNSLink names are inlined to fit in a single DNS label, so they work fine with a wildcart TLS cert ([details](https://github.com/ipfs/in-web-browsers/issues/169)). The NGINX directive is `proxy_set_header X-Forwarded-Proto "https";`.: - + `http://dweb.link/ipfs/{cid}` → `https://{cid}.ipfs.dweb.link` `http://dweb.link/ipns/your-dnslink.site.example.com` → `https://your--dnslink-site-example-com.ipfs.dweb.link` @@ -1392,7 +1392,7 @@ Enables providing `/p2p-circuit` v2 relay service to other peers on the network. NOTE: This is the service/server part of the relay system. Disabling this will prevent this node from running as a relay server. -Use [`Swarm.EnableAutoRelay`](#swarmenableautorelay) for turning your node into a relay user. +Use [`Swarm.RelayClient.Enabled`](#swarmrelayclientenabled) for turning your node into a relay user. Default: Enabled @@ -1441,7 +1441,7 @@ Default: `128` Type: `optionalInteger` -#### `Swarm.RelayService.MaxReservations` +#### `Swarm.RelayService.MaxCircuits` Maximum number of open relay connections for each peer. From 562365f4fccda80f6a4e08eaee4b534c1f2e3b98 Mon Sep 17 00:00:00 2001 From: chblodg Date: Fri, 17 Dec 2021 09:51:08 -0800 Subject: [PATCH 264/414] Adding PowerShell to Minimal Go Installation Separated CMD and PowerShell to add additional support. --- docs/windows.md | 20 ++++++++++++++++++-- 1 file changed, 18 insertions(+), 2 deletions(-) diff --git a/docs/windows.md b/docs/windows.md index 4487e64ffe9..c23698384f3 100644 --- a/docs/windows.md +++ b/docs/windows.md @@ -114,20 +114,36 @@ You can use whichever version of `git` you wish but we recommend the Windows bui Clone and change directory to the source code, if you haven't already: -``` +CMD: +```bat git clone https://github.com/ipfs/go-ipfs %GOPATH%/src/github.com/ipfs/go-ipfs cd %GOPATH%/src/github.com/ipfs/go-ipfs/cmd/ipfs ``` +PowerShell: +```powershell +git clone https://github.com/ipfs/go-ipfs $env:GOPATH/src/github.com/ipfs/go-ipfs +cd $env:GOPATH/src/github.com/ipfs/go-ipfs/cmd/ipfs +``` + We need the `git` commit hash to be included in our build so that in the extremely rare event a bug is found, we have a reference point later for tracking it. We'll ask `git` for it and store it in a variable. The syntax for the next command is different depending on whether you're using the interactive command line or writing a batch file. Use the one that applies to you. - interactive: `FOR /F %V IN ('git rev-parse --short HEAD') do set SHA=%V` - interpreter: `FOR /F %%V IN ('git rev-parse --short HEAD') do set SHA=%%V` Finally, we'll build and test `ipfs` itself. -``` + +CMD: +```bat go install -ldflags="-X "github.com/ipfs/go-ipfs".CurrentCommit=%SHA%" %GOPATH%\bin\ipfs.exe version --all ``` + +PowerShell: +```powershell +go install -ldflags="-X "github.com/ipfs/go-ipfs".CurrentCommit=$env:SHA" +cp ./ipfs.exe $env:GOPATH/bin/ipfs.exe -force +. $env:GOPATH/bin/ipfs.exe version --all +``` You can check that the ipfs output versions match with `go version` and `git rev-parse --short HEAD`. If `ipfs.exe` executes and everything matches, then building was successful. From 440394682aa611a161f861456fee98189b8a7df1 Mon Sep 17 00:00:00 2001 From: siiky Date: Thu, 30 Dec 2021 01:33:34 +0000 Subject: [PATCH 265/414] docs: fix typo --- core/commands/files.go | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/core/commands/files.go b/core/commands/files.go index 3f7e3e6b9a9..4801f94954a 100644 --- a/core/commands/files.go +++ b/core/commands/files.go @@ -348,8 +348,8 @@ $ ipfs pin add The lazy-copy feature can also be used to protect partial DAG contents from garbage collection. i.e. adding the Wikipedia root to MFS would not download -all the Wikipedia, but will any downloaded Wikipedia-DAG content from being -GC'ed. +all the Wikipedia, but will prevent any downloaded Wikipedia-DAG content from +being GC'ed. `, }, Arguments: []cmds.Argument{ From bc7ddef8dc5ab7e0f499676007d7204091599e83 Mon Sep 17 00:00:00 2001 From: Marcin Rataj Date: Mon, 17 Jan 2022 19:14:23 +0100 Subject: [PATCH 266/414] fix(ci): interop test parallelism (#8674) * fix(ci): interop test parallelism It broke when require got replaced with modern import statement, and CI run all tests four times.. every time. * fix(ci): run interop with 2 vCPUs We often have 3 processes (tests and 2 or more IPFS nodes) * fix(ci): cache npm during interop * fix(ci): run interop on 2xlarge It is similar load as sharness, so let's use same beefy box * fix(ci): enable ipfs-webui it was skipping due to missing chromium binary * fix(ci): force fresh npm cache during interop Needed to pull-in @chainsafe/libp2p-noise@5.0.2 --- .circleci/main.yml | 14 +++++++++++++- 1 file changed, 13 insertions(+), 1 deletion(-) diff --git a/.circleci/main.yml b/.circleci/main.yml index 19e6f0573e3..54f031a20e5 100644 --- a/.circleci/main.yml +++ b/.circleci/main.yml @@ -219,10 +219,16 @@ jobs: docker: - image: cimg/go:1.16-node parallelism: 4 + resource_class: large steps: - *make_out_dirs - attach_workspace: at: /tmp/circleci-workspace + - restore_cache: + keys: + - v1-interop-{{ .Branch }}-{{ .Revision }} + - v1-interop-{{ .Branch }}- + - v1-interop- - run: name: Installing dependencies command: | @@ -236,7 +242,7 @@ jobs: command: | mkdir -p /tmp/test-results/interop/ export MOCHA_FILE="$(mktemp /tmp/test-results/interop/unit.XXXXXX.xml)" - npx ipfs-interop -- -t node -f $(sed -n -e "s|^require('\(.*\)')$|test/\1|p" node_modules/ipfs-interop/test/node.js | circleci tests split) -- --reporter mocha-circleci-reporter + npx ipfs-interop -- -t node -f $(sed -n -e "s|^import '\(.*\)'$|test/\1|p" node_modules/ipfs-interop/test/node.js | circleci tests split --split-by=timings) -- --reporter mocha-circleci-reporter working_directory: ~/ipfs/go-ipfs/interop environment: LIBP2P_TCP_REUSEPORT: false @@ -244,6 +250,10 @@ jobs: IPFS_GO_EXEC: /tmp/circleci-workspace/bin/ipfs - store_test_results: path: /tmp/test-results + - save_cache: + key: v1-interop-{{ .Branch }}-{{ .Revision }} + paths: + - ~/ipfs/go-ipfs/interop/node_modules go-ipfs-api: executor: golang steps: @@ -326,6 +336,7 @@ jobs: name: Installing dependencies command: | npm install + npx playwright install working_directory: ~/ipfs/go-ipfs/ipfs-webui - run: name: Running upstream tests (finish early if they fail) @@ -341,6 +352,7 @@ jobs: - save_cache: key: v1-ipfs-webui-{{ checksum "~/ipfs/go-ipfs/ipfs-webui/package-lock.json" }} paths: + - ~/.cache/ms-playwright - ~/ipfs/go-ipfs/ipfs-webui/node_modules # We only run build as a test here. DockerHub images are built and published # by Github Action now: https://github.com/ipfs/go-ipfs/pull/8467 From 32eb6e3176689ab8f94c6c42fe1370f56dbdc496 Mon Sep 17 00:00:00 2001 From: Marcin Rataj Date: Wed, 19 Jan 2022 18:58:21 +0100 Subject: [PATCH 267/414] fix(ci): faster gobuild job this should make it take way less time without the need for rewriting make cmd/ipfs-try-build --- .circleci/main.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/.circleci/main.yml b/.circleci/main.yml index 54f031a20e5..f575c6978d4 100644 --- a/.circleci/main.yml +++ b/.circleci/main.yml @@ -69,6 +69,7 @@ executors: jobs: gobuild: executor: golang + resource_class: 2xlarge+ steps: - checkout - *make_out_dirs From 9a0bd0fa7a67c8d646b261bd74b69311195a85ea Mon Sep 17 00:00:00 2001 From: Thibault Meunier Date: Thu, 20 Jan 2022 20:04:53 +0100 Subject: [PATCH 268/414] go-ipfs-config: feat: add DNS.MaxCacheTTL for DNS-over-HTTPS resolvers (#161) --- config/dns.go | 2 ++ 1 file changed, 2 insertions(+) diff --git a/config/dns.go b/config/dns.go index 5c4e62da0cc..b0f7b2710b6 100644 --- a/config/dns.go +++ b/config/dns.go @@ -12,4 +12,6 @@ type DNS struct { // - Custom resolver for ENS: `eth.` → `https://eth.link/dns-query` // - Override the default OS resolver: `.` → `https://doh.applied-privacy.net/query` Resolvers map[string]string + // MaxCacheTTL is the maximum duration DNS entries are valid in the cache. + MaxCacheTTL *OptionalDuration `json:",omitempty"` } From 4ad316803e8cfcdc83d44d93a67e799312a8bc6b Mon Sep 17 00:00:00 2001 From: Marcin Rataj Date: Fri, 28 Jan 2022 23:22:26 +0100 Subject: [PATCH 269/414] docs: update badger section in config.md (#8662) This should fix the issue of users thinking badger is "no-brainer faster choice" and then running into problems. Co-authored-by: Johnny <9611008+johnnymatthews@users.noreply.github.com> --- docs/config.md | 33 ++++++++++++++++----------------- 1 file changed, 16 insertions(+), 17 deletions(-) diff --git a/docs/config.md b/docs/config.md index 1cc938c2753..f855dbc1996 100644 --- a/docs/config.md +++ b/docs/config.md @@ -188,37 +188,36 @@ documented in `ipfs config profile --help`. - `flatfs` - Configures the node to use the flatfs datastore. + Configures the node to use the flatfs datastore. Flatfs is the default datastore. - This is the most battle-tested and reliable datastore, but it's significantly - slower than the badger datastore. You should use this datastore if: + This is the most battle-tested and reliable datastore. + You should use this datastore if: - - You need a very simple and very reliable datastore and you trust your + - You need a very simple and very reliable datastore, and you trust your filesystem. This datastore stores each block as a separate file in the underlying filesystem so it's unlikely to lose data unless there's an issue with the underlying file system. - - You need to run garbage collection on a small (<= 10GiB) datastore. The - default datastore, badger, can leave several gigabytes of data behind when - garbage collecting. - - You're concerned about memory usage. In its default configuration, badger can - use up to several gigabytes of memory. + - You need to run garbage collection in a way that reclaims free space as soon as possible. + - You want to minimize memory usage. + - You are ok with the default speed of data import, or prefer to use `--nocopy`. This profile may only be applied when first initializing the node. - `badgerds` - Configures the node to use the badger datastore. - - This is the fastest datastore. Use this datastore if performance, especially - when adding many gigabytes of files, is critical. However: + Configures the node to use the experimental badger datastore. Keep in mind that this **uses an outdated badger 1.x**. + Use this datastore if some aspects of performance, + especially the speed of adding many gigabytes of files, are critical. However, be aware that: + - This datastore will not properly reclaim space when your datastore is - smaller than several gigabytes. If you run IPFS with '--enable-gc' (you have - enabled block-level garbage collection), you plan on storing very little data in + smaller than several gigabytes. If you run IPFS with `--enable-gc`, you plan on storing very little data in your IPFS node, and disk usage is more critical than performance, consider using - flatfs. - - This datastore uses up to several gigabytes of memory. + `flatfs`. + - This datastore uses up to several gigabytes of memory. + - Good for medium-size datastores, but may run into performance issues if your dataset is bigger than a terabyte. + - The current implementation is based on old badger 1.x which is no longer supported by the upstream team. This profile may only be applied when first initializing the node. From 74e6436814a120f3aee802d89cc52bd3f798771d Mon Sep 17 00:00:00 2001 From: Marcin Rataj Date: Fri, 28 Jan 2022 23:39:10 +0100 Subject: [PATCH 270/414] go-ipfs-config: docs: updated flatfs/badger profile helptext (#167) This is copy-paste from https://github.com/ipfs/go-ipfs/pull/8662 to ensure consistency. --- config/profile.go | 34 ++++++++++++++++++---------------- 1 file changed, 18 insertions(+), 16 deletions(-) diff --git a/config/profile.go b/config/profile.go index 1d379d97db0..cbc7c976453 100644 --- a/config/profile.go +++ b/config/profile.go @@ -123,18 +123,16 @@ This profile may only be applied when first initializing the node. "flatfs": { Description: `Configures the node to use the flatfs datastore. -This is the most battle-tested and reliable datastore, but it's significantly -slower than the badger datastore. You should use this datastore if: +This is the most battle-tested and reliable datastore. +You should use this datastore if: -* You need a very simple and very reliable datastore and you trust your +* You need a very simple and very reliable datastore, and you trust your filesystem. This datastore stores each block as a separate file in the underlying filesystem so it's unlikely to loose data unless there's an issue with the underlying file system. -* You need to run garbage collection on a small (<= 10GiB) datastore. The - default datastore, badger, can leave several gigabytes of data behind when - garbage collecting. -* You're concerned about memory usage. In its default configuration, badger can - use up to several gigabytes of memory. +* You need to run garbage collection in a way that reclaims free space as soon as possible. +* You want to minimize memory usage. +* You are ok with the default speed of data import, or prefer to use --nocopy. This profile may only be applied when first initializing the node. `, @@ -146,17 +144,21 @@ This profile may only be applied when first initializing the node. }, }, "badgerds": { - Description: `Configures the node to use the badger datastore. + Description: `Configures the node to use the experimental badger datastore. -This is the fastest datastore. Use this datastore if performance, especially -when adding many gigabytes of files, is critical. However: +Use this datastore if some aspects of performance, +especially the speed of adding many gigabytes of files, are critical. +However, be aware that: * This datastore will not properly reclaim space when your datastore is - smaller than several gigabytes. If you run IPFS with '--enable-gc' (you have - enabled block-level garbage collection), you plan on storing very little data in - your IPFS node, and disk usage is more critical than performance, consider using - flatfs. -* This datastore uses up to several gigabytes of memory. + smaller than several gigabytes. If you run IPFS with --enable-gc, you plan + on storing very little data in your IPFS node, and disk usage is more + critical than performance, consider using flatfs. +* This datastore uses up to several gigabytes of memory. +* Good for medium-size datastores, but may run into performance issues + if your dataset is bigger than a terabyte. +* The current implementation is based on old badger 1.x + which is no longer supported by the upstream team. This profile may only be applied when first initializing the node.`, From fcd3f4963fe3d09793c8148b699a9192063212fc Mon Sep 17 00:00:00 2001 From: Shu Shen Date: Wed, 2 Feb 2022 21:15:24 -0800 Subject: [PATCH 271/414] chore: test go-ipfs-as-a-library against both current and go.mod version --- .circleci/main.yml | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/.circleci/main.yml b/.circleci/main.yml index 54f031a20e5..39c0b183bdc 100644 --- a/.circleci/main.yml +++ b/.circleci/main.yml @@ -106,7 +106,10 @@ jobs: command: bash <(curl -s https://codecov.io/bash) -cF unittests -X search -f coverage/unit_tests.coverprofile - run: command: | - # we want to test the examples against the current version of go-ipfs + # we want to first test with the go-ipfs in the go.mod file + go test -v ./... + + # we also want to test the examples against the current version of go-ipfs # however, that version might be in a fork so we need to replace the dependency # backup the go.mod and go.sum files to restore them after we run the tests From 012be8ae085b4e14388f9ec604fe5cceca1b0463 Mon Sep 17 00:00:00 2001 From: Shu Shen Date: Wed, 2 Feb 2022 21:12:49 -0800 Subject: [PATCH 272/414] chore: bump to go-ipfs@0.11 in go-ipfs-as-a-library --- docs/examples/go-ipfs-as-a-library/go.mod | 10 +- docs/examples/go-ipfs-as-a-library/go.sum | 258 ++++++++++++---------- 2 files changed, 145 insertions(+), 123 deletions(-) diff --git a/docs/examples/go-ipfs-as-a-library/go.mod b/docs/examples/go-ipfs-as-a-library/go.mod index 00b294b63a6..9ebae5489a5 100644 --- a/docs/examples/go-ipfs-as-a-library/go.mod +++ b/docs/examples/go-ipfs-as-a-library/go.mod @@ -3,10 +3,10 @@ module github.com/ipfs/go-ipfs/examples/go-ipfs-as-a-library go 1.16 require ( - github.com/ipfs/go-ipfs v0.10.0 - github.com/ipfs/go-ipfs-config v0.16.0 - github.com/ipfs/go-ipfs-files v0.0.8 - github.com/ipfs/interface-go-ipfs-core v0.5.1 + github.com/ipfs/go-ipfs v0.11.0 + github.com/ipfs/go-ipfs-config v0.18.0 + github.com/ipfs/go-ipfs-files v0.0.9 + github.com/ipfs/interface-go-ipfs-core v0.5.2 github.com/libp2p/go-libp2p-core v0.11.0 - github.com/multiformats/go-multiaddr v0.4.0 + github.com/multiformats/go-multiaddr v0.4.1 ) diff --git a/docs/examples/go-ipfs-as-a-library/go.sum b/docs/examples/go-ipfs-as-a-library/go.sum index bb26555cc37..fc17b80c9eb 100644 --- a/docs/examples/go-ipfs-as-a-library/go.sum +++ b/docs/examples/go-ipfs-as-a-library/go.sum @@ -34,7 +34,7 @@ cloud.google.com/go/storage v1.5.0/go.mod h1:tpKbwo567HUNpVclU5sGELwQWBDZ8gh0Zeo cloud.google.com/go/storage v1.6.0/go.mod h1:N7U0C8pVQ/+NIKOBQyamJIeKQKkZ+mxpohlUTyfDhBk= cloud.google.com/go/storage v1.8.0/go.mod h1:Wv1Oy7z6Yz3DshWRJFhqM/UCfaWIRTdp0RXyy7KQOVs= cloud.google.com/go/storage v1.10.0/go.mod h1:FLPqc6j+Ki4BU591ie1oL6qBQGu2Bl/tZ9ullr3+Kg0= -contrib.go.opencensus.io/exporter/prometheus v0.3.0/go.mod h1:rpCPVQKhiyH8oomWgm34ZmgIdZa8OVYO5WAIygPbBBE= +contrib.go.opencensus.io/exporter/prometheus v0.4.0/go.mod h1:o7cosnyfuPVK0tB8q0QmaQNhGnptITnPQB+z1+qeFB0= dmitri.shuralyov.com/app/changes v0.0.0-20180602232624-0a106ad413e3/go.mod h1:Yl+fi1br7+Rr3LqpNJf1/uxUdtRUV+Tnj0o93V2B9MU= dmitri.shuralyov.com/gpu/mtl v0.0.0-20190408044501-666a987793e9/go.mod h1:H6x//7gZCb22OMCxBHrMx7a5I7Hp++hsVxbQ4BYO7hU= dmitri.shuralyov.com/html/belt v0.0.0-20180602232347-f7d459c86be0/go.mod h1:JLBrvjyP0v+ecvNYvCpyZgu5/xkfAUhi6wJj28eUfSU= @@ -63,6 +63,8 @@ github.com/alecthomas/template v0.0.0-20190718012654-fb15b899a751/go.mod h1:LOuy github.com/alecthomas/units v0.0.0-20151022065526-2efee857e7cf/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0= github.com/alecthomas/units v0.0.0-20190717042225-c3de453c63f4/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0= github.com/alecthomas/units v0.0.0-20190924025748-f65c72e2690d/go.mod h1:rBZYJk541a8SKzHPHnH3zbiI+7dagKZ0cgpgrD7Fyho= +github.com/alecthomas/units v0.0.0-20210927113745-59d0afb8317a h1:E/8AP5dFtMhl5KPJz66Kt9G0n+7Sn41Fy1wv9/jHOrc= +github.com/alecthomas/units v0.0.0-20210927113745-59d0afb8317a/go.mod h1:OMCwj8VM1Kc9e19TLln2VL61YJF0x1XFtfdL4JdbSyE= github.com/alexbrainman/goissue34681 v0.0.0-20191006012335-3fc7a47baff5 h1:iW0a5ljuFxkLGPNem5Ui+KBjFJzKg4Fv2fnxe4dvzpM= github.com/alexbrainman/goissue34681 v0.0.0-20191006012335-3fc7a47baff5/go.mod h1:Y2QMoi1vgtOIfc+6DhrMOGkLoGzqSV2rKp4Sm+opsyA= github.com/anmitsu/go-shlex v0.0.0-20161002113705-648efa622239/go.mod h1:2FmKhYUyUczH0OGQWaF5ceTx0UBShxjsH6f8oGKYe2c= @@ -114,6 +116,8 @@ github.com/casbin/casbin/v2 v2.1.2/go.mod h1:YcPU1XXisHhLzuxH9coDNf2FbKpjGlbCg3n github.com/cenkalti/backoff v2.2.1+incompatible h1:tNowT99t7UNflLxfYYSlKYsBpXdEet03Pg2g16Swow4= github.com/cenkalti/backoff v2.2.1+incompatible/go.mod h1:90ReRw6GdpyfrHakVjL/QHaoyV4aDUVVkXQJJJ3NXXM= github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU= +github.com/ceramicnetwork/go-dag-jose v0.1.0 h1:yJ/HVlfKpnD3LdYP03AHyTvbm3BpPiz2oZiOeReJRdU= +github.com/ceramicnetwork/go-dag-jose v0.1.0/go.mod h1:qYA1nYt0X8u4XoMAVoOV3upUVKtrxy/I670Dg5F0wjI= github.com/cespare/xxhash v1.1.0 h1:a6HrQnmkObjyL+Gs60czilIUGqrzKutQD6XZog3p+ko= github.com/cespare/xxhash v1.1.0/go.mod h1:XrSqR1VqqWfGrhpAt58auRo0WTKS1nRRg3ghfAqPWnc= github.com/cespare/xxhash/v2 v2.1.1 h1:6MnRN8NT7+YBpUIWxHtefFZOKTAPgGjpQSxqLNn0+qY= @@ -147,6 +151,7 @@ github.com/cpuguy83/go-md2man/v2 v2.0.0-20190314233015-f79a8a8ca69d/go.mod h1:ma github.com/crackcomm/go-gitignore v0.0.0-20170627025303-887ab5e44cc3 h1:HVTnpeuvF6Owjd5mniCL8DEXo7uYXdQEmOP4FJbV5tg= github.com/crackcomm/go-gitignore v0.0.0-20170627025303-887ab5e44cc3/go.mod h1:p1d6YEZWvFzEh4KLyvBcVSnrfNDDvK2zfK/4x2v/4pE= github.com/creack/pty v1.1.7/go.mod h1:lj5s0c3V2DBrqTV7llrYr5NG6My20zk30Fl46Y7DoTY= +github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E= github.com/cskr/pubsub v1.0.2 h1:vlOzMhl6PFn60gRlTQQsIfVwaPB/B/8MziK8FhEPt/0= github.com/cskr/pubsub v1.0.2/go.mod h1:/8MzYXk/NJAz782G8RPkFzXTZVu63VotefPnR9TIRis= github.com/davecgh/go-spew v0.0.0-20171005155431-ecdeabc65495/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= @@ -196,12 +201,14 @@ github.com/francoispqt/gojay v1.2.13 h1:d2m3sFjloqoIUQU3TsHBgj6qg/BVGlTBeHDUmyJn github.com/francoispqt/gojay v1.2.13/go.mod h1:ehT5mTG4ua4581f1++1WLG0vPdaA9HaiDsoyrBGkyDY= github.com/franela/goblin v0.0.0-20200105215937-c9ffbefa60db/go.mod h1:7dvUGVsVBjqR7JHJk0brhHOZYGmfBYOrK0ZhYMEtBr4= github.com/franela/goreq v0.0.0-20171204163338-bcd34c9993f8/go.mod h1:ZhphrRTfi2rbfLwlschooIH4+wKKDR4Pdxhh+TRoA20= -github.com/frankban/quicktest v1.11.3 h1:8sXhOn0uLys67V8EsXLc6eszDs8VXWxL3iRvebPhedY= github.com/frankban/quicktest v1.11.3/go.mod h1:wRf/ReqHper53s+kmmSZizM8NamnL3IM0I9ntUbOk+k= +github.com/frankban/quicktest v1.14.0 h1:+cqqvzZV87b4adx/5ayVOaYZ2CrvM4ejQvUdBzPPUss= +github.com/frankban/quicktest v1.14.0/go.mod h1:NeW+ay9A/U67EYXNFA1nPE8e/tnQv/09mUdL/ijj8og= github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo= -github.com/fsnotify/fsnotify v1.4.9 h1:hsms1Qyu0jgnwNXIxa+/V/PDsU6CfLf6CNO8H7IWoS4= github.com/fsnotify/fsnotify v1.4.9/go.mod h1:znqG4EE+3YCdAaPaxE2ZRY/06pZUdp0tY4IgpuI1SZQ= -github.com/gabriel-vasile/mimetype v1.1.2/go.mod h1:6CDPel/o/3/s4+bp6kIbsWATq8pmgOisOPG40CJa6To= +github.com/fsnotify/fsnotify v1.5.1 h1:mZcQUHVQUQWoPXXtuf9yuEXKudkV2sx1E06UadKWpgI= +github.com/fsnotify/fsnotify v1.5.1/go.mod h1:T3375wBYaZdLLcVNkcVbzGHY7f1l/uK5T5Ai1i3InKU= +github.com/gabriel-vasile/mimetype v1.4.0/go.mod h1:fA8fi6KUiG7MgQQ+mEWotXoEOvmxRtOJlERCzSmRvr8= github.com/ghodss/yaml v1.0.0/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04= github.com/gliderlabs/ssh v0.1.1/go.mod h1:U7qILu1NlMHj9FlMhZLlkCdDnU1DBEAqr0aevW3Awn0= github.com/go-bindata/go-bindata/v3 v3.1.3/go.mod h1:1/zrpXsLD8YDIbhZRqXzm1Ghc7NhEvIN9+Z6R5/xH4I= @@ -280,13 +287,13 @@ github.com/google/go-cmp v0.5.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/ github.com/google/go-cmp v0.5.1/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/go-cmp v0.5.3/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/go-cmp v0.5.4/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= -github.com/google/go-cmp v0.5.5 h1:Khx7svrCpmxxtHBq5j2mp/xVjsi8hQMfNLvJFAlrGgU= github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= +github.com/google/go-cmp v0.5.6 h1:BKbKCqvP6I+rmFHt06ZmyQtvB8xAkWdhFyr0ZUNZcxQ= +github.com/google/go-cmp v0.5.6/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/go-github v17.0.0+incompatible/go.mod h1:zLgOLi98H3fifZn+44m+umXrS52loVEgC2AApnigrVQ= github.com/google/go-querystring v1.0.0/go.mod h1:odCYkC5MyYFN7vkCjXpyrEuKhc/BUO6wN/zVPAxq5ck= github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= github.com/google/gopacket v1.1.17/go.mod h1:UdDNZ1OO62aGYVnPhxT1U6aI7ukYtA/kB8vaU0diBUM= -github.com/google/gopacket v1.1.18/go.mod h1:UdDNZ1OO62aGYVnPhxT1U6aI7ukYtA/kB8vaU0diBUM= github.com/google/gopacket v1.1.19 h1:ves8RnFZPGiFnTS0uPQStjwru6uO6h+nlr9j6fL7kF8= github.com/google/gopacket v1.1.19/go.mod h1:iJ8V8n6KS+z2U1A8pUwu8bW5SyEMkXJB8Yo/Vo+TKTo= github.com/google/martian v2.1.0+incompatible/go.mod h1:9I4somxYTbIHy5NJKHRl3wXiIaQGbYVAs8BPL6v8lEs= @@ -310,9 +317,8 @@ github.com/googleapis/gax-go/v2 v2.0.3/go.mod h1:LLvjysVCY1JZeum8Z6l8qUty8fiNwE0 github.com/googleapis/gax-go/v2 v2.0.4/go.mod h1:0Wqv26UfaUD9n4G6kQubkQ+KchISgw+vpHVxEJEs9eg= github.com/googleapis/gax-go/v2 v2.0.5/go.mod h1:DWXyrwAJ9X0FpwwEdw+IPEYBICEFu5mhpdKc/us6bOk= github.com/gopherjs/gopherjs v0.0.0-20181017120253-0766667cb4d1/go.mod h1:wJfORRmW1u3UXTncJ5qlYoELFm8eSnnEO6hX4iZ3EWY= +github.com/gopherjs/gopherjs v0.0.0-20190430165422-3e4dfb77656c h1:7lF+Vz0LqiRidnzC1Oq86fpX1q/iEv2KJdrCtttYjT4= github.com/gopherjs/gopherjs v0.0.0-20190430165422-3e4dfb77656c/go.mod h1:wJfORRmW1u3UXTncJ5qlYoELFm8eSnnEO6hX4iZ3EWY= -github.com/gopherjs/gopherjs v0.0.0-20190812055157-5d271430af9f h1:KMlcu9X58lhTA/KrfX8Bi1LQSO4pzoVjTiL3h4Jk+Zk= -github.com/gopherjs/gopherjs v0.0.0-20190812055157-5d271430af9f/go.mod h1:wJfORRmW1u3UXTncJ5qlYoELFm8eSnnEO6hX4iZ3EWY= github.com/gorilla/context v1.1.1/go.mod h1:kBGZzfjB9CEq2AlWe17Uuf7NDRt0dE0s8S51q0aT7Yg= github.com/gorilla/mux v1.6.2/go.mod h1:1lud6UwP+6orDFRuTfBEV8e9/aOM/c4fVVCaMa2zaAs= github.com/gorilla/mux v1.7.3/go.mod h1:1lud6UwP+6orDFRuTfBEV8e9/aOM/c4fVVCaMa2zaAs= @@ -371,47 +377,48 @@ github.com/influxdata/influxdb1-client v0.0.0-20191209144304-8bf82d3c094d/go.mod github.com/ipfs/bbloom v0.0.1/go.mod h1:oqo8CVWsJFMOZqTglBG4wydCE4IQA/G2/SEofB0rjUI= github.com/ipfs/bbloom v0.0.4 h1:Gi+8EGJ2y5qiD5FbsbpX/TMNcJw8gSqr7eyjHa4Fhvs= github.com/ipfs/bbloom v0.0.4/go.mod h1:cS9YprKXpoZ9lT0n/Mw/a6/aFV6DTjTLYHeA+gyqMG0= +github.com/ipfs/go-bitfield v1.0.0 h1:y/XHm2GEmD9wKngheWNNCNL0pzrWXZwCdQGv1ikXknQ= +github.com/ipfs/go-bitfield v1.0.0/go.mod h1:N/UiujQy+K+ceU1EF5EkVd1TNqevLrCQMIcAEPrdtus= github.com/ipfs/go-bitswap v0.0.9/go.mod h1:kAPf5qgn2W2DrgAcscZ3HrM9qh4pH+X8Fkk3UPrwvis= github.com/ipfs/go-bitswap v0.1.0/go.mod h1:FFJEf18E9izuCqUtHxbWEvq+reg7o4CW5wSAE1wsxj0= github.com/ipfs/go-bitswap v0.1.2/go.mod h1:qxSWS4NXGs7jQ6zQvoPY3+NmOfHHG47mhkiLzBpJQIs= -github.com/ipfs/go-bitswap v0.1.3/go.mod h1:YEQlFy0kkxops5Vy+OxWdRSEZIoS7I7KDIwoa5Chkps= github.com/ipfs/go-bitswap v0.1.8/go.mod h1:TOWoxllhccevbWFUR2N7B1MTSVVge1s6XSMiCSA4MzM= github.com/ipfs/go-bitswap v0.3.4/go.mod h1:4T7fvNv/LmOys+21tnLzGKncMeeXUYUd1nUiJ2teMvI= -github.com/ipfs/go-bitswap v0.4.0 h1:bLiqrpef1na4wdqGLqHKv954s1zz6KFghfmQWCPjBik= -github.com/ipfs/go-bitswap v0.4.0/go.mod h1:J2sAsp9UKxLgHDektSy3y3Q9OfQjM9sjhKBR1dlwrMg= +github.com/ipfs/go-bitswap v0.5.1 h1:721YAEDBnLIrvcIMkCHCdqp34hA8jwL9yKMkyJpSpco= +github.com/ipfs/go-bitswap v0.5.1/go.mod h1:P+ckC87ri1xFLvk74NlXdP0Kj9RmWAh4+H78sC6Qopo= github.com/ipfs/go-block-format v0.0.1/go.mod h1:DK/YYcsSUIVAFNwo/KZCdIIbpN0ROH/baNLgayt4pFc= github.com/ipfs/go-block-format v0.0.2/go.mod h1:AWR46JfpcObNfg3ok2JHDUfdiHRgWhJgCQF+KIgOPJY= github.com/ipfs/go-block-format v0.0.3 h1:r8t66QstRp/pd/or4dpnbVfXT5Gt7lOqRvC+/dDTpMc= github.com/ipfs/go-block-format v0.0.3/go.mod h1:4LmD4ZUw0mhO+JSKdpWwrzATiEfM7WWgQ8H5l6P8MVk= github.com/ipfs/go-blockservice v0.0.7/go.mod h1:EOfb9k/Y878ZTRY/CH0x5+ATtaipfbRhbvNSdgc/7So= github.com/ipfs/go-blockservice v0.1.0/go.mod h1:hzmMScl1kXHg3M2BjTymbVPjv627N7sYcvYaKbop39M= -github.com/ipfs/go-blockservice v0.1.1/go.mod h1:t+411r7psEUhLueM8C7aPA7cxCclv4O3VsUVxt9kz2I= -github.com/ipfs/go-blockservice v0.1.3/go.mod h1:OTZhFpkgY48kNzbgyvcexW9cHrpjBYIjSR0KoDOFOLU= github.com/ipfs/go-blockservice v0.1.4/go.mod h1:OTZhFpkgY48kNzbgyvcexW9cHrpjBYIjSR0KoDOFOLU= -github.com/ipfs/go-blockservice v0.1.7 h1:yVe9te0M7ow8i+PPkx03YFSpxqzXx594d6h+34D6qMg= github.com/ipfs/go-blockservice v0.1.7/go.mod h1:GmS+BAt4hrwBKkzE11AFDQUrnvqjwFatGS2MY7wOjEM= +github.com/ipfs/go-blockservice v0.2.1 h1:NJ4j/cwEfIg60rzAWcCIxRtOwbf6ZPK49MewNxObCPQ= +github.com/ipfs/go-blockservice v0.2.1/go.mod h1:k6SiwmgyYgs4M/qt+ww6amPeUH9EISLRBnvUurKJhi8= github.com/ipfs/go-cid v0.0.1/go.mod h1:GHWU/WuQdMPmIosc4Yn1bcCT7dSeX4lBafM7iqUPQvM= github.com/ipfs/go-cid v0.0.2/go.mod h1:GHWU/WuQdMPmIosc4Yn1bcCT7dSeX4lBafM7iqUPQvM= github.com/ipfs/go-cid v0.0.3/go.mod h1:GHWU/WuQdMPmIosc4Yn1bcCT7dSeX4lBafM7iqUPQvM= github.com/ipfs/go-cid v0.0.4/go.mod h1:4LLaPOQwmk5z9LBgQnpkivrx8BJjUyGwTXCd5Xfj6+M= github.com/ipfs/go-cid v0.0.5/go.mod h1:plgt+Y5MnOey4vO4UlUazGqdbEXuFYitED67FexhXog= github.com/ipfs/go-cid v0.0.6/go.mod h1:6Ux9z5e+HpkQdckYoX1PG/6xqKspzlEIR5SDmgqgC/I= -github.com/ipfs/go-cid v0.0.7 h1:ysQJVJA3fNDF1qigJbsSQOdjhVLsOEoPdh0+R97k3jY= github.com/ipfs/go-cid v0.0.7/go.mod h1:6Ux9z5e+HpkQdckYoX1PG/6xqKspzlEIR5SDmgqgC/I= +github.com/ipfs/go-cid v0.1.0 h1:YN33LQulcRHjfom/i25yoOZR4Telp1Hr/2RU3d0PnC0= +github.com/ipfs/go-cid v0.1.0/go.mod h1:rH5/Xv83Rfy8Rw6xG+id3DYAMUVmem1MowoKwdXmN2o= github.com/ipfs/go-cidutil v0.0.2 h1:CNOboQf1t7Qp0nuNh8QMmhJs0+Q//bRL1axtCnIB1Yo= github.com/ipfs/go-cidutil v0.0.2/go.mod h1:ewllrvrxG6AMYStla3GD7Cqn+XYSLqjK0vc+086tB6s= github.com/ipfs/go-datastore v0.0.1/go.mod h1:d4KVXhMt913cLBEI/PXAy6ko+W7e9AhyAKBGh803qeE= github.com/ipfs/go-datastore v0.0.5/go.mod h1:d4KVXhMt913cLBEI/PXAy6ko+W7e9AhyAKBGh803qeE= github.com/ipfs/go-datastore v0.1.0/go.mod h1:d4KVXhMt913cLBEI/PXAy6ko+W7e9AhyAKBGh803qeE= github.com/ipfs/go-datastore v0.1.1/go.mod h1:w38XXW9kVFNp57Zj5knbKWM2T+KOZCGDRVNdgPHtbHw= -github.com/ipfs/go-datastore v0.3.0/go.mod h1:w38XXW9kVFNp57Zj5knbKWM2T+KOZCGDRVNdgPHtbHw= github.com/ipfs/go-datastore v0.3.1/go.mod h1:w38XXW9kVFNp57Zj5knbKWM2T+KOZCGDRVNdgPHtbHw= github.com/ipfs/go-datastore v0.4.0/go.mod h1:SX/xMIKoCszPqp+z9JhPYCmoOoXTvaa13XEbGtsFUhA= github.com/ipfs/go-datastore v0.4.1/go.mod h1:SX/xMIKoCszPqp+z9JhPYCmoOoXTvaa13XEbGtsFUhA= github.com/ipfs/go-datastore v0.4.4/go.mod h1:SX/xMIKoCszPqp+z9JhPYCmoOoXTvaa13XEbGtsFUhA= github.com/ipfs/go-datastore v0.4.5/go.mod h1:eXTcaaiN6uOlVCLS9GjJUJtlvJfM3xk23w3fyfrmmJs= -github.com/ipfs/go-datastore v0.4.6 h1:zU2cmweykxJ+ziXnA2cPtsLe8rdR/vrthOipLPuf6kc= -github.com/ipfs/go-datastore v0.4.6/go.mod h1:XSipLSc64rFKSFRFGo1ecQl+WhYce3K7frtpHkyPFUc= +github.com/ipfs/go-datastore v0.5.0/go.mod h1:9zhEApYMTl17C8YDp7JmU7sQZi2/wqiYh73hakZ90Bk= +github.com/ipfs/go-datastore v0.5.1 h1:WkRhLuISI+XPD0uk3OskB0fYFSyqK8Ob5ZYew9Qa1nQ= +github.com/ipfs/go-datastore v0.5.1/go.mod h1:9zhEApYMTl17C8YDp7JmU7sQZi2/wqiYh73hakZ90Bk= github.com/ipfs/go-detect-race v0.0.1 h1:qX/xay2W3E4Q1U7d9lNs1sU9nvguX0a7319XbyQ6cOk= github.com/ipfs/go-detect-race v0.0.1/go.mod h1:8BNT7shDZPo99Q74BpGMK+4D8Mn4j46UU0LZ723meps= github.com/ipfs/go-ds-badger v0.0.2/go.mod h1:Y3QpeSFWQf6MopLTiZD+VT6IC1yZqaGmjvRcKeSGij8= @@ -419,67 +426,75 @@ github.com/ipfs/go-ds-badger v0.0.5/go.mod h1:g5AuuCGmr7efyzQhLL8MzwqcauPojGPUaH github.com/ipfs/go-ds-badger v0.0.7/go.mod h1:qt0/fWzZDoPW6jpQeqUjR5kBfhDNB65jd9YlmAvpQBk= github.com/ipfs/go-ds-badger v0.2.1/go.mod h1:Tx7l3aTph3FMFrRS838dcSJh+jjA7cX9DrGVwx/NOwE= github.com/ipfs/go-ds-badger v0.2.3/go.mod h1:pEYw0rgg3FIrywKKnL+Snr+w/LjJZVMTBRn4FS6UHUk= -github.com/ipfs/go-ds-badger v0.2.6/go.mod h1:02rnztVKA4aZwDuaRPTf8mpqcKmXP7mLl6JPxd14JHA= -github.com/ipfs/go-ds-badger v0.2.7 h1:ju5REfIm+v+wgVnQ19xGLYPHYHbYLR6qJfmMbCDSK1I= github.com/ipfs/go-ds-badger v0.2.7/go.mod h1:02rnztVKA4aZwDuaRPTf8mpqcKmXP7mLl6JPxd14JHA= -github.com/ipfs/go-ds-flatfs v0.4.5 h1:4QceuKEbH+HVZ2ZommstJMi3o3II+dWS3IhLaD7IGHs= -github.com/ipfs/go-ds-flatfs v0.4.5/go.mod h1:e4TesLyZoA8k1gV/yCuBTnt2PJtypn4XUlB5n8KQMZY= +github.com/ipfs/go-ds-badger v0.3.0 h1:xREL3V0EH9S219kFFueOYJJTcjgNSZ2HY1iSvN7U1Ro= +github.com/ipfs/go-ds-badger v0.3.0/go.mod h1:1ke6mXNqeV8K3y5Ak2bAA0osoTfmxUdupVCGm4QUIek= +github.com/ipfs/go-ds-flatfs v0.5.1 h1:ZCIO/kQOS/PSh3vcF1H6a8fkRGS7pOfwfPdx4n/KJH4= +github.com/ipfs/go-ds-flatfs v0.5.1/go.mod h1:RWTV7oZD/yZYBKdbVIFXTX2fdY2Tbvl94NsWqmoyAX4= github.com/ipfs/go-ds-leveldb v0.0.1/go.mod h1:feO8V3kubwsEF22n0YRQCffeb79OOYIykR4L04tMOYc= github.com/ipfs/go-ds-leveldb v0.1.0/go.mod h1:hqAW8y4bwX5LWcCtku2rFNX3vjDZCy5LZCg+cSZvYb8= github.com/ipfs/go-ds-leveldb v0.4.1/go.mod h1:jpbku/YqBSsBc1qgME8BkWS4AxzF2cEu1Ii2r79Hh9s= -github.com/ipfs/go-ds-leveldb v0.4.2 h1:QmQoAJ9WkPMUfBLnu1sBVy0xWWlJPg0m4kRAiJL9iaw= github.com/ipfs/go-ds-leveldb v0.4.2/go.mod h1:jpbku/YqBSsBc1qgME8BkWS4AxzF2cEu1Ii2r79Hh9s= -github.com/ipfs/go-ds-measure v0.1.0 h1:vE4TyY4aeLeVgnnPBC5QzKIjKrqzha0NCujTfgvVbVQ= -github.com/ipfs/go-ds-measure v0.1.0/go.mod h1:1nDiFrhLlwArTME1Ees2XaBOl49OoCgd2A3f8EchMSY= -github.com/ipfs/go-fetcher v1.5.0 h1:oreKTKBzja3S09rSmoZlA3KGVlRiUbJ1pQjtB4K6y3w= +github.com/ipfs/go-ds-leveldb v0.5.0 h1:s++MEBbD3ZKc9/8/njrn4flZLnCuY9I79v94gBUNumo= +github.com/ipfs/go-ds-leveldb v0.5.0/go.mod h1:d3XG9RUDzQ6V4SHi8+Xgj9j1XuEk1z82lquxrVbml/Q= +github.com/ipfs/go-ds-measure v0.2.0 h1:sG4goQe0KDTccHMyT45CY1XyUbxe5VwTKpg2LjApYyQ= +github.com/ipfs/go-ds-measure v0.2.0/go.mod h1:SEUD/rE2PwRa4IQEC5FuNAmjJCyYObZr9UvVh8V3JxE= github.com/ipfs/go-fetcher v1.5.0/go.mod h1:5pDZ0393oRF/fHiLmtFZtpMNBQfHOYNPtryWedVuSWE= -github.com/ipfs/go-filestore v0.0.3 h1:MhZ1jT5K3NewZwim6rS/akcJLm1xM+r6nz6foeB9EwE= -github.com/ipfs/go-filestore v0.0.3/go.mod h1:dvXRykFzyyXN2CdNlRGzDAkXMDPyI+D7JE066SiKLSE= +github.com/ipfs/go-fetcher v1.6.1 h1:UFuRVYX5AIllTiRhi5uK/iZkfhSpBCGX7L70nSZEmK8= +github.com/ipfs/go-fetcher v1.6.1/go.mod h1:27d/xMV8bodjVs9pugh/RCjjK2OZ68UgAMspMdingNo= +github.com/ipfs/go-filestore v0.1.0 h1:qxvDVTzGrbQElddMmkwsJwJn+fDwWb3pHQHtKc1H0a8= +github.com/ipfs/go-filestore v0.1.0/go.mod h1:0KTrzoJnJ3sJDEDM09Vq8nz8H475rRyeq4i0n/bpF00= github.com/ipfs/go-fs-lock v0.0.7 h1:6BR3dajORFrFTkb5EpCUFIAypsoxpGpDSVUdFwzgL9U= github.com/ipfs/go-fs-lock v0.0.7/go.mod h1:Js8ka+FNYmgQRLrRXzU3CB/+Csr1BwrRilEcvYrHhhc= -github.com/ipfs/go-graphsync v0.8.0 h1:Zhh6QdTqdipYHD71ncLO8eA6c8EGUTOoJ4Rqybw3K+o= -github.com/ipfs/go-graphsync v0.8.0/go.mod h1:CLxN859dUTcXCav1DvNvmAUWPZfmNLjlGLJYy+c3dlM= -github.com/ipfs/go-ipfs v0.10.0 h1:+b6QNlNvYTTEUPIFab484t1Ubylz+fBczIK+q0UV62Q= -github.com/ipfs/go-ipfs v0.10.0/go.mod h1:HsnRkQdpruG6JMaycJyrlLwJdduw1dJv2rEPgWxdJvA= +github.com/ipfs/go-graphsync v0.11.0 h1:PiiD5CnoC3xEHMW8d6uBGqGcoTwiMB5d9CORIEyF6iA= +github.com/ipfs/go-graphsync v0.11.0/go.mod h1:wC+c8vGVjAHthsVIl8LKr37cUra2GOaMYcQNNmMxDqE= +github.com/ipfs/go-ipfs v0.11.0 h1:gAYt27NOnYJII9Kv9oiwEhURtQM+e4423WMzfllvefc= +github.com/ipfs/go-ipfs v0.11.0/go.mod h1:g68Thu2Ho11AWoHsN34P5fSK7iA6OWWRy3T/g8HLixc= github.com/ipfs/go-ipfs-blockstore v0.0.1/go.mod h1:d3WClOmRQKFnJ0Jz/jj/zmksX0ma1gROTlovZKBmN08= github.com/ipfs/go-ipfs-blockstore v0.1.0/go.mod h1:5aD0AvHPi7mZc6Ci1WCAhiBQu2IsfTduLl+422H6Rqw= github.com/ipfs/go-ipfs-blockstore v0.1.4/go.mod h1:Jxm3XMVjh6R17WvxFEiyKBLUGr86HgIYJW/D/MwqeYQ= -github.com/ipfs/go-ipfs-blockstore v0.1.6 h1:+RNM/gkTF6lzLPtt/xqjEUXJuG0lFwAiv+MV8MoAhvA= github.com/ipfs/go-ipfs-blockstore v0.1.6/go.mod h1:Jxm3XMVjh6R17WvxFEiyKBLUGr86HgIYJW/D/MwqeYQ= +github.com/ipfs/go-ipfs-blockstore v0.2.1 h1:624eIDnkZWNdWbp/N8aDBOUtSY0YW75aJu+vbxnNlkA= +github.com/ipfs/go-ipfs-blockstore v0.2.1/go.mod h1:jGesd8EtCM3/zPgx+qr0/feTXGUeRai6adgwC+Q+JvE= github.com/ipfs/go-ipfs-blocksutil v0.0.1 h1:Eh/H4pc1hsvhzsQoMEP3Bke/aW5P5rVM1IWFJMcGIPQ= github.com/ipfs/go-ipfs-blocksutil v0.0.1/go.mod h1:Yq4M86uIOmxmGPUHv/uI7uKqZNtLb449gwKqXjIsnRk= github.com/ipfs/go-ipfs-chunker v0.0.1/go.mod h1:tWewYK0we3+rMbOh7pPFGDyypCtvGcBFymgY4rSDLAw= github.com/ipfs/go-ipfs-chunker v0.0.5 h1:ojCf7HV/m+uS2vhUGWcogIIxiO5ubl5O57Q7NapWLY8= github.com/ipfs/go-ipfs-chunker v0.0.5/go.mod h1:jhgdF8vxRHycr00k13FM8Y0E+6BoalYeobXmUyTreP8= github.com/ipfs/go-ipfs-cmds v0.6.0/go.mod h1:ZgYiWVnCk43ChwoH8hAmI1IRbuVtq3GSTHwtRB/Kqhk= -github.com/ipfs/go-ipfs-config v0.16.0 h1:CBtIYyp/iWIczCv83bmfge8EA2KqxOOfqmETs3tUnnU= -github.com/ipfs/go-ipfs-config v0.16.0/go.mod h1:wz2lKzOjgJeYJa6zx8W9VT7mz+iSd0laBMqS/9wmX6A= +github.com/ipfs/go-ipfs-config v0.18.0 h1:Ta1aNGNEq6RIvzbw7dqzCVZJKb7j+Dd35JFnAOCpT8g= +github.com/ipfs/go-ipfs-config v0.18.0/go.mod h1:wz2lKzOjgJeYJa6zx8W9VT7mz+iSd0laBMqS/9wmX6A= github.com/ipfs/go-ipfs-delay v0.0.0-20181109222059-70721b86a9a8/go.mod h1:8SP1YXK1M1kXuc4KJZINY3TQQ03J2rwBG9QfXmbRPrw= github.com/ipfs/go-ipfs-delay v0.0.1 h1:r/UXYyRcddO6thwOnhiznIAiSvxMECGgtv35Xs1IeRQ= github.com/ipfs/go-ipfs-delay v0.0.1/go.mod h1:8SP1YXK1M1kXuc4KJZINY3TQQ03J2rwBG9QfXmbRPrw= github.com/ipfs/go-ipfs-ds-help v0.0.1/go.mod h1:gtP9xRaZXqIQRh1HRpp595KbBEdgqWFxefeVKOV8sxo= github.com/ipfs/go-ipfs-ds-help v0.1.1 h1:IW/bXGeaAZV2VH0Kuok+Ohva/zHkHmeLFBxC1k7mNPc= github.com/ipfs/go-ipfs-ds-help v0.1.1/go.mod h1:SbBafGJuGsPI/QL3j9Fc5YPLeAu+SzOkI0gFwAg+mOs= -github.com/ipfs/go-ipfs-exchange-interface v0.0.1 h1:LJXIo9W7CAmugqI+uofioIpRb6rY30GUu7G6LUfpMvM= github.com/ipfs/go-ipfs-exchange-interface v0.0.1/go.mod h1:c8MwfHjtQjPoDyiy9cFquVtVHkO9b9Ob3FG91qJnWCM= -github.com/ipfs/go-ipfs-exchange-offline v0.0.1 h1:P56jYKZF7lDDOLx5SotVh5KFxoY6C81I1NSHW1FxGew= +github.com/ipfs/go-ipfs-exchange-interface v0.1.0 h1:TiMekCrOGQuWYtZO3mf4YJXDIdNgnKWZ9IE3fGlnWfo= +github.com/ipfs/go-ipfs-exchange-interface v0.1.0/go.mod h1:ych7WPlyHqFvCi/uQI48zLZuAWVP5iTQPXEfVaw5WEI= github.com/ipfs/go-ipfs-exchange-offline v0.0.1/go.mod h1:WhHSFCVYX36H/anEKQboAzpUws3x7UeEGkzQc3iNkM0= +github.com/ipfs/go-ipfs-exchange-offline v0.1.1 h1:mEiXWdbMN6C7vtDG21Fphx8TGCbZPpQnz/496w/PL4g= +github.com/ipfs/go-ipfs-exchange-offline v0.1.1/go.mod h1:vTiBRIbzSwDD0OWm+i3xeT0mO7jG2cbJYatp3HPk5XY= github.com/ipfs/go-ipfs-files v0.0.3/go.mod h1:INEFm0LL2LWXBhNJ2PMIIb2w45hpXgPjNoE7yA8Y1d4= github.com/ipfs/go-ipfs-files v0.0.8/go.mod h1:wiN/jSG8FKyk7N0WyctKSvq3ljIa2NNTiZB55kpTdOs= +github.com/ipfs/go-ipfs-files v0.0.9 h1:OFyOfmuVDu9c5YtjSDORmwXzE6fmZikzZpzsnNkgFEg= +github.com/ipfs/go-ipfs-files v0.0.9/go.mod h1:aFv2uQ/qxWpL/6lidWvnSQmaVqCrf0TBGoUr+C1Fo84= github.com/ipfs/go-ipfs-keystore v0.0.2 h1:Fa9xg9IFD1VbiZtrNLzsD0GuELVHUFXCWF64kCPfEXU= github.com/ipfs/go-ipfs-keystore v0.0.2/go.mod h1:H49tRmibOEs7gLMgbOsjC4dqh1u5e0R/SWuc2ScfgSo= -github.com/ipfs/go-ipfs-pinner v0.1.2 h1:Ve9OBhL6eg5+tVqEnIhPZOCXDtMjB+OhOohVZxPUxms= -github.com/ipfs/go-ipfs-pinner v0.1.2/go.mod h1:/u9kMe+TyQybN21O5OBicdyx3x93lVI77PCtiTnArUk= +github.com/ipfs/go-ipfs-pinner v0.2.1 h1:kw9hiqh2p8TatILYZ3WAfQQABby7SQARdrdA+5Z5QfY= +github.com/ipfs/go-ipfs-pinner v0.2.1/go.mod h1:l1AtLL5bovb7opnG77sh4Y10waINz3Y1ni6CvTzx7oo= github.com/ipfs/go-ipfs-posinfo v0.0.1 h1:Esoxj+1JgSjX0+ylc0hUmJCOv6V2vFoZiETLR6OtpRs= github.com/ipfs/go-ipfs-posinfo v0.0.1/go.mod h1:SwyeVP+jCwiDu0C313l/8jg6ZxM0qqtlt2a0vILTc1A= github.com/ipfs/go-ipfs-pq v0.0.1/go.mod h1:LWIqQpqfRG3fNc5XsnIhz/wQ2XXGyugQwls7BgUmUfY= github.com/ipfs/go-ipfs-pq v0.0.2 h1:e1vOOW6MuOwG2lqxcLA+wEn93i/9laCY8sXAw76jFOY= github.com/ipfs/go-ipfs-pq v0.0.2/go.mod h1:LWIqQpqfRG3fNc5XsnIhz/wQ2XXGyugQwls7BgUmUfY= -github.com/ipfs/go-ipfs-provider v0.6.1 h1:4VenAH1J5XH+/mgM2Y7p+QN3wlk7CInMDG8rsT2CGW4= -github.com/ipfs/go-ipfs-provider v0.6.1/go.mod h1:I4Cig3InhftbRJohph76Qy/P2uKEZILNGiKvDJmmC28= +github.com/ipfs/go-ipfs-provider v0.7.1 h1:eKToBUAb6ZY8iiA6AYVxzW4G1ep67XUaaEBUIYpxhfw= +github.com/ipfs/go-ipfs-provider v0.7.1/go.mod h1:QwdDYRYnC5sYGLlOwVDY/0ZB6T3zcMtu+5+GdGeUuw8= github.com/ipfs/go-ipfs-routing v0.0.1/go.mod h1:k76lf20iKFxQTjcJokbPM9iBXVXVZhcOwc360N4nuKs= -github.com/ipfs/go-ipfs-routing v0.1.0 h1:gAJTT1cEeeLj6/DlLX6t+NxD9fQe2ymTO6qWRDI/HQQ= github.com/ipfs/go-ipfs-routing v0.1.0/go.mod h1:hYoUkJLyAUKhF58tysKpids8RNDPO42BVMgK5dNsoqY= +github.com/ipfs/go-ipfs-routing v0.2.1 h1:E+whHWhJkdN9YeoHZNj5itzc+OR292AJ2uE9FFiW0BY= +github.com/ipfs/go-ipfs-routing v0.2.1/go.mod h1:xiNNiwgjmLqPS1cimvAw6EyB9rkVDbiocA4yY+wRNLM= github.com/ipfs/go-ipfs-util v0.0.1/go.mod h1:spsl5z8KUnrve+73pOhSVZND1SIxPW5RyBCNzQxlJBc= github.com/ipfs/go-ipfs-util v0.0.2 h1:59Sswnk1MFaiq+VcaknX7aYEyGyGDAA73ilhEK2POp8= github.com/ipfs/go-ipfs-util v0.0.2/go.mod h1:CbPtkWJzjLdEcezDns2XYaehFVNXG9zrdrtMecczcsQ= @@ -496,8 +511,6 @@ github.com/ipfs/go-ipld-git v0.1.1 h1:TWGnZjS0htmEmlMFEkA3ogrNCqWjIxwr16x1OsdhG+ github.com/ipfs/go-ipld-git v0.1.1/go.mod h1:+VyMqF5lMcJh4rwEppV0e6g4nCCHXThLYYDpKUkJubI= github.com/ipfs/go-ipld-legacy v0.1.0 h1:wxkkc4k8cnvIGIjPO0waJCe7SHEyFgl+yQdafdjGrpA= github.com/ipfs/go-ipld-legacy v0.1.0/go.mod h1:86f5P/srAmh9GcIcWQR9lfFLZPrIyyXQeVlOWeeWEuI= -github.com/ipfs/go-ipns v0.0.2/go.mod h1:WChil4e0/m9cIINWLxZe1Jtf77oz5L05rO2ei/uKJ5U= -github.com/ipfs/go-ipns v0.1.0/go.mod h1:3IbsuPkR6eAGcnx+E7j6HpOSbSQJPZ6zlRj+NK3jPxQ= github.com/ipfs/go-ipns v0.1.2 h1:O/s/0ht+4Jl9+VoxoUo0zaHjnZUS+aBQIKTuzdZ/ucI= github.com/ipfs/go-ipns v0.1.2/go.mod h1:ioQ0j02o6jdIVW+bmi18f4k2gRf0AV3kZ9KeHYHICnQ= github.com/ipfs/go-log v0.0.1/go.mod h1:kL1d2/hzSpI0thNYjiKfjanbVNU+IIGA/WnNESY9leM= @@ -514,54 +527,53 @@ github.com/ipfs/go-log/v2 v2.1.3/go.mod h1:/8d0SH3Su5Ooc31QlL1WysJhvyOTDCjcCZ9Ax github.com/ipfs/go-log/v2 v2.3.0 h1:31Re/cPqFHpsRHgyVwjWADPoF0otB1WrjTy8ZFYwEZU= github.com/ipfs/go-log/v2 v2.3.0/go.mod h1:QqGoj30OTpnKaG/LKTGTxoP2mmQtjVMEnK72gynbe/g= github.com/ipfs/go-merkledag v0.0.6/go.mod h1:QYPdnlvkOg7GnQRofu9XZimC5ZW5Wi3bKys/4GQQfto= -github.com/ipfs/go-merkledag v0.1.0/go.mod h1:SQiXrtSts3KGNmgOzMICy5c0POOpUNQLvB3ClKnBAlk= github.com/ipfs/go-merkledag v0.2.3/go.mod h1:SQiXrtSts3KGNmgOzMICy5c0POOpUNQLvB3ClKnBAlk= -github.com/ipfs/go-merkledag v0.3.0/go.mod h1:4pymaZLhSLNVuiCITYrpViD6vmfZ/Ws4n/L9tfNv3S4= -github.com/ipfs/go-merkledag v0.3.1/go.mod h1:fvkZNNZixVW6cKSZ/JfLlON5OlgTXNdRLz0p6QG/I2M= github.com/ipfs/go-merkledag v0.3.2/go.mod h1:fvkZNNZixVW6cKSZ/JfLlON5OlgTXNdRLz0p6QG/I2M= -github.com/ipfs/go-merkledag v0.4.0 h1:ixNu/5MJSaT/Qs073T0/HsWKwnOoBgqSq1g+GaJIen0= github.com/ipfs/go-merkledag v0.4.0/go.mod h1:XshXBkhyeS63YNGisLL1uDSfuTyrQIxVUOg3ojR5MOE= +github.com/ipfs/go-merkledag v0.5.1 h1:tr17GPP5XtPhvPPiWtu20tSGZiZDuTaJRXBLcr79Umk= +github.com/ipfs/go-merkledag v0.5.1/go.mod h1:cLMZXx8J08idkp5+id62iVftUQV+HlYJ3PIhDfZsjA4= github.com/ipfs/go-metrics-interface v0.0.1 h1:j+cpbjYvu4R8zbleSs36gvB7jR+wsL2fGD6n0jO4kdg= github.com/ipfs/go-metrics-interface v0.0.1/go.mod h1:6s6euYU4zowdslK0GKHmqaIZ3j/b/tL7HTWtJ4VPgWY= github.com/ipfs/go-metrics-prometheus v0.0.2/go.mod h1:ELLU99AQQNi+zX6GCGm2lAgnzdSH3u5UVlCdqSXnEks= -github.com/ipfs/go-mfs v0.1.2 h1:DlelNSmH+yz/Riy0RjPKlooPg0KML4lXGdLw7uZkfAg= -github.com/ipfs/go-mfs v0.1.2/go.mod h1:T1QBiZPEpkPLzDqEJLNnbK55BVKVlNi2a+gVm4diFo0= -github.com/ipfs/go-namesys v0.3.1 h1:DqmeXlVODejOyECAqoqhSB5JGRv8aRFhtG0oPDmxsMc= -github.com/ipfs/go-namesys v0.3.1/go.mod h1:/BL4xk8LP5Lq82AmaRKyxZv/eYRlumNiU9SZUe1Hlps= +github.com/ipfs/go-mfs v0.2.1 h1:5jz8+ukAg/z6jTkollzxGzhkl3yxm022Za9f2nL5ab8= +github.com/ipfs/go-mfs v0.2.1/go.mod h1:Woj80iuw4ajDnIP6+seRaoHpPsc9hmL0pk/nDNDWP88= +github.com/ipfs/go-namesys v0.4.0 h1:Gxg4kEWxVcHuUJl60KMNs1k8AiVB3luXbz8ZJkSGacs= +github.com/ipfs/go-namesys v0.4.0/go.mod h1:jpJwzodyP8DZdWN6DShRjVZw6gaqMr4nQLBSxU5cR6E= github.com/ipfs/go-path v0.0.7/go.mod h1:6KTKmeRnBXgqrTvzFrPV3CamxcgvXX/4z79tfAd2Sno= github.com/ipfs/go-path v0.0.9/go.mod h1:VpDkSBKQ9EFQOUgi54Tq/O/tGi8n1RfYNks13M3DEs8= github.com/ipfs/go-path v0.1.1/go.mod h1:vC8q4AKOtrjJz2NnllIrmr2ZbGlF5fW2OKKyhV9ggb0= -github.com/ipfs/go-path v0.1.2 h1:yQxN9JNhO4KbaaYtVgVpIH0BQDzn5Zpl5A6to93O7Ck= -github.com/ipfs/go-path v0.1.2/go.mod h1:3DdbxZb0PtT0g3UlMqyzms1UBKPc0pQ2NHx5/XScYdY= +github.com/ipfs/go-path v0.2.1 h1:R0JYCu0JBnfa6A3C42nzsNPxtKU5/fnUPhWSuzcJHws= +github.com/ipfs/go-path v0.2.1/go.mod h1:NOScsVgxfC/eIw4nz6OiGwK42PjaSJ4Y/ZFPn1Xe07I= github.com/ipfs/go-peertaskqueue v0.0.4/go.mod h1:03H8fhyeMfKNFWqzYEVyMbcPUeYrqP1MX6Kd+aN+rMQ= github.com/ipfs/go-peertaskqueue v0.1.0/go.mod h1:Jmk3IyCcfl1W3jTW3YpghSwSEC6IJ3Vzz/jUmWw8Z0U= github.com/ipfs/go-peertaskqueue v0.1.1/go.mod h1:Jmk3IyCcfl1W3jTW3YpghSwSEC6IJ3Vzz/jUmWw8Z0U= github.com/ipfs/go-peertaskqueue v0.2.0/go.mod h1:5/eNrBEbtSKWCG+kQK8K8fGNixoYUnr+P7jivavs9lY= -github.com/ipfs/go-peertaskqueue v0.4.0 h1:x1hFgA4JOUJ3ntPfqLRu6v4k6kKL0p07r3RSg9JNyHI= -github.com/ipfs/go-peertaskqueue v0.4.0/go.mod h1:KL9F49hXJMoXCad8e5anivjN+kWdr+CyGcyh4K6doLc= +github.com/ipfs/go-peertaskqueue v0.7.0 h1:VyO6G4sbzX80K58N60cCaHsSsypbUNs1GjO5seGNsQ0= +github.com/ipfs/go-peertaskqueue v0.7.0/go.mod h1:M/akTIE/z1jGNXMU7kFB4TeSEFvj68ow0Rrb04donIU= github.com/ipfs/go-pinning-service-http-client v0.1.0/go.mod h1:tcCKmlkWWH9JUUkKs8CrOZBanacNc1dmKLfjlyXAMu4= -github.com/ipfs/go-unixfs v0.1.0/go.mod h1:lysk5ELhOso8+Fed9U1QTGey2ocsfaZ18h0NCO2Fj9s= github.com/ipfs/go-unixfs v0.2.4/go.mod h1:SUdisfUjNoSDzzhGVxvCL9QO/nKdwXdr+gbMUdqcbYw= -github.com/ipfs/go-unixfs v0.2.5 h1:irj/WzIcgTBay48mSMUYDbKlIzIocXWcuUUsi5qOMOE= -github.com/ipfs/go-unixfs v0.2.5/go.mod h1:SUdisfUjNoSDzzhGVxvCL9QO/nKdwXdr+gbMUdqcbYw= +github.com/ipfs/go-unixfs v0.3.1 h1:LrfED0OGfG98ZEegO4/xiprx2O+yS+krCMQSp7zLVv8= +github.com/ipfs/go-unixfs v0.3.1/go.mod h1:h4qfQYzghiIc8ZNFKiLMFWOTzrWIAtzYQ59W/pCFf1o= github.com/ipfs/go-unixfsnode v1.1.2/go.mod h1:5dcE2x03pyjHk4JjamXmunTMzz+VUtqvPwZjIEkfV6s= github.com/ipfs/go-unixfsnode v1.1.3 h1:IyqJBGIEvcHvll1wDDVIHOEVXnE+IH6tjzTWpZ6kGiI= github.com/ipfs/go-unixfsnode v1.1.3/go.mod h1:ZZxUM5wXBC+G0Co9FjrYTOm+UlhZTjxLfRYdWY9veZ4= github.com/ipfs/go-verifcid v0.0.1 h1:m2HI7zIuR5TFyQ1b79Da5N9dnnCP1vcu2QqawmWlK2E= github.com/ipfs/go-verifcid v0.0.1/go.mod h1:5Hrva5KBeIog4A+UpqlaIU+DEstipcJYQQZc0g37pY0= github.com/ipfs/interface-go-ipfs-core v0.4.0/go.mod h1:UJBcU6iNennuI05amq3FQ7g0JHUkibHFAfhfUIy927o= -github.com/ipfs/interface-go-ipfs-core v0.5.1 h1:1KMM7RkjUD8W5fSoRsa9xR6ZMzeL8fLHOUM1UEW9Y4M= -github.com/ipfs/interface-go-ipfs-core v0.5.1/go.mod h1:lNBJrdXHtWS46evMPBdWtDQMDsrKcGbxCOGoKLkztOE= -github.com/ipfs/tar-utils v0.0.1/go.mod h1:ACflm9wXvV9w0eMJt6yYXxS2zuIV+yXGNwbuq1bhLeE= -github.com/ipld/go-car v0.3.1/go.mod h1:dPkEWeAK8KaVvH5TahaCs6Mncpd4lDMpkbs0/SPzuVs= +github.com/ipfs/interface-go-ipfs-core v0.5.2 h1:m1/5U+WpOK2ZE7Qzs5iIu80QM1ZA3aWYi2Ilwpi+tdg= +github.com/ipfs/interface-go-ipfs-core v0.5.2/go.mod h1:lNBJrdXHtWS46evMPBdWtDQMDsrKcGbxCOGoKLkztOE= +github.com/ipfs/tar-utils v0.0.2/go.mod h1:4qlnRWgTVljIMhSG2SqRYn66NT+3wrv/kZt9V+eqxDM= +github.com/ipld/go-car v0.3.2/go.mod h1:WEjynkVt04dr0GwJhry0KlaTeSDEiEYyMPOxDBQ17KE= github.com/ipld/go-codec-dagpb v1.2.0/go.mod h1:6nBN7X7h8EOsEejZGqC7tej5drsdBAXbMHyBT+Fne5s= github.com/ipld/go-codec-dagpb v1.3.0 h1:czTcaoAuNNyIYWs6Qe01DJ+sEX7B+1Z0LcXjSatMGe8= github.com/ipld/go-codec-dagpb v1.3.0/go.mod h1:ga4JTU3abYApDC3pZ00BC2RSvC3qfBb9MSJkMLSwnhA= github.com/ipld/go-ipld-prime v0.9.0/go.mod h1:KvBLMr4PX1gWptgkzRjVZCrLmSGcZCb/jioOQwCqZN8= github.com/ipld/go-ipld-prime v0.9.1-0.20210324083106-dc342a9917db/go.mod h1:KvBLMr4PX1gWptgkzRjVZCrLmSGcZCb/jioOQwCqZN8= github.com/ipld/go-ipld-prime v0.11.0/go.mod h1:+WIAkokurHmZ/KwzDOMUuoeJgaRQktHtEaLglS3ZeV8= -github.com/ipld/go-ipld-prime v0.12.2 h1:StIquYvKIRuSEAtjJDr39fyzBtziioHPwVC75tBiXzo= -github.com/ipld/go-ipld-prime v0.12.2/go.mod h1:PaeLYq8k6dJLmDUSLrzkEpoGV4PEfe/1OtFN/eALOc8= +github.com/ipld/go-ipld-prime v0.12.3/go.mod h1:PaeLYq8k6dJLmDUSLrzkEpoGV4PEfe/1OtFN/eALOc8= +github.com/ipld/go-ipld-prime v0.14.1/go.mod h1:QcE4Y9n/ZZr8Ijg5bGPT0GqYWgZ1704nH0RDcQtgTP0= +github.com/ipld/go-ipld-prime v0.14.2 h1:P5fO2usnisXwrN/1sR5exCgEvINg/w/27EuYPKB/zx8= +github.com/ipld/go-ipld-prime v0.14.2/go.mod h1:QcE4Y9n/ZZr8Ijg5bGPT0GqYWgZ1704nH0RDcQtgTP0= github.com/jackpal/gateway v1.0.5/go.mod h1:lTpwd4ACLXmpyiCTRtfiNyVnUmqT9RivzCDQetPfnjA= github.com/jackpal/go-nat-pmp v1.0.1/go.mod h1:QPH045xvCAeXUZOxsnwmrtiCoxIr9eob+4orBN1SBKc= github.com/jackpal/go-nat-pmp v1.0.2 h1:KzKSgb7qkJvOUTqYl9/Hg/me3pWgBmERKrTGD7BdWus= @@ -588,7 +600,6 @@ github.com/jrick/logrotate v1.0.0/go.mod h1:LNinyqDIJnpAur+b8yyulnQw/wDuN1+BYKlT github.com/json-iterator/go v1.1.6/go.mod h1:+SdeFBvtyEkXs7REEP0seUULqWtbJapLOCVDaaPEHmU= github.com/json-iterator/go v1.1.7/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4= github.com/json-iterator/go v1.1.8/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4= -github.com/json-iterator/go v1.1.9/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4= github.com/json-iterator/go v1.1.10/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4= github.com/json-iterator/go v1.1.11/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4= github.com/jstemmer/go-junit-report v0.0.0-20190106144839-af01ea7f8024/go.mod h1:6v2b51hI/fHJwM22ozAgKL4VKDeJcHhJFhtBdhmNjmU= @@ -619,12 +630,14 @@ github.com/koron/go-ssdp v0.0.2/go.mod h1:XoLfkAiA2KeZsYh4DbHxD7h3nR2AZNqVQOa+LJ github.com/kr/logfmt v0.0.0-20140226030751-b84e30acd515/go.mod h1:+0opPa2QZZtGFBFZlji/RkVcI2GknAs/DXo4wKdlNEc= github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo= github.com/kr/pretty v0.2.0/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfnI= -github.com/kr/pretty v0.2.1 h1:Fmg33tUaq4/8ym9TJN1x7sLJnHVwhP33CNkpYV/7rwI= github.com/kr/pretty v0.2.1/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfnI= +github.com/kr/pretty v0.3.0 h1:WgNl7dwNpEZ6jJ9k1snq4pZsg7DOEN8hP9Xw0Tsjwk0= +github.com/kr/pretty v0.3.0/go.mod h1:640gp4NfQd8pI5XOwp5fnNeVWj67G7CFk/SaSQn7NBk= github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= github.com/kr/pty v1.1.3/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= -github.com/kr/text v0.1.0 h1:45sCR5RtlFHMR4UwH9sdQ5TC8v0qDQCHnXt+kaKSTVE= github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= +github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY= +github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE= github.com/libp2p/go-addr-util v0.0.1/go.mod h1:4ac6O7n9rIAKB1dnd+s8IbbMXkt+oBpzX4/+RACcnlQ= github.com/libp2p/go-addr-util v0.0.2/go.mod h1:Ecd6Fb3yIuLzq4bD7VcywcVSBtefcAwnUISBM3WG15E= github.com/libp2p/go-addr-util v0.1.0 h1:acKsntI33w2bTU7tC9a0SaPimJGfSI0bFKC18ChxeVI= @@ -662,8 +675,8 @@ github.com/libp2p/go-libp2p v0.13.0/go.mod h1:pM0beYdACRfHO1WcJlp65WXyG2A6NqYM+t github.com/libp2p/go-libp2p v0.14.0/go.mod h1:dsQrWLAoIn+GkHPN/U+yypizkHiB9tnv79Os+kSgQ4Q= github.com/libp2p/go-libp2p v0.14.3/go.mod h1:d12V4PdKbpL0T1/gsUNN8DfgMuRPDX8bS2QxCZlwRH0= github.com/libp2p/go-libp2p v0.14.4/go.mod h1:EIRU0Of4J5S8rkockZM7eJp2S0UrCyi55m2kJVru3rM= -github.com/libp2p/go-libp2p v0.15.0-rc.1.0.20211021081216-db8f9c6fddb5 h1:nE20CmFlCbwN56/3bADccjHEvbM9E9hFe7Y+0ebdpig= -github.com/libp2p/go-libp2p v0.15.0-rc.1.0.20211021081216-db8f9c6fddb5/go.mod h1:P+WgjkSS2d8eBj+NvkyKo0nb8fJAC04G+cCex0ZMcvI= +github.com/libp2p/go-libp2p v0.16.0 h1:aTxzQPllnW+nyC9mY8xaS20BbcrSYMt1HCkjZRHvdGY= +github.com/libp2p/go-libp2p v0.16.0/go.mod h1:ump42BsirwAWxKzsCiFnTtN1Yc+DuPu76fyMX364/O4= github.com/libp2p/go-libp2p-asn-util v0.0.0-20200825225859-85005c6cf052/go.mod h1:nRMRTab+kZuk0LnKZpxhOVH/ndsdr2Nr//Zltc/vwgo= github.com/libp2p/go-libp2p-asn-util v0.1.0 h1:rABPCO77SjdbJ/eJ/ynIo8vWICy1VEnL5JAxJbQLo1E= github.com/libp2p/go-libp2p-asn-util v0.1.0/go.mod h1:wu+AnM9Ii2KgO5jMmS1rz9dvzTdj8BXqsPR9HR0XB7I= @@ -675,8 +688,8 @@ github.com/libp2p/go-libp2p-autonat v0.2.1/go.mod h1:MWtAhV5Ko1l6QBsHQNSuM6b1sRk github.com/libp2p/go-libp2p-autonat v0.2.2/go.mod h1:HsM62HkqZmHR2k1xgX34WuWDzk/nBwNHoeyyT4IWV6A= github.com/libp2p/go-libp2p-autonat v0.4.0/go.mod h1:YxaJlpr81FhdOv3W3BTconZPfhaYivRdf53g+S2wobk= github.com/libp2p/go-libp2p-autonat v0.4.2/go.mod h1:YxaJlpr81FhdOv3W3BTconZPfhaYivRdf53g+S2wobk= -github.com/libp2p/go-libp2p-autonat v0.5.0 h1:/+3+4NcQV47DQ/duvRyFDP8oxv6CQTvSKYD5iWoPcYs= -github.com/libp2p/go-libp2p-autonat v0.5.0/go.mod h1:085tmmuXn0nXgFwuF7a2tt4UxgTjuapbuml27v4htKY= +github.com/libp2p/go-libp2p-autonat v0.6.0 h1:+vbQ1pMzMGjE/RJopiQKK2FRjdCKHPNPrkPm8u+luQU= +github.com/libp2p/go-libp2p-autonat v0.6.0/go.mod h1:bFC6kY8jwzNNWoqc8iGE57vsfwyJ/lP4O4DOV1e0B2o= github.com/libp2p/go-libp2p-blankhost v0.0.1/go.mod h1:Ibpbw/7cPPYwFb7PACIWdvxxv0t0XCCI10t7czjAjTc= github.com/libp2p/go-libp2p-blankhost v0.1.1/go.mod h1:pf2fvdLJPsC1FsVrNP3DUUvMzUts2dsLLBEpo1vW1ro= github.com/libp2p/go-libp2p-blankhost v0.1.4/go.mod h1:oJF0saYsAXQCSfDq254GMNmLNz6ZTHTOvtF4ZydUvwU= @@ -728,8 +741,8 @@ github.com/libp2p/go-libp2p-discovery v0.1.0/go.mod h1:4F/x+aldVHjHDHuX85x1zWoFT github.com/libp2p/go-libp2p-discovery v0.2.0/go.mod h1:s4VGaxYMbw4+4+tsoQTqh7wfxg97AEdo4GYBt6BadWg= github.com/libp2p/go-libp2p-discovery v0.3.0/go.mod h1:o03drFnz9BVAZdzC/QUQ+NeQOu38Fu7LJGEOK2gQltw= github.com/libp2p/go-libp2p-discovery v0.5.0/go.mod h1:+srtPIU9gDaBNu//UHvcdliKBIcr4SfDcm0/PfPJLug= -github.com/libp2p/go-libp2p-discovery v0.5.1 h1:CJylx+h2+4+s68GvrM4pGNyfNhOYviWBPtVv5PA7sfo= -github.com/libp2p/go-libp2p-discovery v0.5.1/go.mod h1:+srtPIU9gDaBNu//UHvcdliKBIcr4SfDcm0/PfPJLug= +github.com/libp2p/go-libp2p-discovery v0.6.0 h1:1XdPmhMJr8Tmj/yUfkJMIi8mgwWrLUsCB3bMxdT+DSo= +github.com/libp2p/go-libp2p-discovery v0.6.0/go.mod h1:/u1voHt0tKIe5oIA1RHBKQLVCWPna2dXmPNHc2zR9S8= github.com/libp2p/go-libp2p-gostream v0.3.0/go.mod h1:pLBQu8db7vBMNINGsAwLL/ZCE8wng5V1FThoaE5rNjc= github.com/libp2p/go-libp2p-host v0.0.1/go.mod h1:qWd+H1yuU0m5CwzAkvbSjqKairayEHdR5MMl7Cwa7Go= github.com/libp2p/go-libp2p-host v0.0.3/go.mod h1:Y/qPyA6C8j2coYyos1dfRm0I8+nvd4TGrDGt4tA7JR8= @@ -738,9 +751,8 @@ github.com/libp2p/go-libp2p-interface-connmgr v0.0.1/go.mod h1:GarlRLH0LdeWcLnYM github.com/libp2p/go-libp2p-interface-connmgr v0.0.4/go.mod h1:GarlRLH0LdeWcLnYM/SaBykKFl9U5JFnbBGruAk/D5k= github.com/libp2p/go-libp2p-interface-connmgr v0.0.5/go.mod h1:GarlRLH0LdeWcLnYM/SaBykKFl9U5JFnbBGruAk/D5k= github.com/libp2p/go-libp2p-interface-pnet v0.0.1/go.mod h1:el9jHpQAXK5dnTpKA4yfCNBZXvrzdOU75zz+C6ryp3k= -github.com/libp2p/go-libp2p-kad-dht v0.11.1/go.mod h1:5ojtR2acDPqh/jXf5orWy8YGb8bHQDS+qeDcoscL/PI= -github.com/libp2p/go-libp2p-kad-dht v0.13.1 h1:wQgzOpoc+dcPVDb3h0HNWUjon5JiYEqsA4iNBUtIA7A= -github.com/libp2p/go-libp2p-kad-dht v0.13.1/go.mod h1:iVdxmsKHVPQSCGPP4V/A+tDFCLsxrREZUBX8ohOcKDw= +github.com/libp2p/go-libp2p-kad-dht v0.15.0 h1:Ke+Oj78gX5UDXnA6HBdrgvi+fStJxgYTDa51U0TsCLo= +github.com/libp2p/go-libp2p-kad-dht v0.15.0/go.mod h1:rZtPxYu1TnHHz6n1RggdGrxUX/tA1C2/Wiw3ZMUDrU0= github.com/libp2p/go-libp2p-kbucket v0.3.1/go.mod h1:oyjT5O7tS9CQurok++ERgc46YLwEpuGoFq9ubvoUOio= github.com/libp2p/go-libp2p-kbucket v0.4.7 h1:spZAcgxifvFZHBD8tErvppbnNiKA5uokDu3CV7axu70= github.com/libp2p/go-libp2p-kbucket v0.4.7/go.mod h1:XyVo99AfQH0foSf176k4jY1xUJ2+jUJIZCSDm7r2YKk= @@ -785,25 +797,23 @@ github.com/libp2p/go-libp2p-peerstore v0.2.2/go.mod h1:NQxhNjWxf1d4w6PihR8btWIRj github.com/libp2p/go-libp2p-peerstore v0.2.6/go.mod h1:ss/TWTgHZTMpsU/oKVVPQCGuDHItOpf2W8RxAi50P2s= github.com/libp2p/go-libp2p-peerstore v0.2.7/go.mod h1:ss/TWTgHZTMpsU/oKVVPQCGuDHItOpf2W8RxAi50P2s= github.com/libp2p/go-libp2p-peerstore v0.2.8/go.mod h1:gGiPlXdz7mIHd2vfAsHzBNAMqSDkt2UBFwgcITgw1lA= -github.com/libp2p/go-libp2p-peerstore v0.3.0 h1:wp/G0+37+GLr7tu+wE+4GWNrA3uxKg6IPRigIMSS5oQ= -github.com/libp2p/go-libp2p-peerstore v0.3.0/go.mod h1:fNX9WlOENMvdx/YD7YO/5Hkrn8+lQIk5A39BHa1HIrM= +github.com/libp2p/go-libp2p-peerstore v0.4.0 h1:DOhRJLnM9Dc9lIXi3rPDZBf789LXy1BrzwIs7Tj0cKA= +github.com/libp2p/go-libp2p-peerstore v0.4.0/go.mod h1:rDJUFyzEWPpXpEwywkcTYYzDHlwza8riYMaUzaN6hX0= github.com/libp2p/go-libp2p-pnet v0.2.0 h1:J6htxttBipJujEjz1y0a5+eYoiPcFHhSYHH6na5f0/k= github.com/libp2p/go-libp2p-pnet v0.2.0/go.mod h1:Qqvq6JH/oMZGwqs3N1Fqhv8NVhrdYcO0BW4wssv21LA= github.com/libp2p/go-libp2p-protocol v0.0.1/go.mod h1:Af9n4PiruirSDjHycM1QuiMi/1VZNHYcK8cLgFJLZ4s= github.com/libp2p/go-libp2p-protocol v0.1.0/go.mod h1:KQPHpAabB57XQxGrXCNvbL6UEXfQqUgC/1adR2Xtflk= -github.com/libp2p/go-libp2p-pubsub v0.4.0/go.mod h1:izkeMLvz6Ht8yAISXjx60XUQZMq9ZMe5h2ih4dLIBIQ= -github.com/libp2p/go-libp2p-pubsub v0.5.4 h1:rHl9/Xok4zX3zgi0pg0XnUj9Xj2OeXO8oTu85q2+YA8= -github.com/libp2p/go-libp2p-pubsub v0.5.4/go.mod h1:gVOzwebXVdSMDQBTfH8ACO5EJ4SQrvsHqCmYsCZpD0E= -github.com/libp2p/go-libp2p-pubsub-router v0.4.0 h1:KjzTLIOBCt0+/4wH6epTxD/Qu4Up/IyeKHlj9MhWRJI= -github.com/libp2p/go-libp2p-pubsub-router v0.4.0/go.mod h1:hs0j0ugcBjMOMgJ6diOlZM2rZEId/w5Gg86E+ac4SmQ= +github.com/libp2p/go-libp2p-pubsub v0.6.0 h1:98+RXuEWW17U6cAijK1yaTf6mw/B+n5yPA421z+dlo0= +github.com/libp2p/go-libp2p-pubsub v0.6.0/go.mod h1:nJv87QM2cU0w45KPR1rZicq+FmFIOD16zmT+ep1nOmg= +github.com/libp2p/go-libp2p-pubsub-router v0.5.0 h1:WuYdY42DVIJ+N0qMdq2du/E9poJH+xzsXL7Uptwj9tw= +github.com/libp2p/go-libp2p-pubsub-router v0.5.0/go.mod h1:TRJKskSem3C0aSb3CmRgPwq6IleVFzds6hS09fmZbGM= github.com/libp2p/go-libp2p-quic-transport v0.10.0/go.mod h1:RfJbZ8IqXIhxBRm5hqUEJqjiiY8xmEuq3HUDS993MkA= github.com/libp2p/go-libp2p-quic-transport v0.11.2/go.mod h1:wlanzKtIh6pHrq+0U3p3DY9PJfGqxMgPaGKaK5LifwQ= github.com/libp2p/go-libp2p-quic-transport v0.13.0/go.mod h1:39/ZWJ1TW/jx1iFkKzzUg00W6tDJh73FC0xYudjr7Hc= -github.com/libp2p/go-libp2p-quic-transport v0.14.0 h1:sBjT/8zKv8otFZh3Uhdxl91BhwXwuHAOB5lJgbT2zyk= -github.com/libp2p/go-libp2p-quic-transport v0.14.0/go.mod h1:/W4njiXIRowKk62w6j4y4dVpBZvEk9WtGOtOYh2M6J8= +github.com/libp2p/go-libp2p-quic-transport v0.15.0 h1:DR0mP6kcieowikBprWkcNtbquRKOPWb5dLZ4ahDZujk= +github.com/libp2p/go-libp2p-quic-transport v0.15.0/go.mod h1:wv4uGwjcqe8Mhjj7N/Ic0aKjA+/10UnMlSzLO0yRpYQ= github.com/libp2p/go-libp2p-record v0.0.1/go.mod h1:grzqg263Rug/sRex85QrDOLntdFAymLDLm7lxMgU79Q= github.com/libp2p/go-libp2p-record v0.1.0/go.mod h1:ujNc8iuE5dlKWVy6wuL6dd58t0n7xI4hAIl8pE6wu5Q= -github.com/libp2p/go-libp2p-record v0.1.1/go.mod h1:VRgKajOyMVgP/F0L5g3kH7SVskp17vFi2xheb5uMJtg= github.com/libp2p/go-libp2p-record v0.1.2/go.mod h1:pal0eNcT5nqZaTV7UGhqeGqxFgGdsU/9W//C8dqjQDk= github.com/libp2p/go-libp2p-record v0.1.3 h1:R27hoScIhQf/A8XJZ8lYpnqh9LatJ5YbHs28kCIfql0= github.com/libp2p/go-libp2p-record v0.1.3/go.mod h1:yNUff/adKIfPnYQXgp6FQmNu3gLJ6EMg7+/vv2+9pY4= @@ -825,8 +835,8 @@ github.com/libp2p/go-libp2p-swarm v0.3.1/go.mod h1:hdv95GWCTmzkgeJpP+GK/9D9puJeg github.com/libp2p/go-libp2p-swarm v0.4.0/go.mod h1:XVFcO52VoLoo0eitSxNQWYq4D6sydGOweTOAjJNraCw= github.com/libp2p/go-libp2p-swarm v0.5.0/go.mod h1:sU9i6BoHE0Ve5SKz3y9WfKrh8dUat6JknzUehFx8xW4= github.com/libp2p/go-libp2p-swarm v0.5.3/go.mod h1:NBn7eNW2lu568L7Ns9wdFrOhgRlkRnIDg0FLKbuu3i8= -github.com/libp2p/go-libp2p-swarm v0.7.0 h1:ZohJ/XtPP0O73Y1BeCvRRfBcoBfZkqRiKmBwKQfnYGg= -github.com/libp2p/go-libp2p-swarm v0.7.0/go.mod h1:Ii3RNGBC+CMIO3BzK/hmzzriJUOkCVT7viOd+alyEPY= +github.com/libp2p/go-libp2p-swarm v0.8.0 h1:nRHNRhi86L7jhka02N4MoV+PSFFPoJFkHNQwCTFxNhw= +github.com/libp2p/go-libp2p-swarm v0.8.0/go.mod h1:sOMp6dPuqco0r0GHTzfVheVBh6UEL0L1lXUZ5ot2Fvc= github.com/libp2p/go-libp2p-testing v0.0.1/go.mod h1:gvchhf3FQOtBdr+eFUABet5a4MBLK8jM3V4Zghvmi+E= github.com/libp2p/go-libp2p-testing v0.0.2/go.mod h1:gvchhf3FQOtBdr+eFUABet5a4MBLK8jM3V4Zghvmi+E= github.com/libp2p/go-libp2p-testing v0.0.3/go.mod h1:gvchhf3FQOtBdr+eFUABet5a4MBLK8jM3V4Zghvmi+E= @@ -840,8 +850,9 @@ github.com/libp2p/go-libp2p-testing v0.4.2/go.mod h1:Q+PFXYoiYFN5CAEG2w3gLPEzotl github.com/libp2p/go-libp2p-testing v0.5.0 h1:bTjC29TTQ/ODq0ld3+0KLq3irdA5cAH3OMbRi0/QsvE= github.com/libp2p/go-libp2p-testing v0.5.0/go.mod h1:QBk8fqIL1XNcno/l3/hhaIEn4aLRijpYOR+zVjjlh+A= github.com/libp2p/go-libp2p-tls v0.1.3/go.mod h1:wZfuewxOndz5RTnCAxFliGjvYSDA40sKitV4c50uI1M= -github.com/libp2p/go-libp2p-tls v0.3.0 h1:8BgvUJiOTcj0Gp6XvEicF0rL5aUtRg/UzEdeZDmDlC8= github.com/libp2p/go-libp2p-tls v0.3.0/go.mod h1:fwF5X6PWGxm6IDRwF3V8AVCCj/hOd5oFlg+wo2FxJDY= +github.com/libp2p/go-libp2p-tls v0.3.1 h1:lsE2zYte+rZCEOHF72J1Fg3XK3dGQyKvI6i5ehJfEp0= +github.com/libp2p/go-libp2p-tls v0.3.1/go.mod h1:fwF5X6PWGxm6IDRwF3V8AVCCj/hOd5oFlg+wo2FxJDY= github.com/libp2p/go-libp2p-transport v0.0.1/go.mod h1:UzbUs9X+PHOSw7S3ZmeOxfnwaQY5vGDzZmKPod3N3tk= github.com/libp2p/go-libp2p-transport v0.0.5/go.mod h1:StoY3sx6IqsP6XKoabsPnHCwqKXWUMWU7Rfcsubee/A= github.com/libp2p/go-libp2p-transport-upgrader v0.0.4/go.mod h1:RGq+tupk+oj7PzL2kn/m1w6YXxcIAYJYeI90h6BGgUc= @@ -868,8 +879,9 @@ github.com/libp2p/go-libp2p-yamux v0.4.0/go.mod h1:+DWDjtFMzoAwYLVkNZftoucn7PelN github.com/libp2p/go-libp2p-yamux v0.5.0/go.mod h1:AyR8k5EzyM2QN9Bbdg6X1SkVVuqLwTGf0L4DFq9g6po= github.com/libp2p/go-libp2p-yamux v0.5.1/go.mod h1:dowuvDu8CRWmr0iqySMiSxK+W0iL5cMVO9S94Y6gkv4= github.com/libp2p/go-libp2p-yamux v0.5.3/go.mod h1:Vy3TMonBAfTMXHWopsMc8iX/XGRYrRlpUaMzaeuHV/s= -github.com/libp2p/go-libp2p-yamux v0.5.4 h1:/UOPtT/6DHPtr3TtKXBHa6g0Le0szYuI33Xc/Xpd7fQ= github.com/libp2p/go-libp2p-yamux v0.5.4/go.mod h1:tfrXbyaTqqSU654GTvK3ocnSZL3BuHoeTSqhcel1wsE= +github.com/libp2p/go-libp2p-yamux v0.6.0 h1:TKayW983n92JhCGdCo7ej7eEb+DQ0VYfKNOxlN/1kNQ= +github.com/libp2p/go-libp2p-yamux v0.6.0/go.mod h1:MRhd6mAYnFRnSISp4M8i0ClV/j+mWHo2mYLifWGw33k= github.com/libp2p/go-maddr-filter v0.0.1/go.mod h1:6eT12kSQMA9x2pvFQa+xesMKUBlj9VImZbj3B9FBH/Q= github.com/libp2p/go-maddr-filter v0.0.4/go.mod h1:6eT12kSQMA9x2pvFQa+xesMKUBlj9VImZbj3B9FBH/Q= github.com/libp2p/go-maddr-filter v0.0.5/go.mod h1:Jk+36PMfIqCJhAnaASRH83bdAvfDRp/w6ENFaC9bG+M= @@ -958,8 +970,9 @@ github.com/libp2p/go-yamux v1.4.1 h1:P1Fe9vF4th5JOxxgQvfbOHkrGqIZniTLf+ddhZp8YTI github.com/libp2p/go-yamux v1.4.1/go.mod h1:fr7aVgmdNGJK+N1g+b6DW6VxzbRCjCOejR/hkmpooHE= github.com/libp2p/go-yamux/v2 v2.0.0/go.mod h1:NVWira5+sVUIU6tu1JWvaRn1dRnG+cawOJiflsAM+7U= github.com/libp2p/go-yamux/v2 v2.1.1/go.mod h1:3So6P6TV6r75R9jiBpiIKgU/66lOarCZjqROGxzPpPQ= -github.com/libp2p/go-yamux/v2 v2.2.0 h1:RwtpYZ2/wVviZ5+3pjC8qdQ4TKnrak0/E01N1UWoAFU= github.com/libp2p/go-yamux/v2 v2.2.0/go.mod h1:3So6P6TV6r75R9jiBpiIKgU/66lOarCZjqROGxzPpPQ= +github.com/libp2p/go-yamux/v2 v2.3.0 h1:luRV68GS1vqqr6EFUjtu1kr51d+IbW0gSowu8emYWAI= +github.com/libp2p/go-yamux/v2 v2.3.0/go.mod h1:iTU+lOIn/2h0AgKcL49clNTwfEw+WSfDYrXe05EyKIs= github.com/libp2p/zeroconf/v2 v2.1.1 h1:XAuSczA96MYkVwH+LqqqCUZb2yH3krobMJ1YE+0hG2s= github.com/libp2p/zeroconf/v2 v2.1.1/go.mod h1:fuJqLnUwZTshS3U/bMRJ3+ow/v9oid1n0DmyYyNO1Xs= github.com/lightstep/lightstep-tracer-common/golang/gogo v0.0.0-20190605223551-bc2310a04743/go.mod h1:qklhhLq1aX+mtWk9cPHPzaBjWImj5ULL6C7HFJtXQMM= @@ -1059,8 +1072,9 @@ github.com/multiformats/go-multiaddr v0.2.2/go.mod h1:NtfXiOtHvghW9KojvtySjH5y0u github.com/multiformats/go-multiaddr v0.3.0/go.mod h1:dF9kph9wfJ+3VLAaeBqo9Of8x4fJxp6ggJGteB8HQTI= github.com/multiformats/go-multiaddr v0.3.1/go.mod h1:uPbspcUPd5AfaP6ql3ujFY+QWzmBD8uLLL4bXW0XfGc= github.com/multiformats/go-multiaddr v0.3.3/go.mod h1:lCKNGP1EQ1eZ35Za2wlqnabm9xQkib3fyB+nZXHLag0= -github.com/multiformats/go-multiaddr v0.4.0 h1:hL/K4ZJhJ5PTw3nwylq9lGU5yArzcAroZmex1ghSEkQ= github.com/multiformats/go-multiaddr v0.4.0/go.mod h1:YcpyLH8ZPudLxQlemYBPhSm0/oCXAT8Z4mzFpyoPyRc= +github.com/multiformats/go-multiaddr v0.4.1 h1:Pq37uLx3hsyNlTDir7FZyU8+cFCTqd5y1KiM2IzOutI= +github.com/multiformats/go-multiaddr v0.4.1/go.mod h1:3afI9HfVW8csiF8UZqtpYRiDyew8pRX7qLIGHu9FLuM= github.com/multiformats/go-multiaddr-dns v0.0.1/go.mod h1:9kWcqw/Pj6FwxAwW38n/9403szc57zJPs45fmnznu3Q= github.com/multiformats/go-multiaddr-dns v0.0.2/go.mod h1:9kWcqw/Pj6FwxAwW38n/9403szc57zJPs45fmnznu3Q= github.com/multiformats/go-multiaddr-dns v0.2.0/go.mod h1:TJ5pr5bBO7Y1B18djPuRsVkduhQH2YqYSbxWJzYGdK0= @@ -1091,8 +1105,10 @@ github.com/multiformats/go-multihash v0.0.9/go.mod h1:YSLudS+Pi8NHE7o6tb3D8vrpKa github.com/multiformats/go-multihash v0.0.10/go.mod h1:YSLudS+Pi8NHE7o6tb3D8vrpKa63epEDmG8nTduyAew= github.com/multiformats/go-multihash v0.0.13/go.mod h1:VdAWLKTwram9oKAatUcLxBNUjdtcVwxObEQBtRfuyjc= github.com/multiformats/go-multihash v0.0.14/go.mod h1:VdAWLKTwram9oKAatUcLxBNUjdtcVwxObEQBtRfuyjc= -github.com/multiformats/go-multihash v0.0.15 h1:hWOPdrNqDjwHDx82vsYGSDZNyktOJJ2dzZJzFkOV1jM= github.com/multiformats/go-multihash v0.0.15/go.mod h1:D6aZrWNLFTV/ynMpKsNtB40mJzmCl4jb1alC0OvHiHg= +github.com/multiformats/go-multihash v0.0.16/go.mod h1:zhfEIgVnB/rPMfxgFw15ZmGoNaKyNUIE4IWHG/kC+Ag= +github.com/multiformats/go-multihash v0.1.0 h1:CgAgwqk3//SVEw3T+6DqI4mWMyRuDwZtOWcJT0q9+EA= +github.com/multiformats/go-multihash v0.1.0/go.mod h1:RJlXsxt6vHGaia+S8We0ErjhojtKzPP2AH4+kYM7k84= github.com/multiformats/go-multistream v0.0.1/go.mod h1:fJTiDfXJVmItycydCnNx4+wSzZ5NwG2FEVAI30fiovg= github.com/multiformats/go-multistream v0.0.4/go.mod h1:fJTiDfXJVmItycydCnNx4+wSzZ5NwG2FEVAI30fiovg= github.com/multiformats/go-multistream v0.1.0/go.mod h1:fJTiDfXJVmItycydCnNx4+wSzZ5NwG2FEVAI30fiovg= @@ -1178,7 +1194,6 @@ github.com/prometheus/client_golang v0.9.2/go.mod h1:OsXs2jCmiKlQ1lTBmv21f2mNfw4 github.com/prometheus/client_golang v0.9.3-0.20190127221311-3c4408c8b829/go.mod h1:p2iRAGwDERtqlqzRXnrOVns+ignqQo//hLXqYxZYVNs= github.com/prometheus/client_golang v1.0.0/go.mod h1:db9x61etRT2tGnBNRi70OPL5FsnadC4Ky3P0J6CfImo= github.com/prometheus/client_golang v1.3.0/go.mod h1:hJaj2vgQTGQmVCsAACORcieXFeDPbaTKGT+JTgUa3og= -github.com/prometheus/client_golang v1.6.0/go.mod h1:ZLOG9ck3JLRdB5MgO8f+lLTe83AXG6ro35rLTxvnIl4= github.com/prometheus/client_golang v1.7.1/go.mod h1:PY5Wy2awLA44sXw4AOSfFBetzPP4j5+D6mVACh+pe2M= github.com/prometheus/client_golang v1.9.0/go.mod h1:FqZLKOZnGdFAhOK4nqGHa7D66IdsO+O441Eve7ptJDU= github.com/prometheus/client_golang v1.10.0/go.mod h1:WJM3cc3yu7XKBKa/I8WeZm+V3eltZnBwfENSU7mdogU= @@ -1196,7 +1211,6 @@ github.com/prometheus/common v0.0.0-20181126121408-4724e9255275/go.mod h1:daVV7q github.com/prometheus/common v0.2.0/go.mod h1:TNfzLD0ON7rHzMJeJkieUDPYmFC7Snx/y86RQel1bk4= github.com/prometheus/common v0.4.1/go.mod h1:TNfzLD0ON7rHzMJeJkieUDPYmFC7Snx/y86RQel1bk4= github.com/prometheus/common v0.7.0/go.mod h1:DjGbpBbp5NYNiECxcL/VnbXCCaQpKd3tt26CguLLsqA= -github.com/prometheus/common v0.9.1/go.mod h1:yhUN8i9wzaXS3w1O07YhxHEBxD+W35wd8bs7vj7HSQ4= github.com/prometheus/common v0.10.0/go.mod h1:Tlit/dnDKsSWFlCLTWaA1cyBgKHSMdTB80sz/V91rCo= github.com/prometheus/common v0.15.0/go.mod h1:U+gB1OBLb1lF3O42bTCL+FK18tX9Oar16Clt/msog/s= github.com/prometheus/common v0.18.0/go.mod h1:U+gB1OBLb1lF3O42bTCL+FK18tX9Oar16Clt/msog/s= @@ -1210,18 +1224,18 @@ github.com/prometheus/procfs v0.0.0-20181204211112-1dc9a6cbc91a/go.mod h1:c3At6R github.com/prometheus/procfs v0.0.0-20190117184657-bf6a532e95b1/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk= github.com/prometheus/procfs v0.0.2/go.mod h1:TjEm7ze935MbeOT/UhFTIMYKhuLP4wbCsTZCD3I8kEA= github.com/prometheus/procfs v0.0.8/go.mod h1:7Qr8sr6344vo1JqZ6HhLceV9o3AJ1Ff+GxbHq6oeK9A= -github.com/prometheus/procfs v0.0.11/go.mod h1:lV6e/gmhEcM9IjHGsFOCxxuZ+z1YqCvr4OA4YeYWdaU= github.com/prometheus/procfs v0.1.3/go.mod h1:lV6e/gmhEcM9IjHGsFOCxxuZ+z1YqCvr4OA4YeYWdaU= github.com/prometheus/procfs v0.2.0/go.mod h1:lV6e/gmhEcM9IjHGsFOCxxuZ+z1YqCvr4OA4YeYWdaU= github.com/prometheus/procfs v0.6.0/go.mod h1:cz+aTbrPOrUb4q7XlbU9ygM+/jj0fzG6c1xBZuNvfVA= github.com/prometheus/procfs v0.7.3 h1:4jVXhlkAyzOScmCkXBTOLRLTz8EeU+eyjrwB/EPq0VU= github.com/prometheus/procfs v0.7.3/go.mod h1:cz+aTbrPOrUb4q7XlbU9ygM+/jj0fzG6c1xBZuNvfVA= -github.com/prometheus/statsd_exporter v0.20.0/go.mod h1:YL3FWCG8JBBtaUSxAg4Gz2ZYu22bS84XM89ZQXXTWmQ= github.com/prometheus/statsd_exporter v0.21.0/go.mod h1:rbT83sZq2V+p73lHhPZfMc3MLCHmSHelCh9hSGYNLTQ= github.com/rcrowley/go-metrics v0.0.0-20181016184325-3113b8401b8a/go.mod h1:bCqnVzQkZxMG4s8nGwiZ5l3QUCyqpo9Y+/ZMZ9VjZe4= github.com/rogpeppe/fastuuid v0.0.0-20150106093220-6724a57986af/go.mod h1:XWv6SoW27p1b0cqNHllgS5HIMJraePCO15w5zCzIWYg= github.com/rogpeppe/fastuuid v1.2.0/go.mod h1:jVj6XXZzXRy/MSR5jhDC/2q6DgLz+nrA6LYCDYWNEvQ= github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4= +github.com/rogpeppe/go-internal v1.6.1 h1:/FiVV8dS/e+YqF2JvO3yXRFbBLTIuSDkuC7aBOAvL+k= +github.com/rogpeppe/go-internal v1.6.1/go.mod h1:xXDCJY+GAPziupqXw64V24skbSoqbTEfhy4qGm1nDQc= github.com/rs/cors v1.7.0/go.mod h1:gFx+x8UowdsKA9AchylcLynDq+nNFfI8FkUZdN/jGCU= github.com/russross/blackfriday v1.5.2/go.mod h1:JO/DiYxRf+HjHt06OyowR9PTA263kcR/rfWxYHBV53g= github.com/russross/blackfriday/v2 v2.0.1/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM= @@ -1257,9 +1271,8 @@ github.com/sirupsen/logrus v1.2.0/go.mod h1:LxeOpSwHxABJmUn/MG1IvRgCAasNZTLOkJPx github.com/sirupsen/logrus v1.4.2/go.mod h1:tLMulIdttU9McNUspp0xgXVQah82FyeX6MwdIuYE2rE= github.com/sirupsen/logrus v1.6.0/go.mod h1:7uNnSEd1DgxDLC74fIahvMZmmYsHGZGEOFrfsX/uA88= github.com/smartystreets/assertions v0.0.0-20180927180507-b2de0cb4f26d/go.mod h1:OnSkiWE9lh6wB0YB77sQom3nweQdgAjqCqsofrRNTgc= +github.com/smartystreets/assertions v1.0.0 h1:UVQPSSmc3qtTi+zPPkCXvZX9VvW/xT/NsRvKfwY81a8= github.com/smartystreets/assertions v1.0.0/go.mod h1:kHHU4qYBaI3q23Pp3VPrmWhuIUrLW/7eUrw0BU5VaoM= -github.com/smartystreets/assertions v1.0.1 h1:voD4ITNjPL5jjBfgR/r8fPIIBrliWrWHeiJApdr3r4w= -github.com/smartystreets/assertions v1.0.1/go.mod h1:kHHU4qYBaI3q23Pp3VPrmWhuIUrLW/7eUrw0BU5VaoM= github.com/smartystreets/goconvey v0.0.0-20190222223459-a17d461953aa/go.mod h1:2RVY1rIf+2J2o/IM9+vPq9RzmHDSseB7FoXiSNIUsoU= github.com/smartystreets/goconvey v0.0.0-20190330032615-68dc04aab96a/go.mod h1:syvi0/a8iFYH4r/RixwvyeAJjdLS9QV7WQ/tjFTllLA= github.com/smartystreets/goconvey v1.6.4 h1:fv0U8FUIMPNf1L9lnHLvLhgicrIVChEkdzIKYqbNC9s= @@ -1310,8 +1323,9 @@ github.com/urfave/cli/v2 v2.0.0/go.mod h1:SE9GqnLQmjVa0iPEY0f1w3ygNIYcIJ0OKPMoW2 github.com/viant/assertly v0.4.8/go.mod h1:aGifi++jvCrUaklKEKT0BU95igDNaqkvz+49uaYMPRU= github.com/viant/toolbox v0.24.0/go.mod h1:OxMCG57V0PXuIP2HNQrtJf2CjqdmbrOx5EkMILuUhzM= github.com/wangjia184/sortedset v0.0.0-20160527075905-f5d03557ba30/go.mod h1:YkocrP2K2tcw938x9gCOmT5G5eCD6jsTz0SZuyAqwIE= -github.com/warpfork/go-testmark v0.3.0 h1:Q81c4u7hT+BR5kNfNQhEF0VT2pmL7+Kk0wD+ORYl7iA= github.com/warpfork/go-testmark v0.3.0/go.mod h1:jhEf8FVxd+F17juRubpmut64NEG6I2rgkUhlcqqXwE0= +github.com/warpfork/go-testmark v0.9.0 h1:nc+uaCiv5lFQLYjhuC2LTYeJ7JaC+gdDmsz9r0ISy0Y= +github.com/warpfork/go-testmark v0.9.0/go.mod h1:jhEf8FVxd+F17juRubpmut64NEG6I2rgkUhlcqqXwE0= github.com/warpfork/go-wish v0.0.0-20180510122957-5ad1f5abf436/go.mod h1:x6AKhvSSexNrVSrViXSHUEbICjmGXhtgABaHIySUSGw= github.com/warpfork/go-wish v0.0.0-20190328234359-8b3e70f8e830/go.mod h1:x6AKhvSSexNrVSrViXSHUEbICjmGXhtgABaHIySUSGw= github.com/warpfork/go-wish v0.0.0-20200122115046-b9ea61034e4a h1:G++j5e0OC488te356JvdhaM8YS6nMsjLAYF7JxCv07w= @@ -1375,17 +1389,17 @@ go.uber.org/atomic v1.6.0/go.mod h1:sABNBOSYdrvTF6hTgEIbc7YasKWGhgEQZyfxyTvoXHQ= go.uber.org/atomic v1.7.0/go.mod h1:fEN4uk6kAWBTFdckzkM89CLk9XfWZrxpCo0nPH17wJc= go.uber.org/atomic v1.9.0 h1:ECmE8Bn/WFTYwEW/bpKD3M8VtR/zQVbavAoalC1PYyE= go.uber.org/atomic v1.9.0/go.mod h1:fEN4uk6kAWBTFdckzkM89CLk9XfWZrxpCo0nPH17wJc= -go.uber.org/dig v1.10.0 h1:yLmDDj9/zuDjv3gz8GQGviXMs9TfysIUMUilCpgzUJY= -go.uber.org/dig v1.10.0/go.mod h1:X34SnWGr8Fyla9zQNO2GSO2D+TIuqB14OS8JhYocIyw= -go.uber.org/fx v1.13.1 h1:CFNTr1oin5OJ0VCZ8EycL3wzF29Jz2g0xe55RFsf2a4= -go.uber.org/fx v1.13.1/go.mod h1:bREWhavnedxpJeTq9pQT53BbvwhUv7TcpsOqcH4a+3w= -go.uber.org/goleak v0.10.0/go.mod h1:VCZuO8V8mFPlL0F5J5GK1rtHV3DrFcQ1R8ryq7FK0aI= +go.uber.org/dig v1.12.0 h1:l1GQeZpEbss0/M4l/ZotuBndCrkMdjnygzgcuOjAdaY= +go.uber.org/dig v1.12.0/go.mod h1:X34SnWGr8Fyla9zQNO2GSO2D+TIuqB14OS8JhYocIyw= +go.uber.org/fx v1.15.0 h1:kcfBpAm98n0ksanyyZLFE/Q3T7yPi13Ge2liu3TxR+A= +go.uber.org/fx v1.15.0/go.mod h1:jI3RazQUhGv5KkpZIRv+kuP4CcgX3fnc0qX8bLnzbx8= go.uber.org/goleak v1.0.0/go.mod h1:8a7PlsEVH3e/a/GLqe5IIrQx6GzcnRmZEufDUTk4A7A= -go.uber.org/goleak v1.1.10 h1:z+mqJhf6ss6BSfSM671tgKyZBFPTTJM+HLxnhPC3wu0= go.uber.org/goleak v1.1.10/go.mod h1:8a7PlsEVH3e/a/GLqe5IIrQx6GzcnRmZEufDUTk4A7A= +go.uber.org/goleak v1.1.11-0.20210813005559-691160354723/go.mod h1:cwTWslyiVhfpKIDGSZEM2HlOvcqm+tG4zioyIeLoqMQ= +go.uber.org/goleak v1.1.11 h1:wy28qYRKZgnJTxGxvye5/wgWr1EKjmUDGYox5mGlRlI= +go.uber.org/goleak v1.1.11/go.mod h1:cwTWslyiVhfpKIDGSZEM2HlOvcqm+tG4zioyIeLoqMQ= go.uber.org/multierr v1.1.0/go.mod h1:wR5kodmAFQ0UK8QlbwjlSNy0Z68gJhDJUG5sjR94q/0= go.uber.org/multierr v1.3.0/go.mod h1:VgVr7evmIr6uPjLBxg28wmKNXyqE9akIJ5XnfpiKl+4= -go.uber.org/multierr v1.4.0/go.mod h1:VgVr7evmIr6uPjLBxg28wmKNXyqE9akIJ5XnfpiKl+4= go.uber.org/multierr v1.5.0/go.mod h1:FeouvMocqHpRaaGuG9EjoKcStLC43Zu/fmqdUMPcKYU= go.uber.org/multierr v1.6.0/go.mod h1:cdWPpRnG4AhwMwsgIHip0KRBQjJy5kYEpYjJxpXp9iU= go.uber.org/multierr v1.7.0 h1:zaiO/rmgFjbmCXdSYJWQcdvOCsthmdaHfr3Gm2Kx4Ec= @@ -1397,8 +1411,9 @@ go.uber.org/zap v1.14.1/go.mod h1:Mb2vm2krFEG5DV0W9qcHBYFtp/Wku1cvYaqPsS/WYfc= go.uber.org/zap v1.15.0/go.mod h1:Mb2vm2krFEG5DV0W9qcHBYFtp/Wku1cvYaqPsS/WYfc= go.uber.org/zap v1.16.0/go.mod h1:MA8QOfq0BHJwdXa996Y4dYkAqRKB8/1K1QMMZVaNZjQ= go.uber.org/zap v1.18.1/go.mod h1:xg/QME4nWcxGxrpdeYfq7UvYrLh66cuVKdrbD1XF/NI= -go.uber.org/zap v1.19.0 h1:mZQZefskPPCMIBCSEH0v2/iUqqLrYtaeqwD6FUGUnFE= go.uber.org/zap v1.19.0/go.mod h1:xg/QME4nWcxGxrpdeYfq7UvYrLh66cuVKdrbD1XF/NI= +go.uber.org/zap v1.19.1 h1:ue41HOKd1vGURxrmeKIgELGb3jPW9DMUDGtsinblHwI= +go.uber.org/zap v1.19.1/go.mod h1:j3DNczoxDZroyBnOT1L/Q79cfUMGZxlv/9dzN7SM1rI= go4.org v0.0.0-20180809161055-417644f6feb5/go.mod h1:MkTOUMDaeVYJUOUsaDXIhWPZYa1yOyC1qaOBpL57BhE= go4.org v0.0.0-20200411211856-f5505b9728dd h1:BNJlw5kRTzdmyfh5U8F93HA2OwkP7ZGwA51eJ/0wKOU= go4.org v0.0.0-20200411211856-f5505b9728dd/go.mod h1:CIiUVy99QCPfoE13bO4EZaz5GZMZXMSBGhxRdsvzbkg= @@ -1433,8 +1448,9 @@ golang.org/x/crypto v0.0.0-20210220033148-5ea612d1eb83/go.mod h1:jdWPYTVW3xRLrWP golang.org/x/crypto v0.0.0-20210322153248-0c34fe9e7dc2/go.mod h1:T9bdIzuCu7OtxOm1hfPfRQxPLYneinmdGuTeoZ9dtd4= golang.org/x/crypto v0.0.0-20210506145944-38f3c27a63bf/go.mod h1:P+XmwS30IXTQdn5tA2iutPOUgjI07+tq3H3K9MVA1s8= golang.org/x/crypto v0.0.0-20210513164829-c07d793c2f9a/go.mod h1:P+XmwS30IXTQdn5tA2iutPOUgjI07+tq3H3K9MVA1s8= -golang.org/x/crypto v0.0.0-20210813211128-0a44fdfbc16e h1:VvfwVmMH40bpMeizC9/K7ipM5Qjucuu16RWfneFPyhQ= golang.org/x/crypto v0.0.0-20210813211128-0a44fdfbc16e/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= +golang.org/x/crypto v0.0.0-20210921155107-089bfa567519 h1:7I4JAnoQBe7ZtJcBaYHi5UtiO8tQHbUSXxL+pnGRANg= +golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= golang.org/x/exp v0.0.0-20190306152737-a1d7652674e8/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= golang.org/x/exp v0.0.0-20190510132918-efd6b22b2522/go.mod h1:ZjyILWgesfNpC6sMxTJOJm9Kp84zZh5NQWvqDGG3Qr8= @@ -1457,9 +1473,8 @@ golang.org/x/lint v0.0.0-20190909230951-414d861bb4ac/go.mod h1:6SW0HCj/g11FgYtHl golang.org/x/lint v0.0.0-20190930215403-16217165b5de/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= golang.org/x/lint v0.0.0-20191125180803-fdd1cda4f05f/go.mod h1:5qLYkcX4OjUUV8bRuDixDT3tpyyb+LUpUlRWLxfhWrs= golang.org/x/lint v0.0.0-20200130185559-910be7a94367/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY= +golang.org/x/lint v0.0.0-20200302205851-738671d3881b h1:Wh+f8QHJXR411sJR8/vRBTZ7YapZaRvUcLFFJhusH0k= golang.org/x/lint v0.0.0-20200302205851-738671d3881b/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY= -golang.org/x/lint v0.0.0-20201208152925-83fdc39ff7b5 h1:2M3HP5CCK1Si9FQhwnzYhXdG6DXeebvUHFpre8QvbyI= -golang.org/x/lint v0.0.0-20201208152925-83fdc39ff7b5/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY= golang.org/x/mobile v0.0.0-20190312151609-d3739f865fa6/go.mod h1:z+o9i4GpDbdi3rU15maQ/Ox0txvL9dWGYEHz965HBQE= golang.org/x/mobile v0.0.0-20190719004257-d2bd2a29d028/go.mod h1:E/iHnbuqvinMTCcRqshq8CkpyQDoeVncDDYHnLhea+o= golang.org/x/mod v0.0.0-20190513183733-4bf6d317e70e/go.mod h1:mXi4GBBbnImb6dmsKGUJ2LatrhH/nqhxcFungHvyanc= @@ -1468,7 +1483,6 @@ golang.org/x/mod v0.1.1-0.20191105210325-c90efee705ee/go.mod h1:QqPTAvyqsEbceGzB golang.org/x/mod v0.1.1-0.20191107180719-034126e5016b/go.mod h1:QqPTAvyqsEbceGzBzNggFXnrqF1CaUcvgkdR5Ot7KZg= golang.org/x/mod v0.2.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= -golang.org/x/mod v0.4.1/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= golang.org/x/mod v0.4.2 h1:Gz96sIWK3OalVv/I/qNygP42zyoKp3xptRVCWRFEBvo= golang.org/x/mod v0.4.2/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= golang.org/x/net v0.0.0-20180719180050-a680a1efc54d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= @@ -1524,6 +1538,7 @@ golang.org/x/net v0.0.0-20210316092652-d523dce5a7f4/go.mod h1:RBQZq4jEuRlivfhVLd golang.org/x/net v0.0.0-20210405180319-a5a99cb37ef4/go.mod h1:p54w0d4576C0XHj96bSt6lcn1PtDYWL6XObtHCRCNQM= golang.org/x/net v0.0.0-20210423184538-5f58ad60dda6/go.mod h1:OJAsFXCWl8Ukc7SiCT/9KSuxbyM7479/AVlXFRxuMCk= golang.org/x/net v0.0.0-20210428140749-89ef3d95e781/go.mod h1:OJAsFXCWl8Ukc7SiCT/9KSuxbyM7479/AVlXFRxuMCk= +golang.org/x/net v0.0.0-20210505024714-0287a6fb4125/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= golang.org/x/net v0.0.0-20210525063256-abc453219eb5/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= golang.org/x/net v0.0.0-20210813160813-60bc85c4be6d h1:LO7XpTYMwTqxjLcGWPijK3vRXg1aWdlNOVOHRq45d7c= golang.org/x/net v0.0.0-20210813160813-60bc85c4be6d/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= @@ -1600,7 +1615,6 @@ golang.org/x/sys v0.0.0-20200223170610-d5e6a3e2c0ae/go.mod h1:h1NjWce9XRLGQEsW7w golang.org/x/sys v0.0.0-20200302150141-5c8b2ff67527/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200323222414-85ca7c5b95cd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200331124033-c3d80250170d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20200420163511-1957bb5e6d1f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200501052902-10377860bb8e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200511232937-7e40ca221e25/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200515095857-1151b9dac4a9/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= @@ -1627,8 +1641,11 @@ golang.org/x/sys v0.0.0-20210511113859-b0526f3d8744/go.mod h1:oPkhp1MJrh7nUepCBc golang.org/x/sys v0.0.0-20210514084401-e8d321eab015/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20210603081109-ebe580a85c40/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20210816183151-1e6c022a8912 h1:uCLL3g5wH2xjxVREVuAbP9JM5PPKjRbXKRa6IBjkzmU= +golang.org/x/sys v0.0.0-20210630005230-0f9fa26af87c/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20210816183151-1e6c022a8912/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20210903071746-97244b99971b/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20211025112917-711f33c9992c h1:i4MLwL3EbCgobekQtkVW94UBSPLMadfEGtKq+CAFsEU= +golang.org/x/sys v0.0.0-20211025112917-711f33c9992c/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/term v0.0.0-20201117132131-f5c789dd3221/go.mod h1:Nr5EML6q2oocZ2LXRh80K7BxOlk5/8JxuGnuhpl+muw= golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= golang.org/x/text v0.0.0-20170915032832-14c0d48ead0c/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= @@ -1669,7 +1686,6 @@ golang.org/x/tools v0.0.0-20191029190741-b9c20aec41a5/go.mod h1:b+2E5dAYhXwXZwtn golang.org/x/tools v0.0.0-20191030062658-86caa796c7ab/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/tools v0.0.0-20191108193012-7d206e10da11/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/tools v0.0.0-20191113191852-77e3bb0ad9e7/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= -golang.org/x/tools v0.0.0-20191114200427-caa0b0f7d508/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/tools v0.0.0-20191115202509-3a792d9c32b2/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/tools v0.0.0-20191125144606-a911d9008d1f/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= @@ -1699,9 +1715,9 @@ golang.org/x/tools v0.0.0-20200804011535-6c149bb5ef0d/go.mod h1:njjCfa9FT2d7l9Bc golang.org/x/tools v0.0.0-20200825202427-b303f430e36d/go.mod h1:njjCfa9FT2d7l9Bc6FUM5FLjQPp3cFF28FI3qnDFljA= golang.org/x/tools v0.0.0-20201224043029-2b0845dc783e/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= golang.org/x/tools v0.0.0-20210106214847-113979e3529a/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= -golang.org/x/tools v0.1.1-0.20210225150353-54dc8c5edb56/go.mod h1:9bzcO0MWcOuT0tm1iBGzDVPshzfwoVvREIui8C+MHqU= -golang.org/x/tools v0.1.1 h1:wGiQel/hW0NnEkJUk8lbzkX2gFJU6PFxf1v5OlCfuOs= golang.org/x/tools v0.1.1/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk= +golang.org/x/tools v0.1.5 h1:ouewzE6p+/VEB31YYnTbEJdi8pFqKp4P4n85vwo3DHA= +golang.org/x/tools v0.1.5/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk= golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= @@ -1822,6 +1838,8 @@ gopkg.in/fsnotify.v1 v1.4.7/go.mod h1:Tz8NjZHkW78fSQdbUxIjBTcgA1z1m8ZHf0WmKUhAMy gopkg.in/gcfg.v1 v1.2.3/go.mod h1:yesOnuUOFQAhST5vPY4nbZsb/huCgGGXlipJsBn0b3o= gopkg.in/inf.v0 v0.9.1/go.mod h1:cWUDdTG/fYaXco+Dcufb5Vnc6Gp2YChqWtbxRZE0mXw= gopkg.in/resty.v1 v1.12.0/go.mod h1:mDo4pnntr5jdWRML875a/NmxYqAlA73dVijT2AXvQQo= +gopkg.in/square/go-jose.v2 v2.5.1 h1:7odma5RETjNHWJnR32wx8t+Io4djHE1PqxCFx3iiZ2w= +gopkg.in/square/go-jose.v2 v2.5.1/go.mod h1:M9dMgbHiYLoDGQrXy7OpJDJWiKiU//h+vD76mk0e1AI= gopkg.in/src-d/go-cli.v0 v0.0.0-20181105080154-d492247bbc0d/go.mod h1:z+K8VcOYVYcSwSjGebuDL6176A1XskgbtNl64NSg+n8= gopkg.in/src-d/go-log.v1 v1.0.1/go.mod h1:GN34hKP0g305ysm2/hctJ0Y8nWP3zxXXJ8GFabTyABE= gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7 h1:uRGJdciOHaEIrze2W8Q3AKkepLTh2hOroT7a+7czfdQ= @@ -1849,6 +1867,10 @@ honnef.co/go/tools v0.0.0-20190523083050-ea95bdfd59fc/go.mod h1:rf3lG4BRIbNafJWh honnef.co/go/tools v0.0.1-2019.2.3/go.mod h1:a3bituU0lyd329TUQxRnasdCoJDkEUEAqEt0JzvZhAg= honnef.co/go/tools v0.0.1-2020.1.3/go.mod h1:X/FiERA/W4tHapMX5mGpAtMSVEeEUOyHaw9vFzvIQ3k= honnef.co/go/tools v0.0.1-2020.1.4/go.mod h1:X/FiERA/W4tHapMX5mGpAtMSVEeEUOyHaw9vFzvIQ3k= +lukechampine.com/blake3 v1.1.6 h1:H3cROdztr7RCfoaTpGZFQsrqvweFLrqS73j7L7cmR5c= +lukechampine.com/blake3 v1.1.6/go.mod h1:tkKEOtDkNtklkXtLNEOGNq5tcV90tJiA1vAA12R78LA= +pgregory.net/rapid v0.4.7 h1:MTNRktPuv5FNqOO151TM9mDTa+XHcX6ypYeISDVD14g= +pgregory.net/rapid v0.4.7/go.mod h1:UYpPVyjFHzYBGHIxLFoupi8vwk6rXNzRY9OMvVxFIOU= rsc.io/binaryregexp v0.2.0/go.mod h1:qTv7/COck+e2FymRvadv62gMdZztPaShugOCi3I+8D8= rsc.io/quote/v3 v3.1.0/go.mod h1:yEA65RcK8LyAZtP9Kv3t0HmxON59tX3rD+tICJqUlj0= rsc.io/sampler v1.3.0/go.mod h1:T1hPZKmBbMNahiBKFy5HrXp6adAjACjK9JXDnKaTXpA= From fe788cae989dff25aad6933619bac2816b493863 Mon Sep 17 00:00:00 2001 From: Lucas Molas Date: Thu, 10 Feb 2022 12:45:02 -0300 Subject: [PATCH 273/414] feat(cmds): add cleartext PEM/PKCS8 for key import/export (#8616) * feat(cmds): add PEM/PKCS8 for key import/export Co-authored-by: Marcin Rataj Co-authored-by: Gus Eggert --- core/commands/keystore.go | 143 ++++++++++++++++-- test/sharness/t0165-keystore-data/README.md | 8 + .../t0165-keystore-data/openssl_ed25519.pem | 3 + .../t0165-keystore-data/openssl_rsa.pem | 28 ++++ test/sharness/t0165-keystore.sh | 86 ++++++++--- 5 files changed, 239 insertions(+), 29 deletions(-) create mode 100644 test/sharness/t0165-keystore-data/README.md create mode 100644 test/sharness/t0165-keystore-data/openssl_ed25519.pem create mode 100644 test/sharness/t0165-keystore-data/openssl_rsa.pem diff --git a/core/commands/keystore.go b/core/commands/keystore.go index bd3146ca57c..11f62fe5046 100644 --- a/core/commands/keystore.go +++ b/core/commands/keystore.go @@ -2,6 +2,9 @@ package commands import ( "bytes" + "crypto/ed25519" + "crypto/x509" + "encoding/pem" "fmt" "io" "io/ioutil" @@ -135,6 +138,13 @@ var keyGenCmd = &cmds.Command{ Type: KeyOutput{}, } +const ( + // Key format options used both for importing and exporting. + keyFormatOptionName = "format" + keyFormatPemCleartextOption = "pem-pkcs8-cleartext" + keyFormatLibp2pCleartextOption = "libp2p-protobuf-cleartext" +) + var keyExportCmd = &cmds.Command{ Helptext: cmds.HelpText{ Tagline: "Export a keypair", @@ -143,6 +153,13 @@ Exports a named libp2p key to disk. By default, the output will be stored at './.key', but an alternate path can be specified with '--output=' or '-o='. + +It is possible to export a private key to interoperable PEM PKCS8 format by explicitly +passing '--format=pem-pkcs8-cleartext'. The resulting PEM file can then be consumed +elsewhere. For example, using openssl to get a PEM with public key: + + $ ipfs key export testkey --format=pem-pkcs8-cleartext -o privkey.pem + $ openssl pkey -in privkey.pem -pubout > pubkey.pem `, }, Arguments: []cmds.Argument{ @@ -150,6 +167,7 @@ path can be specified with '--output=' or '-o='. }, Options: []cmds.Option{ cmds.StringOption(outputOptionName, "o", "The path where the output should be stored."), + cmds.StringOption(keyFormatOptionName, "f", "The format of the exported private key, libp2p-protobuf-cleartext or pem-pkcs8-cleartext.").WithDefault(keyFormatLibp2pCleartextOption), }, NoRemote: true, Run: func(req *cmds.Request, res cmds.ResponseEmitter, env cmds.Environment) error { @@ -186,12 +204,38 @@ path can be specified with '--output=' or '-o='. return fmt.Errorf("key with name '%s' doesn't exist", name) } - encoded, err := crypto.MarshalPrivateKey(sk) - if err != nil { - return err + exportFormat, _ := req.Options[keyFormatOptionName].(string) + var formattedKey []byte + switch exportFormat { + case keyFormatPemCleartextOption: + stdKey, err := crypto.PrivKeyToStdKey(sk) + if err != nil { + return fmt.Errorf("converting libp2p private key to std Go key: %w", err) + + } + // For some reason the ed25519.PrivateKey does not use pointer + // receivers, so we need to convert it for MarshalPKCS8PrivateKey. + // (We should probably change this upstream in PrivKeyToStdKey). + if ed25519KeyPointer, ok := stdKey.(*ed25519.PrivateKey); ok { + stdKey = *ed25519KeyPointer + } + // This function supports a restricted list of public key algorithms, + // but we generate and use only the RSA and ed25519 types that are on that list. + formattedKey, err = x509.MarshalPKCS8PrivateKey(stdKey) + if err != nil { + return fmt.Errorf("marshalling key to PKCS8 format: %w", err) + } + + case keyFormatLibp2pCleartextOption: + formattedKey, err = crypto.MarshalPrivateKey(sk) + if err != nil { + return err + } + default: + return fmt.Errorf("unrecognized export format: %s", exportFormat) } - return res.Emit(bytes.NewReader(encoded)) + return res.Emit(bytes.NewReader(formattedKey)) }, PostRun: cmds.PostRunMap{ cmds.CLI: func(res cmds.Response, re cmds.ResponseEmitter) error { @@ -208,8 +252,16 @@ path can be specified with '--output=' or '-o='. } outPath, _ := req.Options[outputOptionName].(string) + exportFormat, _ := req.Options[keyFormatOptionName].(string) if outPath == "" { - trimmed := strings.TrimRight(fmt.Sprintf("%s.key", req.Arguments[0]), "/") + var fileExtension string + switch exportFormat { + case keyFormatPemCleartextOption: + fileExtension = "pem" + case keyFormatLibp2pCleartextOption: + fileExtension = "key" + } + trimmed := strings.TrimRight(fmt.Sprintf("%s.%s", req.Arguments[0], fileExtension), "/") _, outPath = filepath.Split(trimmed) outPath = filepath.Clean(outPath) } @@ -221,9 +273,26 @@ path can be specified with '--output=' or '-o='. } defer file.Close() - _, err = io.Copy(file, outReader) - if err != nil { - return err + switch exportFormat { + case keyFormatPemCleartextOption: + privKeyBytes, err := ioutil.ReadAll(outReader) + if err != nil { + return err + } + + err = pem.Encode(file, &pem.Block{ + Type: "PRIVATE KEY", + Bytes: privKeyBytes, + }) + if err != nil { + return fmt.Errorf("encoding PEM block: %w", err) + } + + case keyFormatLibp2pCleartextOption: + _, err = io.Copy(file, outReader) + if err != nil { + return err + } } return nil @@ -234,9 +303,22 @@ path can be specified with '--output=' or '-o='. var keyImportCmd = &cmds.Command{ Helptext: cmds.HelpText{ Tagline: "Import a key and prints imported key id", + ShortDescription: ` +Imports a key and stores it under the provided name. + +By default, the key is assumed to be in 'libp2p-protobuf-cleartext' format, +however it is possible to import private keys wrapped in interoperable PEM PKCS8 +by passing '--format=pem-pkcs8-cleartext'. + +The PEM format allows for key generation outside of the IPFS node: + + $ openssl genpkey -algorithm ED25519 > ed25519.pem + $ ipfs key import test-openssl -f pem-pkcs8-cleartext ed25519.pem +`, }, Options: []cmds.Option{ ke.OptionIPNSBase, + cmds.StringOption(keyFormatOptionName, "f", "The format of the private key to import, libp2p-protobuf-cleartext or pem-pkcs8-cleartext.").WithDefault(keyFormatLibp2pCleartextOption), }, Arguments: []cmds.Argument{ cmds.StringArg("name", true, false, "name to associate with key in keychain"), @@ -265,9 +347,48 @@ var keyImportCmd = &cmds.Command{ return err } - sk, err := crypto.UnmarshalPrivateKey(data) - if err != nil { - return err + importFormat, _ := req.Options[keyFormatOptionName].(string) + var sk crypto.PrivKey + switch importFormat { + case keyFormatPemCleartextOption: + pemBlock, rest := pem.Decode(data) + if pemBlock == nil { + return fmt.Errorf("PEM block not found in input data:\n%s", rest) + } + + if pemBlock.Type != "PRIVATE KEY" { + return fmt.Errorf("expected PRIVATE KEY type in PEM block but got: %s", pemBlock.Type) + } + + stdKey, err := x509.ParsePKCS8PrivateKey(pemBlock.Bytes) + if err != nil { + return fmt.Errorf("parsing PKCS8 format: %w", err) + } + + // In case ed25519.PrivateKey is returned we need the pointer for + // conversion to libp2p (see export command for more details). + if ed25519KeyPointer, ok := stdKey.(ed25519.PrivateKey); ok { + stdKey = &ed25519KeyPointer + } + + sk, _, err = crypto.KeyPairFromStdKey(stdKey) + if err != nil { + return fmt.Errorf("converting std Go key to libp2p key: %w", err) + + } + case keyFormatLibp2pCleartextOption: + sk, err = crypto.UnmarshalPrivateKey(data) + if err != nil { + // check if data is PEM, if so, provide user with hint + pemBlock, _ := pem.Decode(data) + if pemBlock != nil { + return fmt.Errorf("unexpected PEM block for format=%s: try again with format=%s", keyFormatLibp2pCleartextOption, keyFormatPemCleartextOption) + } + return fmt.Errorf("unable to unmarshall format=%s: %w", keyFormatLibp2pCleartextOption, err) + } + + default: + return fmt.Errorf("unrecognized import format: %s", importFormat) } cfgRoot, err := cmdenv.GetConfigRoot(env) diff --git a/test/sharness/t0165-keystore-data/README.md b/test/sharness/t0165-keystore-data/README.md new file mode 100644 index 00000000000..33c77fbd376 --- /dev/null +++ b/test/sharness/t0165-keystore-data/README.md @@ -0,0 +1,8 @@ +# OpenSSL generated keys for import/export tests + +Created with commands: + +```bash +openssl genpkey -algorithm ED25519 > openssl_ed25519.pem +openssl genpkey -algorithm RSA -pkeyopt rsa_keygen_bits:2048 > openssl_rsa.pem +``` diff --git a/test/sharness/t0165-keystore-data/openssl_ed25519.pem b/test/sharness/t0165-keystore-data/openssl_ed25519.pem new file mode 100644 index 00000000000..387972c5265 --- /dev/null +++ b/test/sharness/t0165-keystore-data/openssl_ed25519.pem @@ -0,0 +1,3 @@ +-----BEGIN PRIVATE KEY----- +MC4CAQAwBQYDK2VwBCIEIJ2M1na2f3dRm4b1FcAQvsn7q08+XfBZcr4MgH4yiBdz +-----END PRIVATE KEY----- diff --git a/test/sharness/t0165-keystore-data/openssl_rsa.pem b/test/sharness/t0165-keystore-data/openssl_rsa.pem new file mode 100644 index 00000000000..34d365bed2e --- /dev/null +++ b/test/sharness/t0165-keystore-data/openssl_rsa.pem @@ -0,0 +1,28 @@ +-----BEGIN PRIVATE KEY----- +MIIEvwIBADANBgkqhkiG9w0BAQEFAASCBKkwggSlAgEAAoIBAQDSaJB9EKnShOs6 +sbGkB40crn72yNKXj5OBPS2wBDTHWwxyhTB0qJirOT2QYW2DmR/4lPfVk5/f4CJ7 +xIHUBJRoC+NTwqHit24DQBd00tNG4EnKn2Dad/arZ/nEVshkKiGXn0qXxiHHsaCn +X/pnVPU4+O7fdfUlz2EKf3Og/ocRCFrdMsULR2QwDc0YWsY8ngrcKegyFCbKjXjo +zvfbGevCDPlhKaZLxRy0PHnON00YC4KO6d77XpbECFvsE1aG1RxYQX0Zjr+i8UvD +UJp/YCoRNEX54/wKpGebMUrFse5K9hBsFen/wCsPnOsYPSb9g8qyoYRDBnr9sIe1 +9MxFTMy/AgMBAAECggEAKXu2KQI1CS1tlzfbdySJ/MKmg49afckv4sYmENLzeO6J +iLabtBRdbTyu151t0wlIlWEBb9lYJvJwuggnNJ7mh5D4c9YmxqU1imyDc2PxhcLI +qas8lDYcqvSn+L7HaYAo+VTNhxjoJg/uRbGVk/PbGS1zIxmFiLvXPROdv3sPNBsf +EYMDH9q7/8DI6dNBQPxtTKlTDLDsTezbkNFQ74znlXgQYcfY1mXljcRtbJqhQJT3 +uppktESPwLRmqtT9H+v9nCtQR6OLmAmLWNgMrSdGKBsSsgJwv2xfpNMffwd84dtT +uGrS2K+BY0TH2q+Xx04r18GLCst3U5MBSklyHQ/mwQKBgQDqnxNOnK41/n/Q8X4a +/TUnZBx/JHiCoQoa06AsMxFgOvV3ycR+Z9lwb5I5BsicH1GUcHIxSY3mCyd4fLwE +FC0QIyNhPJ5oFKh0Oynjm+79VE8v7kK2qqRL4zUpaCXEsSOrhRsCY0/WQdMUPVsh +okXDUIv37G9KUcjdrhNVpGK3oQKBgQDllK7augIhmlQZTdSLTgmuzhYsXdSGDML/ +Bx48q7OvPhvZIIOsygLGhtcBk2xG6PN1yP44cx9dvcTnzxU6TEblO5P8TWY0BSNj +ZuC5wdxLwc3KUdLd9JLR7qcbjqndDruE01rQFVQ3MDbyB1+VrJgiVHIEomJJrKGm +FQ+314moXwKBgQDL90sDlnZk/kED1k15DRN+kSus5HnXpkRwmfWvNx4t+FOZtdCa +y5Fei8Akz17rStbTIwZDDtzLVnsT5exV52xdkQ6a4+YaOYtQsHZ0JwWXOgo1cv6Q +ary2NGns+1uKKS0HWYnng4rOix8Dg2uMS9Q2PfnQqLz/cSYcgc7RLz2awQKBgQDd +HSaLYztKQeldtahPwwlwYuzYLkbSFNh559EnfffBgIAxzy8C7E1gB95sliBi61oQ +x1SR6c776hoLaVd4np5picgt6B3XXFuJETy/rAcQr8gUZFpDi5sctk4cLHtNfTL9 +6tI8N061GKrS0GcvMNwVtF9cN0mSy8GkxAQvfFgI4QKBgQC4NVimIPptfFckulAL +/t0vkdLhCRr1+UFNhgsQJhCZpfWZK4x8If6Jru/eiU7ywEsL6fHE2ENvyoTjV33g +b9yJ7SV4zkz4VhBxc3p26SIvBgLqtHwH8IkIonlbfQFoEAg1iOneLvimPy0YGHsG ++bTwwlAJJhctILkFtAbooeAQVQ== +-----END PRIVATE KEY----- diff --git a/test/sharness/t0165-keystore.sh b/test/sharness/t0165-keystore.sh index ad4b6a6c7c7..4729a7e2e20 100755 --- a/test/sharness/t0165-keystore.sh +++ b/test/sharness/t0165-keystore.sh @@ -63,24 +63,16 @@ ipfs key rm key_ed25519 echo $rsahash > rsa_key_id ' + test_key_import_export_all_formats rsa_key + test_expect_success "create a new ed25519 key" ' edhash=$(ipfs key gen generated_ed25519_key --type=ed25519) echo $edhash > ed25519_key_id ' - test_expect_success "export and import rsa key" ' - ipfs key export generated_rsa_key && - ipfs key rm generated_rsa_key && - ipfs key import generated_rsa_key generated_rsa_key.key > roundtrip_rsa_key_id && - test_cmp rsa_key_id roundtrip_rsa_key_id - ' + test_key_import_export_all_formats ed25519_key - test_expect_success "export and import ed25519 key" ' - ipfs key export generated_ed25519_key && - ipfs key rm generated_ed25519_key && - ipfs key import generated_ed25519_key generated_ed25519_key.key > roundtrip_ed25519_key_id && - test_cmp ed25519_key_id roundtrip_ed25519_key_id - ' + test_openssl_compatibility_all_types test_expect_success "test export file option" ' ipfs key export generated_rsa_key -o=named_rsa_export_file && @@ -176,15 +168,15 @@ ipfs key rm key_ed25519 ' # export works directly on the keystore present in IPFS_PATH - test_expect_success "export and import ed25519 key while daemon is running" ' - edhash=$(ipfs key gen exported_ed25519_key --type=ed25519) + test_expect_success "prepare ed25519 key while daemon is running" ' + edhash=$(ipfs key gen generated_ed25519_key --type=ed25519) echo $edhash > ed25519_key_id - ipfs key export exported_ed25519_key && - ipfs key rm exported_ed25519_key && - ipfs key import exported_ed25519_key exported_ed25519_key.key > roundtrip_ed25519_key_id && - test_cmp ed25519_key_id roundtrip_ed25519_key_id ' + test_key_import_export_all_formats ed25519_key + + test_openssl_compatibility_all_types + test_expect_success "key export over HTTP /api/v0/key/export is not possible" ' ipfs key gen nohttpexporttest_key --type=ed25519 && curl -X POST -sI "http://$API_ADDR/api/v0/key/export&arg=nohttpexporttest_key" | grep -q "^HTTP/1.1 404 Not Found" @@ -214,6 +206,64 @@ test_check_ed25519_sk() { } } +test_key_import_export_all_formats() { + KEY_NAME=$1 + test_key_import_export $KEY_NAME pem-pkcs8-cleartext + test_key_import_export $KEY_NAME libp2p-protobuf-cleartext +} + +test_key_import_export() { + local KEY_NAME FORMAT + KEY_NAME=$1 + FORMAT=$2 + ORIG_KEY="generated_$KEY_NAME" + if [ $FORMAT == "pem-pkcs8-cleartext" ]; then + FILE_EXT="pem" + else + FILE_EXT="key" + fi + + test_expect_success "export and import $KEY_NAME with format $FORMAT" ' + ipfs key export $ORIG_KEY --format=$FORMAT && + ipfs key rm $ORIG_KEY && + ipfs key import $ORIG_KEY $ORIG_KEY.$FILE_EXT --format=$FORMAT > imported_key_id && + test_cmp ${KEY_NAME}_id imported_key_id + ' +} + +# Test the entire import/export cycle with a openssl-generated key. +# 1. Import openssl key with PEM format. +# 2. Export key with libp2p format. +# 3. Reimport key. +# 4. Now exported with PEM format. +# 5. Compare with original openssl key. +# 6. Clean up. +test_openssl_compatibility() { + local KEY_NAME FORMAT + KEY_NAME=$1 + + test_expect_success "import and export $KEY_NAME with all formats" ' + ipfs key import test-openssl -f pem-pkcs8-cleartext $KEY_NAME > /dev/null && + ipfs key export test-openssl -f libp2p-protobuf-cleartext -o $KEY_NAME.libp2p.key && + ipfs key rm test-openssl && + + ipfs key import test-openssl -f libp2p-protobuf-cleartext $KEY_NAME.libp2p.key > /dev/null && + ipfs key export test-openssl -f pem-pkcs8-cleartext -o $KEY_NAME.ipfs-exported.pem && + ipfs key rm test-openssl && + + test_cmp $KEY_NAME $KEY_NAME.ipfs-exported.pem && + + rm $KEY_NAME.libp2p.key && + rm $KEY_NAME.ipfs-exported.pem + ' +} + +test_openssl_compatibility_all_types() { + test_openssl_compatibility ../t0165-keystore-data/openssl_ed25519.pem + test_openssl_compatibility ../t0165-keystore-data/openssl_rsa.pem +} + + test_key_cmd test_done From 556c03848f299463badf2eb930f31b98c6b781aa Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Thu, 10 Feb 2022 11:54:23 -0500 Subject: [PATCH 274/414] chore(deps): bump go.uber.org/zap from 1.19.1 to 1.21.0 (#8721) Bumps [go.uber.org/zap](https://github.com/uber-go/zap) from 1.19.1 to 1.21.0. - [Release notes](https://github.com/uber-go/zap/releases) - [Changelog](https://github.com/uber-go/zap/blob/master/CHANGELOG.md) - [Commits](https://github.com/uber-go/zap/compare/v1.19.1...v1.21.0) --- updated-dependencies: - dependency-name: go.uber.org/zap dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- go.mod | 2 +- go.sum | 5 ++--- 2 files changed, 3 insertions(+), 4 deletions(-) diff --git a/go.mod b/go.mod index 0ea335814d6..7239fa8433e 100644 --- a/go.mod +++ b/go.mod @@ -105,7 +105,7 @@ require ( github.com/whyrusleeping/multiaddr-filter v0.0.0-20160516205228-e903e4adabd7 go.opencensus.io v0.23.0 go.uber.org/fx v1.15.0 - go.uber.org/zap v1.19.1 + go.uber.org/zap v1.21.0 golang.org/x/crypto v0.0.0-20210921155107-089bfa567519 golang.org/x/sync v0.0.0-20210220032951-036812b2e83c golang.org/x/sys v0.0.0-20211025112917-711f33c9992c diff --git a/go.sum b/go.sum index 49a1addffe4..cfa66c02e14 100644 --- a/go.sum +++ b/go.sum @@ -1424,7 +1424,6 @@ go.uber.org/fx v1.15.0 h1:kcfBpAm98n0ksanyyZLFE/Q3T7yPi13Ge2liu3TxR+A= go.uber.org/fx v1.15.0/go.mod h1:jI3RazQUhGv5KkpZIRv+kuP4CcgX3fnc0qX8bLnzbx8= go.uber.org/goleak v1.0.0/go.mod h1:8a7PlsEVH3e/a/GLqe5IIrQx6GzcnRmZEufDUTk4A7A= go.uber.org/goleak v1.1.10/go.mod h1:8a7PlsEVH3e/a/GLqe5IIrQx6GzcnRmZEufDUTk4A7A= -go.uber.org/goleak v1.1.11-0.20210813005559-691160354723/go.mod h1:cwTWslyiVhfpKIDGSZEM2HlOvcqm+tG4zioyIeLoqMQ= go.uber.org/goleak v1.1.11 h1:wy28qYRKZgnJTxGxvye5/wgWr1EKjmUDGYox5mGlRlI= go.uber.org/goleak v1.1.11/go.mod h1:cwTWslyiVhfpKIDGSZEM2HlOvcqm+tG4zioyIeLoqMQ= go.uber.org/multierr v1.1.0/go.mod h1:wR5kodmAFQ0UK8QlbwjlSNy0Z68gJhDJUG5sjR94q/0= @@ -1441,8 +1440,8 @@ go.uber.org/zap v1.15.0/go.mod h1:Mb2vm2krFEG5DV0W9qcHBYFtp/Wku1cvYaqPsS/WYfc= go.uber.org/zap v1.16.0/go.mod h1:MA8QOfq0BHJwdXa996Y4dYkAqRKB8/1K1QMMZVaNZjQ= go.uber.org/zap v1.18.1/go.mod h1:xg/QME4nWcxGxrpdeYfq7UvYrLh66cuVKdrbD1XF/NI= go.uber.org/zap v1.19.0/go.mod h1:xg/QME4nWcxGxrpdeYfq7UvYrLh66cuVKdrbD1XF/NI= -go.uber.org/zap v1.19.1 h1:ue41HOKd1vGURxrmeKIgELGb3jPW9DMUDGtsinblHwI= -go.uber.org/zap v1.19.1/go.mod h1:j3DNczoxDZroyBnOT1L/Q79cfUMGZxlv/9dzN7SM1rI= +go.uber.org/zap v1.21.0 h1:WefMeulhovoZ2sYXz7st6K0sLj7bBhpiFaud4r4zST8= +go.uber.org/zap v1.21.0/go.mod h1:wjWOCqI0f2ZZrJF/UufIOkiC8ii6tm1iqIsLo76RfJw= go4.org v0.0.0-20180809161055-417644f6feb5/go.mod h1:MkTOUMDaeVYJUOUsaDXIhWPZYa1yOyC1qaOBpL57BhE= go4.org v0.0.0-20200411211856-f5505b9728dd h1:BNJlw5kRTzdmyfh5U8F93HA2OwkP7ZGwA51eJ/0wKOU= go4.org v0.0.0-20200411211856-f5505b9728dd/go.mod h1:CIiUVy99QCPfoE13bO4EZaz5GZMZXMSBGhxRdsvzbkg= From a494f48a9dd0a66bd682651b89e7503b5500ac2a Mon Sep 17 00:00:00 2001 From: Lucas Molas Date: Thu, 10 Feb 2022 16:42:32 -0300 Subject: [PATCH 275/414] feat(cmds): ipfs id: support --offline option (#8626) * feat(cmds): ipfs id: add offline option * docs: clarify why 'ipfs id ' in offline mode Co-authored-by: Marcin Rataj --- core/commands/id.go | 31 +++++++++++++------------------ test/sharness/t0026-id.sh | 9 ++++++++- 2 files changed, 21 insertions(+), 19 deletions(-) diff --git a/core/commands/id.go b/core/commands/id.go index 06a70bf35b5..8920c90921f 100644 --- a/core/commands/id.go +++ b/core/commands/id.go @@ -23,14 +23,7 @@ import ( identify "github.com/libp2p/go-libp2p/p2p/protocol/identify" ) -const offlineIdErrorMessage = `'ipfs id' currently cannot query information on remote -peers without a running daemon; we are working to fix this. -In the meantime, if you want to query remote peers using 'ipfs id', -please run the daemon: - - ipfs daemon & - ipfs id QmaCpDMGvV2BGHeYERUEnRQAwe3N8SzbUtfsmvsqQLuvuJ -` +const offlineIdErrorMessage = "'ipfs id' cannot query information on remote peers without a running daemon; if you only want to convert --peerid-base, pass --offline option." type IdOutput struct { ID string @@ -102,19 +95,21 @@ EXAMPLE: return cmds.EmitOnce(res, output) } - // TODO handle offline mode with polymorphism instead of conditionals - if !n.IsOnline { + offline, _ := req.Options[OfflineOption].(bool) + if !offline && !n.IsOnline { return errors.New(offlineIdErrorMessage) } - // We need to actually connect to run identify. - err = n.PeerHost.Connect(req.Context, peer.AddrInfo{ID: id}) - switch err { - case nil: - case kb.ErrLookupFailure: - return errors.New(offlineIdErrorMessage) - default: - return err + if !offline { + // We need to actually connect to run identify. + err = n.PeerHost.Connect(req.Context, peer.AddrInfo{ID: id}) + switch err { + case nil: + case kb.ErrLookupFailure: + return errors.New(offlineIdErrorMessage) + default: + return err + } } output, err := printPeer(keyEnc, n.Peerstore, id) diff --git a/test/sharness/t0026-id.sh b/test/sharness/t0026-id.sh index 8e02fac3711..6f37120e059 100755 --- a/test/sharness/t0026-id.sh +++ b/test/sharness/t0026-id.sh @@ -48,10 +48,17 @@ test_expect_success "checking ProtocolVersion" ' test_cmp expected-protocol-version actual-protocol-version ' -test_expect_success "checking ID" ' +test_expect_success "checking ID of self" ' ipfs config Identity.PeerID > expected-id && ipfs id -f "\n" > actual-id && test_cmp expected-id actual-id ' +test_expect_success "checking and converting ID of a random peer while offline" ' + # Peer ID taken from `t0140-swarm.sh` test. + echo k2k4r8ncs1yoluq95unsd7x2vfhgve0ncjoggwqx9vyh3vl8warrcp15 > expected-id && + ipfs id -f "\n" --peerid-base base36 --offline QmYyQSo1c1Ym7orWxLYvCrM2EmxFTANf8wXmmE7DWjhx5N > actual-id && + test_cmp expected-id actual-id +' + test_done From a93907a40f8e19d73cb81c8612beef3b63a5abc0 Mon Sep 17 00:00:00 2001 From: Thibault Meunier Date: Thu, 10 Feb 2022 21:26:14 +0000 Subject: [PATCH 276/414] feat: DNS.MaxCacheTTL for DNS-over-HTTPS resolvers (#8615) * feat: Add MaxCacheTTL option for DNS-over-HTTPS resolvers * Update libp2p/go-doh-resolver dependencies to support Options * feat: Add `DNS.MaxCacheTTL` config documentation * docs: DNS.MaxCacheTTL * chore: go-ipfs-config@v0.19.0 Co-authored-by: Gus Eggert Co-authored-by: Marcin Rataj --- core/node/dns.go | 13 ++++++++++--- docs/config.md | 26 ++++++++++++++++++++++---- go.mod | 4 ++-- go.sum | 8 ++++---- 4 files changed, 38 insertions(+), 13 deletions(-) diff --git a/core/node/dns.go b/core/node/dns.go index e49a93ac157..aeec23de145 100644 --- a/core/node/dns.go +++ b/core/node/dns.go @@ -2,7 +2,9 @@ package node import ( "fmt" + "math" "strings" + "time" config "github.com/ipfs/go-ipfs-config" doh "github.com/libp2p/go-doh-resolver" @@ -16,18 +18,23 @@ var defaultResolvers = map[string]string{ "crypto.": "https://resolver.cloudflare-eth.com/dns-query", } -func newResolver(url string) (madns.BasicResolver, error) { +func newResolver(url string, opts ...doh.Option) (madns.BasicResolver, error) { if !strings.HasPrefix(url, "https://") { return nil, fmt.Errorf("invalid resolver url: %s", url) } - return doh.NewResolver(url), nil + return doh.NewResolver(url, opts...) } func DNSResolver(cfg *config.Config) (*madns.Resolver, error) { var opts []madns.Option var err error + var dohOpts []doh.Option + if !cfg.DNS.MaxCacheTTL.IsDefault() { + dohOpts = append(dohOpts, doh.WithMaxCacheTTL(cfg.DNS.MaxCacheTTL.WithDefault(time.Duration(math.MaxUint32)*time.Second))) + } + domains := make(map[string]struct{}) // to track overridden default resolvers rslvrs := make(map[string]madns.BasicResolver) // to reuse resolvers for the same URL @@ -44,7 +51,7 @@ func DNSResolver(cfg *config.Config) (*madns.Resolver, error) { rslv, ok := rslvrs[url] if !ok { - rslv, err = newResolver(url) + rslv, err = newResolver(url, dohOpts...) if err != nil { return nil, fmt.Errorf("bad resolver for %s: %w", domain, err) } diff --git a/docs/config.md b/docs/config.md index f855dbc1996..e5fc4a6c85f 100644 --- a/docs/config.md +++ b/docs/config.md @@ -140,7 +140,8 @@ config file at runtime. - [`Swarm.Transports.Multiplexers.Yamux`](#swarmtransportsmultiplexersyamux) - [`Swarm.Transports.Multiplexers.Mplex`](#swarmtransportsmultiplexersmplex) - [`DNS`](#dns) - - [`DNS.Resolvers`](#dnsresolvers) + - [`DNS.Resolvers`](#dnsresolvers) + - [`DNS.MaxCacheTTL`](#dnsmaxcachettl) @@ -1756,7 +1757,7 @@ Type: `priority` Options for configuring DNS resolution for [DNSLink](https://docs.ipfs.io/concepts/dnslink/) and `/dns*` [Multiaddrs](https://github.com/multiformats/multiaddr/). -## `DNS.Resolvers` +### `DNS.Resolvers` Map of [FQDNs](https://en.wikipedia.org/wiki/Fully_qualified_domain_name) to custom resolver URLs. @@ -1771,7 +1772,7 @@ Example: "eth.": "https://eth.link/dns-query", "crypto.": "https://resolver.unstoppable.io/dns-query", "libre.": "https://ns1.iriseden.fr/dns-query", - ".": "https://doh-ch.blahdns.com:4443/dns-query" + ".": "https://cloudflare-dns.com/dns-query" } } } @@ -1784,7 +1785,7 @@ Be mindful that: ```json { "eth.": "https://resolver.cloudflare-eth.com/dns-query", - "crypto.": "https://resolver.cloudflare-eth.com/dns-query + "crypto.": "https://resolver.cloudflare-eth.com/dns-query" } ``` To get all the benefits of a decentralized naming system we strongly suggest setting DoH endpoint to an empty string and running own decentralized resolver as catch-all one on localhost. @@ -1792,3 +1793,20 @@ Be mindful that: Default: `{}` Type: `object[string -> string]` + +### `DNS.MaxCacheTTL` + +Maximum duration for which entries are valid in the DoH cache. + +This allows you to cap the Time-To-Live suggested by the DNS response ([RFC2181](https://datatracker.ietf.org/doc/html/rfc2181#section-8)). +If present, the upper bound is applied to DoH resolvers in [`DNS.Resolvers`](#dnsresolvers). + +Note: this does NOT work with Go's default DNS resolver. To make this a global setting, add a `.` entry to `DNS.Resolvers` first. + +**Examples:** +* `"5m"` DNS entries are kept for 5 minutes or less. +* `"0s"` DNS entries expire as soon as they are retrieved. + +Default: Respect DNS Response TTL + +Type: `optionalDuration` diff --git a/go.mod b/go.mod index 7239fa8433e..98d2f5a9e55 100644 --- a/go.mod +++ b/go.mod @@ -31,7 +31,7 @@ require ( github.com/ipfs/go-ipfs-blockstore v1.1.2 github.com/ipfs/go-ipfs-chunker v0.0.5 github.com/ipfs/go-ipfs-cmds v0.6.0 - github.com/ipfs/go-ipfs-config v0.18.0 + github.com/ipfs/go-ipfs-config v0.19.0 github.com/ipfs/go-ipfs-exchange-interface v0.1.0 github.com/ipfs/go-ipfs-exchange-offline v0.1.1 github.com/ipfs/go-ipfs-files v0.0.9 @@ -65,7 +65,7 @@ require ( github.com/jbenet/go-random v0.0.0-20190219211222-123a90aedc0c github.com/jbenet/go-temp-err-catcher v0.1.0 github.com/jbenet/goprocess v0.1.4 - github.com/libp2p/go-doh-resolver v0.3.1 + github.com/libp2p/go-doh-resolver v0.4.0 github.com/libp2p/go-libp2p v0.16.0 github.com/libp2p/go-libp2p-connmgr v0.2.4 github.com/libp2p/go-libp2p-core v0.11.0 diff --git a/go.sum b/go.sum index cfa66c02e14..5b529b8b49b 100644 --- a/go.sum +++ b/go.sum @@ -475,8 +475,8 @@ github.com/ipfs/go-ipfs-chunker v0.0.5 h1:ojCf7HV/m+uS2vhUGWcogIIxiO5ubl5O57Q7Na github.com/ipfs/go-ipfs-chunker v0.0.5/go.mod h1:jhgdF8vxRHycr00k13FM8Y0E+6BoalYeobXmUyTreP8= github.com/ipfs/go-ipfs-cmds v0.6.0 h1:yAxdowQZzoFKjcLI08sXVNnqVj3jnABbf9smrPQmBsw= github.com/ipfs/go-ipfs-cmds v0.6.0/go.mod h1:ZgYiWVnCk43ChwoH8hAmI1IRbuVtq3GSTHwtRB/Kqhk= -github.com/ipfs/go-ipfs-config v0.18.0 h1:Ta1aNGNEq6RIvzbw7dqzCVZJKb7j+Dd35JFnAOCpT8g= -github.com/ipfs/go-ipfs-config v0.18.0/go.mod h1:wz2lKzOjgJeYJa6zx8W9VT7mz+iSd0laBMqS/9wmX6A= +github.com/ipfs/go-ipfs-config v0.19.0 h1:OuKIL+BkOZgJ+hb4Wg/9ynCtE/BaZBWcGy8hgdMepAo= +github.com/ipfs/go-ipfs-config v0.19.0/go.mod h1:wz2lKzOjgJeYJa6zx8W9VT7mz+iSd0laBMqS/9wmX6A= github.com/ipfs/go-ipfs-delay v0.0.0-20181109222059-70721b86a9a8/go.mod h1:8SP1YXK1M1kXuc4KJZINY3TQQ03J2rwBG9QfXmbRPrw= github.com/ipfs/go-ipfs-delay v0.0.1 h1:r/UXYyRcddO6thwOnhiznIAiSvxMECGgtv35Xs1IeRQ= github.com/ipfs/go-ipfs-delay v0.0.1/go.mod h1:8SP1YXK1M1kXuc4KJZINY3TQQ03J2rwBG9QfXmbRPrw= @@ -673,8 +673,8 @@ github.com/libp2p/go-conn-security-multistream v0.2.0/go.mod h1:hZN4MjlNetKD3Rq5 github.com/libp2p/go-conn-security-multistream v0.2.1/go.mod h1:cR1d8gA0Hr59Fj6NhaTpFhJZrjSYuNmhpT2r25zYR70= github.com/libp2p/go-conn-security-multistream v0.3.0 h1:9UCIKlBL1hC9u7nkMXpD1nkc/T53PKMAn3/k9ivBAVc= github.com/libp2p/go-conn-security-multistream v0.3.0/go.mod h1:EEP47t4fw/bTelVmEzIDqSe69hO/ip52xBEhZMLWAHM= -github.com/libp2p/go-doh-resolver v0.3.1 h1:1wbVGkB4Tdj4WEvjAuYknOPyt4vSSDn9thnj13pKPaY= -github.com/libp2p/go-doh-resolver v0.3.1/go.mod h1:y5go1ZppAq9N2eppbX0xON01CyPBeUg2yS6BTssssog= +github.com/libp2p/go-doh-resolver v0.4.0 h1:gUBa1f1XsPwtpE1du0O+nnZCUqtG7oYi7Bb+0S7FQqw= +github.com/libp2p/go-doh-resolver v0.4.0/go.mod h1:v1/jwsFusgsWIGX/c6vCRrnJ60x7bhTiq/fs2qt0cAg= github.com/libp2p/go-eventbus v0.1.0/go.mod h1:vROgu5cs5T7cv7POWlWxBaVLxfSegC5UGQf8A2eEmx4= github.com/libp2p/go-eventbus v0.2.1 h1:VanAdErQnpTioN2TowqNcOijf6YwhuODe4pPKSDpxGc= github.com/libp2p/go-eventbus v0.2.1/go.mod h1:jc2S4SoEVPP48H9Wpzm5aiGwUCBMfGhVhhBjyhhCJs8= From f9643a61d73ac300db8c915cdac750436c6d8674 Mon Sep 17 00:00:00 2001 From: Marcin Rataj Date: Thu, 10 Feb 2022 23:52:18 +0100 Subject: [PATCH 277/414] docs: optionalInteger|String|Duration (#8729) --- docs/config.md | 26 +++++++++++++++++++++++--- 1 file changed, 23 insertions(+), 3 deletions(-) diff --git a/docs/config.md b/docs/config.md index e5fc4a6c85f..90cdf215d7b 100644 --- a/docs/config.md +++ b/docs/config.md @@ -16,6 +16,8 @@ config file at runtime. - [`strings`](#strings) - [`duration`](#duration) - [`optionalInteger`](#optionalinteger) + - [`optionalString`](#optionalstring) + - [`optionalDuration`](#optionalduration) - [`Addresses`](#addresses) - [`Addresses.API`](#addressesapi) - [`Addresses.Gateway`](#addressesgateway) @@ -270,12 +272,30 @@ does (e.g, `"1d2h4m40.01s"`). ### `optionalInteger` -Optional Integers allow specifying some numerical value which has -an implicit default when `null` or missing from the config file: +Optional integers allow specifying some numerical value which has +an implicit default when missing from the config file: -- `null`/missing (apply the default value defined in go-ipfs sources) +- `null`/missing will apply the default value defined in go-ipfs sources (`.WithDefault(value)`) - an integer between `-2^63` and `2^63-1` (i.e. `-9223372036854775808` to `9223372036854775807`) + +### `optionalString` + +Optional strings allow specifying some string value which has +an implicit default when missing from the config file: + +- `null`/missing will apply the default value defined in go-ipfs sources (`.WithDefault("value")`) +- a string + + +### `optionalDuration` + +Optional durations allow specifying some duration value which has +an implicit default when missing from the config file: + +- `null`/missing will apply the default value defined in go-ipfs sources (`.WithDefault("1h2m3s")`) +- a string with a valid [go duration](#duration) (e.g, `"1d2h4m40.01s"`). + ## `Addresses` Contains information about various listener addresses to be used by this node. From ebf86718c89f01253c17c6b4035d3143bac69b19 Mon Sep 17 00:00:00 2001 From: Adin Schmahmann Date: Thu, 10 Feb 2022 16:48:44 -0500 Subject: [PATCH 278/414] chore: update go-path --- go.mod | 2 +- go.sum | 3 ++- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/go.mod b/go.mod index 98d2f5a9e55..0971edada60 100644 --- a/go.mod +++ b/go.mod @@ -52,7 +52,7 @@ require ( github.com/ipfs/go-metrics-prometheus v0.0.2 github.com/ipfs/go-mfs v0.2.1 github.com/ipfs/go-namesys v0.4.0 - github.com/ipfs/go-path v0.2.1 + github.com/ipfs/go-path v0.2.2 github.com/ipfs/go-pinning-service-http-client v0.1.0 github.com/ipfs/go-unixfs v0.3.1 github.com/ipfs/go-unixfsnode v1.1.3 diff --git a/go.sum b/go.sum index 5b529b8b49b..d33d89696ab 100644 --- a/go.sum +++ b/go.sum @@ -557,8 +557,9 @@ github.com/ipfs/go-namesys v0.4.0/go.mod h1:jpJwzodyP8DZdWN6DShRjVZw6gaqMr4nQLBS github.com/ipfs/go-path v0.0.7/go.mod h1:6KTKmeRnBXgqrTvzFrPV3CamxcgvXX/4z79tfAd2Sno= github.com/ipfs/go-path v0.0.9/go.mod h1:VpDkSBKQ9EFQOUgi54Tq/O/tGi8n1RfYNks13M3DEs8= github.com/ipfs/go-path v0.1.1/go.mod h1:vC8q4AKOtrjJz2NnllIrmr2ZbGlF5fW2OKKyhV9ggb0= -github.com/ipfs/go-path v0.2.1 h1:R0JYCu0JBnfa6A3C42nzsNPxtKU5/fnUPhWSuzcJHws= github.com/ipfs/go-path v0.2.1/go.mod h1:NOScsVgxfC/eIw4nz6OiGwK42PjaSJ4Y/ZFPn1Xe07I= +github.com/ipfs/go-path v0.2.2 h1:E2FEQX7iiwKfk58Kn/33SsAkN3+1fI4d3rYbjtF2h9o= +github.com/ipfs/go-path v0.2.2/go.mod h1:NOScsVgxfC/eIw4nz6OiGwK42PjaSJ4Y/ZFPn1Xe07I= github.com/ipfs/go-peertaskqueue v0.0.4/go.mod h1:03H8fhyeMfKNFWqzYEVyMbcPUeYrqP1MX6Kd+aN+rMQ= github.com/ipfs/go-peertaskqueue v0.1.0/go.mod h1:Jmk3IyCcfl1W3jTW3YpghSwSEC6IJ3Vzz/jUmWw8Z0U= github.com/ipfs/go-peertaskqueue v0.1.1/go.mod h1:Jmk3IyCcfl1W3jTW3YpghSwSEC6IJ3Vzz/jUmWw8Z0U= From 4f3eb4cdd4bc8d7dcec54a37e7f888cce7c01cc9 Mon Sep 17 00:00:00 2001 From: Gus Eggert Date: Thu, 10 Feb 2022 17:48:38 -0500 Subject: [PATCH 279/414] feat: log multifetcher errors This is to make it easier to understand why the multifetcher is falling back to a different fetcher. --- repo/fsrepo/migrations/fetcher.go | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/repo/fsrepo/migrations/fetcher.go b/repo/fsrepo/migrations/fetcher.go index 26a9275ded7..06794236e1b 100644 --- a/repo/fsrepo/migrations/fetcher.go +++ b/repo/fsrepo/migrations/fetcher.go @@ -2,6 +2,7 @@ package migrations import ( "context" + "fmt" "io" "os" @@ -39,7 +40,8 @@ type limitReadCloser struct { // NewMultiFetcher creates a MultiFetcher with the given Fetchers. The // Fetchers are tried in order ther passed to this function. -func NewMultiFetcher(f ...Fetcher) Fetcher { +func NewMultiFetcher(f ...Fetcher) *MultiFetcher { + mf := &MultiFetcher{ fetchers: make([]Fetcher, len(f)), } @@ -56,6 +58,7 @@ func (f *MultiFetcher) Fetch(ctx context.Context, ipfsPath string) (io.ReadClose if err == nil { return rc, nil } + fmt.Printf("Error fetching: %s\n", err.Error()) errs = multierror.Append(errs, err) } return nil, errs From b1ffc870d5f2fe167458918311b06ecf795d3422 Mon Sep 17 00:00:00 2001 From: Adin Schmahmann Date: Fri, 11 Feb 2022 14:57:51 -0500 Subject: [PATCH 280/414] feat: refactor Fetcher interface used for downloading migrations (#8728) * feat: refactor Fetcher interface used for downloading migrations * feat: add RetryFetcher for migration downloads * feat: 3 retries for each HTTP migration download --- repo/fsrepo/migrations/fetch.go | 7 ++-- repo/fsrepo/migrations/fetch_test.go | 14 +++----- repo/fsrepo/migrations/fetcher.go | 10 +++--- repo/fsrepo/migrations/httpfetcher.go | 14 +++++--- .../migrations/ipfsfetcher/ipfsfetcher.go | 16 ++++++--- .../ipfsfetcher/ipfsfetcher_test.go | 9 +++-- repo/fsrepo/migrations/migrations.go | 5 +-- repo/fsrepo/migrations/migrations_test.go | 13 +++++--- repo/fsrepo/migrations/retryfetcher.go | 33 +++++++++++++++++++ repo/fsrepo/migrations/versions.go | 6 ++-- 10 files changed, 83 insertions(+), 44 deletions(-) create mode 100644 repo/fsrepo/migrations/retryfetcher.go diff --git a/repo/fsrepo/migrations/fetch.go b/repo/fsrepo/migrations/fetch.go index a3493e75009..ff202088a00 100644 --- a/repo/fsrepo/migrations/fetch.go +++ b/repo/fsrepo/migrations/fetch.go @@ -111,15 +111,14 @@ func FetchBinary(ctx context.Context, fetcher Fetcher, dist, ver, binName, out s } defer arcFile.Close() - // Open connection to download archive from ipfs path - rc, err := fetcher.Fetch(ctx, arcDistPath) + // Open connection to download archive from ipfs path and write to file + arcBytes, err := fetcher.Fetch(ctx, arcDistPath) if err != nil { return "", err } - defer rc.Close() // Write download data - _, err = io.Copy(arcFile, rc) + _, err = io.Copy(arcFile, bytes.NewReader(arcBytes)) if err != nil { return "", err } diff --git a/repo/fsrepo/migrations/fetch_test.go b/repo/fsrepo/migrations/fetch_test.go index ec7c6d5e73e..2273cb5e9e0 100644 --- a/repo/fsrepo/migrations/fetch_test.go +++ b/repo/fsrepo/migrations/fetch_test.go @@ -2,10 +2,10 @@ package migrations import ( "bufio" + "bytes" "context" "fmt" "io" - "io/ioutil" "net/http" "net/http/httptest" "os" @@ -96,14 +96,13 @@ func TestHttpFetch(t *testing.T) { fetcher := NewHttpFetcher("", ts.URL, "", 0) - rc, err := fetcher.Fetch(ctx, "/versions") + out, err := fetcher.Fetch(ctx, "/versions") if err != nil { t.Fatal(err) } - defer rc.Close() var lines []string - scan := bufio.NewScanner(rc) + scan := bufio.NewScanner(bytes.NewReader(out)) for scan.Scan() { lines = append(lines, scan.Text()) } @@ -232,16 +231,11 @@ func TestMultiFetcher(t *testing.T) { mf := NewMultiFetcher(badFetcher, fetcher) - rc, err := mf.Fetch(ctx, "/versions") + vers, err := mf.Fetch(ctx, "/versions") if err != nil { t.Fatal(err) } - defer rc.Close() - vers, err := ioutil.ReadAll(rc) - if err != nil { - t.Fatal("could not read versions:", err) - } if len(vers) < 45 { fmt.Println("unexpected more data") } diff --git a/repo/fsrepo/migrations/fetcher.go b/repo/fsrepo/migrations/fetcher.go index 06794236e1b..a63ba7276ff 100644 --- a/repo/fsrepo/migrations/fetcher.go +++ b/repo/fsrepo/migrations/fetcher.go @@ -21,8 +21,7 @@ const ( type Fetcher interface { // Fetch attempts to fetch the file at the given ipfs path. - // Returns io.ReadCloser on success, which caller must close. - Fetch(ctx context.Context, filePath string) (io.ReadCloser, error) + Fetch(ctx context.Context, filePath string) ([]byte, error) // Close performs any cleanup after the fetcher is not longer needed. Close() error } @@ -50,13 +49,12 @@ func NewMultiFetcher(f ...Fetcher) *MultiFetcher { } // Fetch attempts to fetch the file at each of its fetchers until one succeeds. -// Returns io.ReadCloser on success, which caller must close. -func (f *MultiFetcher) Fetch(ctx context.Context, ipfsPath string) (io.ReadCloser, error) { +func (f *MultiFetcher) Fetch(ctx context.Context, ipfsPath string) ([]byte, error) { var errs error for _, fetcher := range f.fetchers { - rc, err := fetcher.Fetch(ctx, ipfsPath) + out, err := fetcher.Fetch(ctx, ipfsPath) if err == nil { - return rc, nil + return out, nil } fmt.Printf("Error fetching: %s\n", err.Error()) errs = multierror.Append(errs, err) diff --git a/repo/fsrepo/migrations/httpfetcher.go b/repo/fsrepo/migrations/httpfetcher.go index 6fb20bb45c2..3f74a084ed6 100644 --- a/repo/fsrepo/migrations/httpfetcher.go +++ b/repo/fsrepo/migrations/httpfetcher.go @@ -60,9 +60,8 @@ func NewHttpFetcher(distPath, gateway, userAgent string, fetchLimit int64) *Http } // Fetch attempts to fetch the file at the given path, from the distribution -// site configured for this HttpFetcher. Returns io.ReadCloser on success, -// which caller must close. -func (f *HttpFetcher) Fetch(ctx context.Context, filePath string) (io.ReadCloser, error) { +// site configured for this HttpFetcher. +func (f *HttpFetcher) Fetch(ctx context.Context, filePath string) ([]byte, error) { gwURL := f.gateway + path.Join(f.distPath, filePath) fmt.Printf("Fetching with HTTP: %q\n", gwURL) @@ -89,10 +88,15 @@ func (f *HttpFetcher) Fetch(ctx context.Context, filePath string) (io.ReadCloser return nil, fmt.Errorf("GET %s error: %s: %s", gwURL, resp.Status, string(mes)) } + var rc io.ReadCloser if f.limit != 0 { - return NewLimitReadCloser(resp.Body, f.limit), nil + rc = NewLimitReadCloser(resp.Body, f.limit) + } else { + rc = resp.Body } - return resp.Body, nil + defer rc.Close() + + return ioutil.ReadAll(rc) } func (f *HttpFetcher) Close() error { diff --git a/repo/fsrepo/migrations/ipfsfetcher/ipfsfetcher.go b/repo/fsrepo/migrations/ipfsfetcher/ipfsfetcher.go index 88f07b502ee..11203ed5a05 100644 --- a/repo/fsrepo/migrations/ipfsfetcher/ipfsfetcher.go +++ b/repo/fsrepo/migrations/ipfsfetcher/ipfsfetcher.go @@ -52,6 +52,8 @@ type IpfsFetcher struct { addrInfo peer.AddrInfo } +var _ migrations.Fetcher = (*IpfsFetcher)(nil) + // NewIpfsFetcher creates a new IpfsFetcher // // Specifying "" for distPath sets the default IPNS path. @@ -85,9 +87,8 @@ func NewIpfsFetcher(distPath string, fetchLimit int64, repoRoot *string) *IpfsFe } // Fetch attempts to fetch the file at the given path, from the distribution -// site configured for this HttpFetcher. Returns io.ReadCloser on success, -// which caller must close. -func (f *IpfsFetcher) Fetch(ctx context.Context, filePath string) (io.ReadCloser, error) { +// site configured for this HttpFetcher. +func (f *IpfsFetcher) Fetch(ctx context.Context, filePath string) ([]byte, error) { // Initialize and start IPFS node on first call to Fetch, since the fetcher // may be created by not used. f.openOnce.Do(func() { @@ -123,10 +124,15 @@ func (f *IpfsFetcher) Fetch(ctx context.Context, filePath string) (io.ReadCloser return nil, fmt.Errorf("%q is not a file", filePath) } + var rc io.ReadCloser if f.limit != 0 { - return migrations.NewLimitReadCloser(fileNode, f.limit), nil + rc = migrations.NewLimitReadCloser(fileNode, f.limit) + } else { + rc = fileNode } - return fileNode, nil + defer rc.Close() + + return ioutil.ReadAll(rc) } func (f *IpfsFetcher) Close() error { diff --git a/repo/fsrepo/migrations/ipfsfetcher/ipfsfetcher_test.go b/repo/fsrepo/migrations/ipfsfetcher/ipfsfetcher_test.go index 877de5e788e..e300371a679 100644 --- a/repo/fsrepo/migrations/ipfsfetcher/ipfsfetcher_test.go +++ b/repo/fsrepo/migrations/ipfsfetcher/ipfsfetcher_test.go @@ -2,6 +2,7 @@ package ipfsfetcher import ( "bufio" + "bytes" "context" "fmt" "os" @@ -28,14 +29,13 @@ func TestIpfsFetcher(t *testing.T) { fetcher := NewIpfsFetcher("", 0, nil) defer fetcher.Close() - rc, err := fetcher.Fetch(ctx, "go-ipfs/versions") + out, err := fetcher.Fetch(ctx, "go-ipfs/versions") if err != nil { t.Fatal(err) } - defer rc.Close() var lines []string - scan := bufio.NewScanner(rc) + scan := bufio.NewScanner(bytes.NewReader(out)) for scan.Scan() { lines = append(lines, scan.Text()) } @@ -52,8 +52,7 @@ func TestIpfsFetcher(t *testing.T) { } // Check not found - _, err = fetcher.Fetch(ctx, "/no_such_file") - if err == nil { + if _, err = fetcher.Fetch(ctx, "/no_such_file"); err == nil { t.Fatal("expected error 404") } diff --git a/repo/fsrepo/migrations/migrations.go b/repo/fsrepo/migrations/migrations.go index 861dc7b7caf..5eac91b2932 100644 --- a/repo/fsrepo/migrations/migrations.go +++ b/repo/fsrepo/migrations/migrations.go @@ -155,13 +155,14 @@ func ReadMigrationConfig(repoRoot string) (*config.Migration, error) { // downloadSources, func GetMigrationFetcher(downloadSources []string, distPath string, newIpfsFetcher func(string) Fetcher) (Fetcher, error) { const httpUserAgent = "go-ipfs" + const numTriesPerHTTP = 3 var fetchers []Fetcher for _, src := range downloadSources { src := strings.TrimSpace(src) switch src { case "HTTPS", "https", "HTTP", "http": - fetchers = append(fetchers, NewHttpFetcher(distPath, "", httpUserAgent, 0)) + fetchers = append(fetchers, &RetryFetcher{NewHttpFetcher(distPath, "", httpUserAgent, 0), numTriesPerHTTP}) case "IPFS", "ipfs": if newIpfsFetcher != nil { fetchers = append(fetchers, newIpfsFetcher(distPath)) @@ -178,7 +179,7 @@ func GetMigrationFetcher(downloadSources []string, distPath string, newIpfsFetch default: return nil, errors.New("bad gateway address: url scheme must be http or https") } - fetchers = append(fetchers, NewHttpFetcher(distPath, u.String(), httpUserAgent, 0)) + fetchers = append(fetchers, &RetryFetcher{NewHttpFetcher(distPath, u.String(), httpUserAgent, 0), numTriesPerHTTP}) case "": // Ignore empty string } diff --git a/repo/fsrepo/migrations/migrations_test.go b/repo/fsrepo/migrations/migrations_test.go index b09174a4930..0e52b3a65ed 100644 --- a/repo/fsrepo/migrations/migrations_test.go +++ b/repo/fsrepo/migrations/migrations_test.go @@ -3,7 +3,6 @@ package migrations import ( "context" "fmt" - "io" "log" "os" "path/filepath" @@ -290,7 +289,9 @@ func TestReadMigrationConfig(t *testing.T) { type mockIpfsFetcher struct{} -func (m *mockIpfsFetcher) Fetch(ctx context.Context, filePath string) (io.ReadCloser, error) { +var _ Fetcher = (*mockIpfsFetcher)(nil) + +func (m *mockIpfsFetcher) Fetch(ctx context.Context, filePath string) ([]byte, error) { return nil, nil } @@ -323,7 +324,9 @@ func TestGetMigrationFetcher(t *testing.T) { if err != nil { t.Fatal(err) } - if _, ok := f.(*HttpFetcher); !ok { + if rf, ok := f.(*RetryFetcher); !ok { + t.Fatal("expected RetryFetcher") + } else if _, ok := rf.Fetcher.(*HttpFetcher); !ok { t.Fatal("expected HttpFetcher") } @@ -341,7 +344,9 @@ func TestGetMigrationFetcher(t *testing.T) { if err != nil { t.Fatal(err) } - if _, ok := f.(*HttpFetcher); !ok { + if rf, ok := f.(*RetryFetcher); !ok { + t.Fatal("expected RetryFetcher") + } else if _, ok := rf.Fetcher.(*HttpFetcher); !ok { t.Fatal("expected HttpFetcher") } diff --git a/repo/fsrepo/migrations/retryfetcher.go b/repo/fsrepo/migrations/retryfetcher.go new file mode 100644 index 00000000000..81415bb6756 --- /dev/null +++ b/repo/fsrepo/migrations/retryfetcher.go @@ -0,0 +1,33 @@ +package migrations + +import ( + "context" + "fmt" +) + +type RetryFetcher struct { + Fetcher + MaxTries int +} + +var _ Fetcher = (*RetryFetcher)(nil) + +func (r *RetryFetcher) Fetch(ctx context.Context, filePath string) ([]byte, error) { + var lastErr error + for i := 0; i < r.MaxTries; i++ { + out, err := r.Fetcher.Fetch(ctx, filePath) + if err == nil { + return out, nil + } + + if ctx.Err() != nil { + return nil, ctx.Err() + } + lastErr = err + } + return nil, fmt.Errorf("exceeded number of retries. last error was %w", lastErr) +} + +func (r *RetryFetcher) Close() error { + return r.Fetcher.Close() +} diff --git a/repo/fsrepo/migrations/versions.go b/repo/fsrepo/migrations/versions.go index 69b2e290bb4..af5bbbbd969 100644 --- a/repo/fsrepo/migrations/versions.go +++ b/repo/fsrepo/migrations/versions.go @@ -2,6 +2,7 @@ package migrations import ( "bufio" + "bytes" "context" "errors" "fmt" @@ -39,16 +40,15 @@ func LatestDistVersion(ctx context.Context, fetcher Fetcher, dist string, stable // available on the distriburion site. List is in ascending order, unless // sortDesc is true. func DistVersions(ctx context.Context, fetcher Fetcher, dist string, sortDesc bool) ([]string, error) { - rc, err := fetcher.Fetch(ctx, path.Join(dist, distVersions)) + versionBytes, err := fetcher.Fetch(ctx, path.Join(dist, distVersions)) if err != nil { return nil, err } - defer rc.Close() prefix := "v" var vers []semver.Version - scan := bufio.NewScanner(rc) + scan := bufio.NewScanner(bytes.NewReader(versionBytes)) for scan.Scan() { ver, err := semver.Make(strings.TrimLeft(scan.Text(), prefix)) if err != nil { From 0216bae3078c18aaac1c44268f861cc519196665 Mon Sep 17 00:00:00 2001 From: odanado Date: Wed, 16 Feb 2022 06:54:47 +0900 Subject: [PATCH 281/414] docker: build for arm cpu (#8633) ref: #4931 --- .github/workflows/docker-image.yml | 27 ++++++++++--- bin/get-docker-tags.sh | 61 ++++++++++++++++++++++++++++++ 2 files changed, 82 insertions(+), 6 deletions(-) create mode 100755 bin/get-docker-tags.sh diff --git a/.github/workflows/docker-image.yml b/.github/workflows/docker-image.yml index 8d2a95a9a60..f2f94739f17 100644 --- a/.github/workflows/docker-image.yml +++ b/.github/workflows/docker-image.yml @@ -15,13 +15,23 @@ jobs: runs-on: ubuntu-latest env: IMAGE_NAME: ipfs/go-ipfs - WIP_IMAGE_TAG: wip steps: - name: Check out the repo uses: actions/checkout@v2 - - name: Build wip Docker image - run: docker build -t $IMAGE_NAME:$WIP_IMAGE_TAG . + - name: Set up QEMU + uses: docker/setup-qemu-action@v1 + + - name: Set up Docker Buildx + uses: docker/setup-buildx-action@v1 + + - name: Get tags + id: tags + run: | + TAGS="$(./bin/get-docker-tags.sh $(date -u +%F))" + TAGS="${TAGS//$'\n'/'%0A'}" + echo "::set-output name=value::$(echo $TAGS)" + shell: bash - name: Log in to Docker Hub uses: docker/login-action@f054a8b539a109f9f41c372932f1ae047eff08c9 @@ -29,6 +39,11 @@ jobs: username: ${{ secrets.DOCKER_USERNAME }} password: ${{ secrets.DOCKER_PASSWORD }} - - name: Publish Docker Image to Docker Hub - run: ./bin/push-docker-tags.sh $(date -u +%F) - + - name: Build Docker image and publish to Docker Hub + uses: docker/build-push-action@v2 + with: + platforms: linux/amd64,linux/arm/v7,linux/arm64/v8 + context: . + push: true + file: ./Dockerfile + tags: "${{ steps.tags.outputs.value }}" diff --git a/bin/get-docker-tags.sh b/bin/get-docker-tags.sh new file mode 100755 index 00000000000..809dfa4c2dc --- /dev/null +++ b/bin/get-docker-tags.sh @@ -0,0 +1,61 @@ +#!/usr/bin/env bash + +# get-docker-tags.sh +# +# Usage: +# ./get-docker-tags.sh [git tag name] +# +# Example: +# +# # get tag for the master branch +# ./get-docker-tags.sh $(date -u +%F) testingsha master +# +# # get tag for a release tag +# ./get-docker-tags.sh $(date -u +%F) testingsha release v0.5.0 +# +# # Serving suggestion in circle ci - https://circleci.com/docs/2.0/env-vars/#built-in-environment-variables +# ./get-docker-tags.sh $(date -u +%F) "$CIRCLE_SHA1" "$CIRCLE_BRANCH" "$CIRCLE_TAG" +# +set -euo pipefail + +if [[ $# -lt 1 ]] ; then + echo 'At least 1 arg required.' + echo 'Usage:' + echo './push-docker-tags.sh [git commit sha1] [git branch name] [git tag name]' + exit 1 +fi + +BUILD_NUM=$1 +GIT_SHA1=${2:-$(git rev-parse HEAD)} +GIT_SHA1_SHORT=$(echo "$GIT_SHA1" | cut -c 1-7) +GIT_BRANCH=${3:-$(git symbolic-ref -q --short HEAD || echo "unknown")} +GIT_TAG=${4:-$(git describe --tags --exact-match || echo "")} + +IMAGE_NAME=${IMAGE_NAME:-ipfs/go-ipfs} + +echoImageName () { + local IMAGE_TAG=$1 + echo "$IMAGE_NAME:$IMAGE_TAG" +} + +if [[ $GIT_TAG =~ ^v[0-9]+\.[0-9]+\.[0-9]+-rc ]]; then + echoImageName "$GIT_TAG" + +elif [[ $GIT_TAG =~ ^v[0-9]+\.[0-9]+\.[0-9]+$ ]]; then + echoImageName "$GIT_TAG" + echoImageName "latest" + echoImageName "release" # see: https://github.com/ipfs/go-ipfs/issues/3999#issuecomment-742228981 + +elif [[ $GIT_BRANCH =~ ^bifrost-.* ]]; then + # sanitize the branch name since docker tags have stricter char limits than git branch names + branch=$(echo "$GIT_BRANCH" | tr '/' '-' | tr --delete --complement '[:alnum:]-') + echoImageName "${branch}-${BUILD_NUM}-${GIT_SHA1_SHORT}" + +elif [ "$GIT_BRANCH" = "master" ]; then + echoImageName "master-${BUILD_NUM}-${GIT_SHA1_SHORT}" + echoImageName "master-latest" + +else + echo "Nothing to do. No docker tag defined for branch: $GIT_BRANCH, tag: $GIT_TAG" + +fi From edb32ac3d743404118834f8c371a3fdf45c2ea66 Mon Sep 17 00:00:00 2001 From: Manuel Alonso Date: Tue, 15 Feb 2022 23:13:09 +0100 Subject: [PATCH 282/414] chore(gateway): debug logging for the http requests (#8518) * chore(gateway): better logging for the http requests * chore(gateway): removed defer and add more data to the final log * chore(gateway): debug logging refactor * chore(gateway): use debug w/o context when only msg * doc: add cmd for log level * chore: add more logs and address fedback * chore(gateway): log subdomains and from=requestURI, refactor * chore(gateway): fix debug redirect --- core/corehttp/gateway_handler.go | 45 +++++++++++++++++++++++++------- docs/gateway.md | 6 +++++ 2 files changed, 42 insertions(+), 9 deletions(-) diff --git a/core/corehttp/gateway_handler.go b/core/corehttp/gateway_handler.go index f5ee54d8cfd..1262101be0f 100644 --- a/core/corehttp/gateway_handler.go +++ b/core/corehttp/gateway_handler.go @@ -82,6 +82,7 @@ func (sw *statusResponseWriter) WriteHeader(code int) { redirect := sw.ResponseWriter.Header().Get("Location") if redirect != "" && code == http.StatusOK { code = http.StatusMovedPermanently + log.Debugw("subdomain redirect", "location", redirect, "status", code) } sw.ResponseWriter.WriteHeader(code) } @@ -198,6 +199,9 @@ func (i *gatewayHandler) getOrHeadHandler(w http.ResponseWriter, r *http.Request urlPath := r.URL.Path escapedURLPath := r.URL.EscapedPath() + logger := log.With("from", r.RequestURI) + logger.Debug("http request received") + // If the gateway is behind a reverse proxy and mounted at a sub-path, // the prefix header can be set to signal this sub-path. // It will be prepended to links in directory listings and the index.html redirect. @@ -210,6 +214,7 @@ func (i *gatewayHandler) getOrHeadHandler(w http.ResponseWriter, r *http.Request break } } + logger.Debugw("sub-path (deprecrated)", "prefix", prefix) } // HostnameOption might have constructed an IPNS/IPFS path using the Host header. @@ -242,7 +247,10 @@ func (i *gatewayHandler) getOrHeadHandler(w http.ResponseWriter, r *http.Request if u.RawQuery != "" { // preserve query if present path = path + "?" + u.RawQuery } - http.Redirect(w, r, gopath.Join("/", prefix, u.Scheme, u.Host, path), http.StatusMovedPermanently) + + redirectURL := gopath.Join("/", prefix, u.Scheme, u.Host, path) + logger.Debugw("uri param, redirect", "to", redirectURL, "status", http.StatusMovedPermanently) + http.Redirect(w, r, redirectURL, http.StatusMovedPermanently) return } @@ -263,6 +271,7 @@ func (i *gatewayHandler) getOrHeadHandler(w http.ResponseWriter, r *http.Request if prefix == "" && fixupSuperfluousNamespace(w, urlPath, r.URL.RawQuery) { // the error was due to redundant namespace, which we were able to fix // by returning error/redirect page, nothing left to do here + logger.Debugw("redundant namespace; noop") return } // unable to fix path, returning error @@ -279,6 +288,7 @@ func (i *gatewayHandler) getOrHeadHandler(w http.ResponseWriter, r *http.Request return default: if i.servePretty404IfPresent(w, r, parsedPath) { + logger.Debugw("serve pretty 404 if present") return } @@ -345,6 +355,8 @@ func (i *gatewayHandler) getOrHeadHandler(w http.ResponseWriter, r *http.Request } else { name = getFilename(urlPath) } + + logger.Debugw("serving file", "name", name) i.serveFile(w, r, name, modtime, f) return } @@ -354,7 +366,8 @@ func (i *gatewayHandler) getOrHeadHandler(w http.ResponseWriter, r *http.Request return } - idx, err := i.api.Unixfs().Get(r.Context(), ipath.Join(resolvedPath, "index.html")) + idxPath := ipath.Join(resolvedPath, "index.html") + idx, err := i.api.Unixfs().Get(r.Context(), idxPath) switch err.(type) { case nil: dirwithoutslash := urlPath[len(urlPath)-1] != '/' @@ -366,7 +379,10 @@ func (i *gatewayHandler) getOrHeadHandler(w http.ResponseWriter, r *http.Request // preserve query parameters suffix = suffix + "?" + r.URL.RawQuery } - http.Redirect(w, r, originalUrlPath+suffix, 302) + + redirectURL := originalUrlPath + suffix + logger.Debugw("serving index.html file", "to", redirectURL, "status", http.StatusFound, "path", idxPath) + http.Redirect(w, r, redirectURL, http.StatusFound) return } @@ -376,11 +392,12 @@ func (i *gatewayHandler) getOrHeadHandler(w http.ResponseWriter, r *http.Request return } + logger.Debugw("serving index.html file", "path", idxPath) // write to request i.serveFile(w, r, "index.html", modtime, f) return case resolver.ErrNoLink: - // no index.html; noop + logger.Debugw("no index.html; noop", "path", idxPath) default: internalWebError(w, err) return @@ -391,6 +408,7 @@ func (i *gatewayHandler) getOrHeadHandler(w http.ResponseWriter, r *http.Request // Note: this needs to occur before listingTemplate.Execute otherwise we get // superfluous response.WriteHeader call from prometheus/client_golang if w.Header().Get("Location") != "" { + logger.Debugw("location moved permanently", "status", http.StatusMovedPermanently) w.WriteHeader(http.StatusMovedPermanently) return } @@ -399,6 +417,7 @@ func (i *gatewayHandler) getOrHeadHandler(w http.ResponseWriter, r *http.Request // type instead of relying on autodetection (which may fail). w.Header().Set("Content-Type", "text/html") if r.Method == http.MethodHead { + logger.Debug("return as request's HTTP method is HEAD") return } @@ -490,8 +509,9 @@ func (i *gatewayHandler) getOrHeadHandler(w http.ResponseWriter, r *http.Request Hash: hash, } - err = listingTemplate.Execute(w, tplData) - if err != nil { + logger.Debugw("request processed", "tplDataDNSLink", dnslink, "tplDataSize", size, "tplDataBackLink", backLink, "tplDataHash", hash, "duration", time.Since(begin)) + + if err := listingTemplate.Execute(w, tplData); err != nil { internalWebError(w, err) return } @@ -568,7 +588,7 @@ func (i *gatewayHandler) servePretty404IfPresent(w http.ResponseWriter, r *http. return false } - log.Debugf("using pretty 404 file for %s", parsedPath.String()) + log.Debugw("using pretty 404 file", "path", parsedPath) w.Header().Set("Content-Type", ctype) w.Header().Set("Content-Length", strconv.FormatInt(size, 10)) w.WriteHeader(http.StatusNotFound) @@ -585,6 +605,7 @@ func (i *gatewayHandler) postHandler(w http.ResponseWriter, r *http.Request) { i.addUserHeaders(w) // ok, _now_ write user's headers. w.Header().Set("IPFS-Hash", p.Cid().String()) + log.Debugw("CID created, http redirect", "from", r.URL, "to", p, "status", http.StatusCreated) http.Redirect(w, r, p.String(), http.StatusCreated) } @@ -677,7 +698,10 @@ func (i *gatewayHandler) putHandler(w http.ResponseWriter, r *http.Request) { i.addUserHeaders(w) // ok, _now_ write user's headers. w.Header().Set("IPFS-Hash", newcid.String()) - http.Redirect(w, r, gopath.Join(ipfsPathPrefix, newcid.String(), newPath), http.StatusCreated) + + redirectURL := gopath.Join(ipfsPathPrefix, newcid.String(), newPath) + log.Debugw("CID replaced, redirect", "from", r.URL, "to", redirectURL, "status", http.StatusCreated) + http.Redirect(w, r, redirectURL, http.StatusCreated) } func (i *gatewayHandler) deleteHandler(w http.ResponseWriter, r *http.Request) { @@ -748,8 +772,11 @@ func (i *gatewayHandler) deleteHandler(w http.ResponseWriter, r *http.Request) { i.addUserHeaders(w) // ok, _now_ write user's headers. w.Header().Set("IPFS-Hash", ncid.String()) + + redirectURL := gopath.Join(ipfsPathPrefix+ncid.String(), directory) // note: StatusCreated is technically correct here as we created a new resource. - http.Redirect(w, r, gopath.Join(ipfsPathPrefix+ncid.String(), directory), http.StatusCreated) + log.Debugw("CID deleted, redirect", "from", r.RequestURI, "to", redirectURL, "status", http.StatusCreated) + http.Redirect(w, r, redirectURL, http.StatusCreated) } func (i *gatewayHandler) addUserHeaders(w http.ResponseWriter) { diff --git a/docs/gateway.md b/docs/gateway.md index dab41e09171..7e85c58ec83 100644 --- a/docs/gateway.md +++ b/docs/gateway.md @@ -16,6 +16,12 @@ The gateway's configuration options are (briefly) described in the [config](https://github.com/ipfs/go-ipfs/blob/master/docs/config.md#gateway) documentation. +### Debug +The gateway's log level can be changed with this command: +``` +> ipfs log level core/server debug +``` + ## Directories For convenience, the gateway (mostly) acts like a normal web-server when serving From e93d6fbfb13c545c80bb4ccf93845532cbb02493 Mon Sep 17 00:00:00 2001 From: Feiran Yang Date: Wed, 16 Feb 2022 06:19:53 +0800 Subject: [PATCH 283/414] feat: warn user when 'pin remote add' while offline (#8621) * feat: add warning message when the local node is offline for remote pinning * feat: check is node is online * feat: add test in t0700-remotepin.sh * feat: use grep and fix the test * fix: print to stdout only when --enc=text This ensures we don't break JSON produced by --enc=json Co-authored-by: Marcin Rataj --- core/commands/pin/remotepin.go | 3 +++ test/sharness/t0700-remotepin.sh | 8 ++++++++ 2 files changed, 11 insertions(+) diff --git a/core/commands/pin/remotepin.go b/core/commands/pin/remotepin.go index 3ca0d353278..0e4bf373ee0 100644 --- a/core/commands/pin/remotepin.go +++ b/core/commands/pin/remotepin.go @@ -4,6 +4,7 @@ import ( "context" "fmt" "io" + "os" "sort" "strings" "text/tabwriter" @@ -185,6 +186,8 @@ NOTE: a comma-separated notation is supported in CLI for convenience: return err } opts = append(opts, pinclient.PinOpts.WithOrigins(addrs...)) + } else if isInBlockstore && !node.IsOnline && cmds.GetEncoding(req, cmds.Text) == cmds.Text { + fmt.Fprintf(os.Stdout, "WARNING: the local node is offline and remote pinning may fail if there is no other provider for this CID\n") } // Execute remote pin request diff --git a/test/sharness/t0700-remotepin.sh b/test/sharness/t0700-remotepin.sh index 538375841c6..2566c06d899 100755 --- a/test/sharness/t0700-remotepin.sh +++ b/test/sharness/t0700-remotepin.sh @@ -319,6 +319,14 @@ test_remote_pins() { test_remote_pins "" test_kill_ipfs_daemon + +WARNINGMESSAGE="WARNING: the local node is offline and remote pinning may fail if there is no other provider for this CID" + +test_expect_success "'ipfs pin remote add' shows the warning message while offline" ' + test_expect_code 0 ipfs pin remote add --service=test_pin_svc --background $BASE_ARGS --name=name_a $HASH_A > actual && + test_expect_code 0 grep -q "$WARNINGMESSAGE" actual +' + test_done # vim: ts=2 sw=2 sts=2 et: From 898065e09c2dd81703a0f50e77e9dc090680b69a Mon Sep 17 00:00:00 2001 From: Lucas Molas Date: Tue, 15 Feb 2022 19:30:47 -0300 Subject: [PATCH 284/414] chore(cmds): encapsulate ipfs rm logic in another function (#8574) --- core/commands/files.go | 118 +++++++++++++++++++---------------------- 1 file changed, 55 insertions(+), 63 deletions(-) diff --git a/core/commands/files.go b/core/commands/files.go index 4801f94954a..879f1fab10e 100644 --- a/core/commands/files.go +++ b/core/commands/files.go @@ -1052,74 +1052,13 @@ Remove files or directories. for _, arg := range req.Arguments { path, err := checkPath(arg) if err != nil { - errs = append(errs, fmt.Errorf("%s: %w", arg, err)) + errs = append(errs, fmt.Errorf("%s is not a valid path: %w", arg, err)) continue } - if path == "/" { - errs = append(errs, fmt.Errorf("%s: cannot delete root", path)) - continue - } - - // 'rm a/b/c/' will fail unless we trim the slash at the end - if path[len(path)-1] == '/' { - path = path[:len(path)-1] - } - - dir, name := gopath.Split(path) - - pdir, err := getParentDir(nd.FilesRoot, dir) - if err != nil { - if force && err == os.ErrNotExist { - continue - } - errs = append(errs, fmt.Errorf("%s: parent lookup: %w", path, err)) - continue - } - - if force { - err := pdir.Unlink(name) - if err != nil { - if err == os.ErrNotExist { - continue - } - errs = append(errs, fmt.Errorf("%s: %w", path, err)) - continue - } - err = pdir.Flush() - if err != nil { - errs = append(errs, fmt.Errorf("%s: %w", path, err)) - } - continue - } - - // get child node by name, when the node is corrupted and nonexistent, - // it will return specific error. - child, err := pdir.Child(name) - if err != nil { - errs = append(errs, fmt.Errorf("%s: %w", path, err)) - continue - } - - switch child.(type) { - case *mfs.Directory: - if !dashr { - errs = append(errs, fmt.Errorf("%s is a directory, use -r to remove directories", path)) - continue - } - } - - err = pdir.Unlink(name) - if err != nil { - errs = append(errs, fmt.Errorf("%s: %w", path, err)) - continue - } - - err = pdir.Flush() - if err != nil { + if err := removePath(nd.FilesRoot, path, force, dashr); err != nil { errs = append(errs, fmt.Errorf("%s: %w", path, err)) } - continue } if len(errs) > 0 { for _, err = range errs { @@ -1134,6 +1073,59 @@ Remove files or directories. }, } +func removePath(filesRoot *mfs.Root, path string, force bool, dashr bool) error { + if path == "/" { + return fmt.Errorf("cannot delete root") + } + + // 'rm a/b/c/' will fail unless we trim the slash at the end + if path[len(path)-1] == '/' { + path = path[:len(path)-1] + } + + dir, name := gopath.Split(path) + + pdir, err := getParentDir(filesRoot, dir) + if err != nil { + if force && err == os.ErrNotExist { + return nil + } + return err + } + + if force { + err := pdir.Unlink(name) + if err != nil { + if err == os.ErrNotExist { + return nil + } + return err + } + return pdir.Flush() + } + + // get child node by name, when the node is corrupted and nonexistent, + // it will return specific error. + child, err := pdir.Child(name) + if err != nil { + return err + } + + switch child.(type) { + case *mfs.Directory: + if !dashr { + return fmt.Errorf("path is a directory, use -r to remove directories") + } + } + + err = pdir.Unlink(name) + if err != nil { + return err + } + + return pdir.Flush() +} + func getPrefixNew(req *cmds.Request) (cid.Builder, error) { cidVer, cidVerSet := req.Options[filesCidVersionOptionName].(int) hashFunStr, hashFunSet := req.Options[filesHashOptionName].(string) From ef63822ef021fa6abccc66b2805267b0ddeb8375 Mon Sep 17 00:00:00 2001 From: Nato Boram Date: Tue, 15 Feb 2022 17:47:48 -0500 Subject: [PATCH 285/414] fix(build): Recognize Go Beta versions in makefile (#8677) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * 🩹 Fix building with beta Go versions * ✏️ Use `[:space:]` to be more canonical --- bin/check_go_version | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bin/check_go_version b/bin/check_go_version index 395af8a7994..74320010bc6 100755 --- a/bin/check_go_version +++ b/bin/check_go_version @@ -39,6 +39,6 @@ type ${GOCC} >/dev/null 2>&1 || die_upgrade "go is not installed or not in the P VERS_STR=$(${GOCC} version 2>&1) || die "'go version' failed with output: $VERS_STR" -GO_CUR_VERSION=$(expr "$VERS_STR" : ".*go version go\([^ ]*\) .*") || die "Invalid 'go version' output: $VERS_STR" +GO_CUR_VERSION=$(expr "$VERS_STR" : ".*go version.* go\([^[:space:]]*\) .*") || die "Invalid 'go version' output: $VERS_STR" check_at_least_version "$GO_MIN_VERSION" "$GO_CUR_VERSION" "${GOCC}" From b2efcf5ce3bba997997962122f85d12500962927 Mon Sep 17 00:00:00 2001 From: Dimitris Apostolou Date: Wed, 16 Feb 2022 01:50:09 +0200 Subject: [PATCH 286/414] Fix typos (#8726) --- repo/fsrepo/migrations/fetcher.go | 2 +- test/sharness/t0087-repo-robust-gc.sh | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/repo/fsrepo/migrations/fetcher.go b/repo/fsrepo/migrations/fetcher.go index a63ba7276ff..12b2391521d 100644 --- a/repo/fsrepo/migrations/fetcher.go +++ b/repo/fsrepo/migrations/fetcher.go @@ -38,7 +38,7 @@ type limitReadCloser struct { } // NewMultiFetcher creates a MultiFetcher with the given Fetchers. The -// Fetchers are tried in order ther passed to this function. +// Fetchers are tried in order, then passed to this function. func NewMultiFetcher(f ...Fetcher) *MultiFetcher { mf := &MultiFetcher{ diff --git a/test/sharness/t0087-repo-robust-gc.sh b/test/sharness/t0087-repo-robust-gc.sh index ca00d591ffc..89cfbb9b26c 100755 --- a/test/sharness/t0087-repo-robust-gc.sh +++ b/test/sharness/t0087-repo-robust-gc.sh @@ -73,7 +73,7 @@ test_gc_robust_part1() { grep -q "permission denied" block_rm_err ' - # repo gc outputs raw multihashes. We chech HASH1 with block stat rather than + # repo gc outputs raw multihashes. We check HASH1 with block stat rather than # grepping the output since it's not a raw multihash test_expect_success "'ipfs repo gc' should still run and remove as much as possible" ' test_must_fail ipfs repo gc 2>&1 | tee repo_gc_out && From a049ba9d1740f2aa6096dd923c32f938fdfac5ae Mon Sep 17 00:00:00 2001 From: Volker Mische Date: Wed, 16 Feb 2022 13:54:29 +0000 Subject: [PATCH 287/414] fix: installation without sudo (#8715) * fix: installation without sudo I think it's good practice that users don't need to run `sudo` to install something just to try it out. With this change, the local bin directory is tried first, which usually is also in the `PATH`. This way the installation script can be run without `sudo` and should still work. * fix: try local path last and support spaces in $HOME Try the `$HOME/.local/bin` path last, so that the script is backwards compatible. Also make sure that it works even if there are spaces in the directory set by `$HOME`. --- cmd/ipfs/dist/install.sh | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/cmd/ipfs/dist/install.sh b/cmd/ipfs/dist/install.sh index 34c5d59e9c8..9f673d05d59 100755 --- a/cmd/ipfs/dist/install.sh +++ b/cmd/ipfs/dist/install.sh @@ -6,13 +6,15 @@ INSTALL_DIR=$(dirname $0) bin="$INSTALL_DIR/ipfs" -binpaths="/usr/local/bin /usr/bin" +binpaths='/usr/local/bin /usr/bin $HOME/.local/bin' # This variable contains a nonzero length string in case the script fails # because of missing write permissions. is_write_perm_missing="" -for binpath in $binpaths; do +for raw in $binpaths; do + # Expand the $HOME variable. + binpath=$(eval echo "$raw") if mv "$bin" "$binpath/ipfs" ; then echo "Moved $bin to $binpath" exit 0 From 5922eab08f22dc815222bcdc3751165b29c82e28 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Wed, 16 Feb 2022 09:16:30 -0500 Subject: [PATCH 288/414] chore(deps): bump go.uber.org/fx from 1.15.0 to 1.16.0 (#8681) Bumps [go.uber.org/fx](https://github.com/uber-go/fx) from 1.15.0 to 1.16.0. - [Release notes](https://github.com/uber-go/fx/releases) - [Changelog](https://github.com/uber-go/fx/blob/master/CHANGELOG.md) - [Commits](https://github.com/uber-go/fx/compare/v1.15.0...v1.16.0) --- updated-dependencies: - dependency-name: go.uber.org/fx dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- go.mod | 2 +- go.sum | 7 ++++--- 2 files changed, 5 insertions(+), 4 deletions(-) diff --git a/go.mod b/go.mod index 0971edada60..8546b9057b3 100644 --- a/go.mod +++ b/go.mod @@ -104,7 +104,7 @@ require ( github.com/whyrusleeping/go-sysinfo v0.0.0-20190219211824-4a357d4b90b1 github.com/whyrusleeping/multiaddr-filter v0.0.0-20160516205228-e903e4adabd7 go.opencensus.io v0.23.0 - go.uber.org/fx v1.15.0 + go.uber.org/fx v1.16.0 go.uber.org/zap v1.21.0 golang.org/x/crypto v0.0.0-20210921155107-089bfa567519 golang.org/x/sync v0.0.0-20210220032951-036812b2e83c diff --git a/go.sum b/go.sum index d33d89696ab..e791d5ea3cf 100644 --- a/go.sum +++ b/go.sum @@ -83,8 +83,9 @@ github.com/aws/aws-sdk-go v1.27.0/go.mod h1:KmX6BPdI08NWTb3/sm4ZGu5ShLoqVDhKgpiN github.com/aws/aws-sdk-go-v2 v0.18.0/go.mod h1:JWVYvqSMppoMJC0x5wdwiImzgXTI9FuZwxzkQq9wy+g= github.com/benbjohnson/clock v1.0.2/go.mod h1:bGMdMPoPVvcYyt1gHDf4J2KE153Yf9BuiUKYMaxlTDM= github.com/benbjohnson/clock v1.0.3/go.mod h1:bGMdMPoPVvcYyt1gHDf4J2KE153Yf9BuiUKYMaxlTDM= -github.com/benbjohnson/clock v1.1.0 h1:Q92kusRqC1XV2MjkWETPvjJVqKetz1OzxZB7mHJLju8= github.com/benbjohnson/clock v1.1.0/go.mod h1:J11/hYXuz8f4ySSvYwY0FKfm+ezbsZBKZxNJlLklBHA= +github.com/benbjohnson/clock v1.3.0 h1:ip6w0uFQkncKQ979AypyG0ER7mqUSBdKLOgAle/AT8A= +github.com/benbjohnson/clock v1.3.0/go.mod h1:J11/hYXuz8f4ySSvYwY0FKfm+ezbsZBKZxNJlLklBHA= github.com/beorn7/perks v0.0.0-20180321164747-3a771d992973/go.mod h1:Dwedo/Wpr24TaqPxmxbtue+5NUziq4I4S80YR8gNf3Q= github.com/beorn7/perks v1.0.0/go.mod h1:KWe93zE9D1o94FZ5RNwFwVgaQK1VOXiVxmqh+CedLV8= github.com/beorn7/perks v1.0.1 h1:VlbKKnNfV8bJzeqoa4cOKqO6bYr3WgKZxO8Z16+hsOM= @@ -1421,8 +1422,8 @@ go.uber.org/atomic v1.9.0 h1:ECmE8Bn/WFTYwEW/bpKD3M8VtR/zQVbavAoalC1PYyE= go.uber.org/atomic v1.9.0/go.mod h1:fEN4uk6kAWBTFdckzkM89CLk9XfWZrxpCo0nPH17wJc= go.uber.org/dig v1.12.0 h1:l1GQeZpEbss0/M4l/ZotuBndCrkMdjnygzgcuOjAdaY= go.uber.org/dig v1.12.0/go.mod h1:X34SnWGr8Fyla9zQNO2GSO2D+TIuqB14OS8JhYocIyw= -go.uber.org/fx v1.15.0 h1:kcfBpAm98n0ksanyyZLFE/Q3T7yPi13Ge2liu3TxR+A= -go.uber.org/fx v1.15.0/go.mod h1:jI3RazQUhGv5KkpZIRv+kuP4CcgX3fnc0qX8bLnzbx8= +go.uber.org/fx v1.16.0 h1:N8i80+X1DCX+qMRiKzM+jPPZiIiyK/bVCysga3+B+1w= +go.uber.org/fx v1.16.0/go.mod h1:OMoT5BnXcOaiexlpjtpE4vcAmzyDKyRs9TRYXCzamx8= go.uber.org/goleak v1.0.0/go.mod h1:8a7PlsEVH3e/a/GLqe5IIrQx6GzcnRmZEufDUTk4A7A= go.uber.org/goleak v1.1.10/go.mod h1:8a7PlsEVH3e/a/GLqe5IIrQx6GzcnRmZEufDUTk4A7A= go.uber.org/goleak v1.1.11 h1:wy28qYRKZgnJTxGxvye5/wgWr1EKjmUDGYox5mGlRlI= From 33423625c73905d3c3dd7e24e73e26b22aef1e55 Mon Sep 17 00:00:00 2001 From: Piotr Galar Date: Fri, 18 Feb 2022 18:25:46 +0100 Subject: [PATCH 289/414] fix(ci): testground workflow hanging indefinitely (#8741) * ci: set timeout on testground job * ci: use testground action which exits early on scheduling failures Note: this will be continued in https://github.com/ipfs/go-ipfs/issues/8731 --- .github/workflows/testground-on-push.yml | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/.github/workflows/testground-on-push.yml b/.github/workflows/testground-on-push.yml index ee18c340b55..ac4dffaa86a 100644 --- a/.github/workflows/testground-on-push.yml +++ b/.github/workflows/testground-on-push.yml @@ -25,7 +25,9 @@ jobs: steps: - uses: actions/checkout@v2 - name: testground run - uses: coryschwartz/testground-github-action@v1.1 + # restore the mainline once https://github.com/coryschwartz/testground-github-action/pull/2 is released + uses: galargh/testground-github-action@6bdc2d4f12280a3e0ec654fd75fe170d4b7931df + timeout-minutes: 5 with: backend_addr: ${{ matrix.backend_addr }} backend_proto: ${{ matrix.backend_proto }} From 9f6cd22ba4ebfe3f8fb18157fe433cf8276168bb Mon Sep 17 00:00:00 2001 From: Adin Schmahmann Date: Fri, 18 Feb 2022 11:37:12 -0800 Subject: [PATCH 290/414] docs(changelog): update v0.12.0 release notes Add line to the breaking changes section indicating that there's a new version of ipfs-update needed to install go-ipfs v0.12.0 --- CHANGELOG.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index fa51882d959..4e9f1745d6a 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -10,6 +10,8 @@ As usual, this release includes important fixes, some of which may be critical f - `ipfs refs local` will now list all blocks as if they were [raw]() CIDv1 instead of with whatever CID version and IPLD codecs they were stored with. All other functionality should remain the same. +Note: This change also effects [ipfs-update](https://github.com/ipfs/ipfs-update) so if you use that tool to mange your go-ipfs installation then grab ipfs-update v1.8.0 from [dist](https://dist.ipfs.io/#ipfs-update). + Keep reading to learn more details. #### 🔦 Highlights From bfa9d3db997f6e38055ecf2db8a5ac111d231ebd Mon Sep 17 00:00:00 2001 From: Will Date: Fri, 18 Feb 2022 13:29:32 -0800 Subject: [PATCH 291/414] feat(cmd): add silent option for repo gc (#7147) * feat(cmd): add silent option repo gc command closes #7129 * test(cmd): add test case for silent option for command repo gc * fix: no emit on server with --silent This removes unnecessary send to the client that does not care Co-authored-by: Marcin Rataj --- core/commands/repo.go | 11 +++++++++++ test/sharness/t0080-repo.sh | 11 +++++++++++ 2 files changed, 22 insertions(+) diff --git a/core/commands/repo.go b/core/commands/repo.go index 20cc41fcd91..c4066f50e56 100644 --- a/core/commands/repo.go +++ b/core/commands/repo.go @@ -51,6 +51,7 @@ type GcResult struct { const ( repoStreamErrorsOptionName = "stream-errors" repoQuietOptionName = "quiet" + repoSilentOptionName = "silent" ) var repoGcCmd = &cmds.Command{ @@ -65,6 +66,7 @@ order to reclaim hard disk space. Options: []cmds.Option{ cmds.BoolOption(repoStreamErrorsOptionName, "Stream errors."), cmds.BoolOption(repoQuietOptionName, "q", "Write minimal output."), + cmds.BoolOption(repoSilentOptionName, "Write no output."), }, Run: func(req *cmds.Request, re cmds.ResponseEmitter, env cmds.Environment) error { n, err := cmdenv.GetNode(env) @@ -72,6 +74,7 @@ order to reclaim hard disk space. return err } + silent, _ := req.Options[repoSilentOptionName].(bool) streamErrors, _ := req.Options[repoStreamErrorsOptionName].(bool) gcOutChan := corerepo.GarbageCollectAsync(n, req.Context) @@ -95,6 +98,9 @@ order to reclaim hard disk space. } } else { err := corerepo.CollectResult(req.Context, gcOutChan, func(k cid.Cid) { + if silent { + return + } // Nothing to do with this error, really. This // most likely means that the client is gone but // we still need to let the GC finish. @@ -111,6 +117,11 @@ order to reclaim hard disk space. Encoders: cmds.EncoderMap{ cmds.Text: cmds.MakeTypedEncoder(func(req *cmds.Request, w io.Writer, gcr *GcResult) error { quiet, _ := req.Options[repoQuietOptionName].(bool) + silent, _ := req.Options[repoSilentOptionName].(bool) + + if silent { + return nil + } if gcr.Error != "" { _, err := fmt.Fprintf(w, "Error: %s\n", gcr.Error) diff --git a/test/sharness/t0080-repo.sh b/test/sharness/t0080-repo.sh index a6631b53cfc..839e651d1c5 100755 --- a/test/sharness/t0080-repo.sh +++ b/test/sharness/t0080-repo.sh @@ -55,6 +55,17 @@ test_expect_success "ipfs repo gc fully reverse ipfs add (part 1)" ' ipfs pin rm -r $hash && ipfs repo gc ' +test_expect_success "'ipfs repo gc --silent' succeeds (no output)" ' + echo "should be empty" >bfile && + HASH2=`ipfs add -q bfile` && + ipfs cat "$HASH2" >expected11 && + test_cmp expected11 bfile && + ipfs pin rm -r "$HASH2" && + ipfs repo gc --silent >gc_out_empty && + test_cmp /dev/null gc_out_empty && + test_must_fail ipfs cat "$HASH2" 2>err_expected1 && + grep "Error: merkledag: not found" err_expected1 +' test_kill_ipfs_daemon From 686993f6f28044c67420232e43f925648bd474a2 Mon Sep 17 00:00:00 2001 From: Adin Schmahmann Date: Fri, 18 Feb 2022 17:37:55 -0500 Subject: [PATCH 292/414] docs: add Internal.UnixFSShardingSizeThreshold (#8723) Co-authored-by: Marcin Rataj --- docs/config.md | 24 +++++++++++++++++++++++- 1 file changed, 23 insertions(+), 1 deletion(-) diff --git a/docs/config.md b/docs/config.md index 90cdf215d7b..c0b622685bb 100644 --- a/docs/config.md +++ b/docs/config.md @@ -16,6 +16,7 @@ config file at runtime. - [`strings`](#strings) - [`duration`](#duration) - [`optionalInteger`](#optionalinteger) + - [`optionalBytes`](#optionalbytes) - [`optionalString`](#optionalstring) - [`optionalDuration`](#optionalduration) - [`Addresses`](#addresses) @@ -67,6 +68,7 @@ config file at runtime. - [`Internal.Bitswap.EngineBlockstoreWorkerCount`](#internalbitswapengineblockstoreworkercount) - [`Internal.Bitswap.EngineTaskWorkerCount`](#internalbitswapenginetaskworkercount) - [`Internal.Bitswap.MaxOutstandingBytesPerPeer`](#internalbitswapmaxoutstandingbytesperpeer) + - [`Internal.UnixFSShardingSizeThreshold`](#internalunixfsshardingsizethreshold) - [`Ipns`](#ipns) - [`Ipns.RepublishPeriod`](#ipnsrepublishperiod) - [`Ipns.RecordLifetime`](#ipnsrecordlifetime) @@ -278,6 +280,15 @@ an implicit default when missing from the config file: - `null`/missing will apply the default value defined in go-ipfs sources (`.WithDefault(value)`) - an integer between `-2^63` and `2^63-1` (i.e. `-9223372036854775808` to `9223372036854775807`) +### `optionalBytes` + +Optional Bytes allow specifying some number of bytes which has +an implicit default when missing from the config file: + +- `null`/missing (apply the default value defined in go-ipfs sources) +- a string value indicating the number of bytes, including human readable representations: + - [SI sizes](https://en.wikipedia.org/wiki/Metric_prefix#List_of_SI_prefixes) (metric units, powers of 1000), e.g. `1B`, `2kB`, `3MB`, `4GB`, `5TB`, …) + - [IEC sizes](https://en.wikipedia.org/wiki/Binary_prefix#IEC_prefixes) (binary units, powers of 1024), e.g. `1B`, `2KiB`, `3MiB`, `4GiB`, `5TiB`, …) ### `optionalString` @@ -287,7 +298,6 @@ an implicit default when missing from the config file: - `null`/missing will apply the default value defined in go-ipfs sources (`.WithDefault("value")`) - a string - ### `optionalDuration` Optional durations allow specifying some duration value which has @@ -940,6 +950,18 @@ deteriorate the quality provided to less aggressively-wanting peers. Type: `optionalInteger` (byte count, `null` means default which is 1MB) +### `Internal.UnixFSShardingSizeThreshold` + +The sharding threshold used internally to decide whether a UnixFS directory should be sharded or not. +This value is not strictly related to the size of the UnixFS directory block and any increases in +the threshold should come with being careful that block sizes stay under 2MiB in order for them to be +reliably transferable through the networking stack (IPFS peers on the public swarm tend to ignore requests for blocks bigger than 2MiB). + +Decreasing this value to 1B is functionally equivalent to the previous experimental sharding option to +shard all directories. + +Type: `optionalBytes` (`null` means default which is 256KiB) + ## `Ipns` ### `Ipns.RepublishPeriod` From 3ea5631f9a0da288882b12189ebae3eca5e941ec Mon Sep 17 00:00:00 2001 From: Lucas Molas Date: Fri, 18 Feb 2022 19:42:40 -0300 Subject: [PATCH 293/414] fix(cmds/keystore): do not allow to import keys we don't generate (#8733) --- core/commands/keystore.go | 16 ++++++++++++++++ test/sharness/t0165-keystore-data/README.md | 18 ++++++++++++++++++ .../t0165-keystore-data/openssl_secp384r1.pem | 6 ++++++ test/sharness/t0165-keystore.sh | 12 ++++++++++++ 4 files changed, 52 insertions(+) create mode 100644 test/sharness/t0165-keystore-data/openssl_secp384r1.pem diff --git a/core/commands/keystore.go b/core/commands/keystore.go index 11f62fe5046..5596ceee03a 100644 --- a/core/commands/keystore.go +++ b/core/commands/keystore.go @@ -143,6 +143,7 @@ const ( keyFormatOptionName = "format" keyFormatPemCleartextOption = "pem-pkcs8-cleartext" keyFormatLibp2pCleartextOption = "libp2p-protobuf-cleartext" + keyAllowAnyTypeOptionName = "allow-any-key-type" ) var keyExportCmd = &cmds.Command{ @@ -319,6 +320,7 @@ The PEM format allows for key generation outside of the IPFS node: Options: []cmds.Option{ ke.OptionIPNSBase, cmds.StringOption(keyFormatOptionName, "f", "The format of the private key to import, libp2p-protobuf-cleartext or pem-pkcs8-cleartext.").WithDefault(keyFormatLibp2pCleartextOption), + cmds.BoolOption(keyAllowAnyTypeOptionName, "Allow importing any key type.").WithDefault(false), }, Arguments: []cmds.Argument{ cmds.StringArg("name", true, false, "name to associate with key in keychain"), @@ -391,6 +393,20 @@ The PEM format allows for key generation outside of the IPFS node: return fmt.Errorf("unrecognized import format: %s", importFormat) } + // We only allow importing keys of the same type we generate (see list in + // https://github.com/ipfs/interface-go-ipfs-core/blob/1c3d8fc/options/key.go#L58-L60), + // unless explicitly stated by the user. + allowAnyKeyType, _ := req.Options[keyAllowAnyTypeOptionName].(bool) + if !allowAnyKeyType { + switch t := sk.(type) { + case *crypto.RsaPrivateKey, *crypto.Ed25519PrivateKey: + default: + return fmt.Errorf("key type %T is not allowed to be imported, only RSA or Ed25519;"+ + " use flag --%s if you are sure of what you're doing", + t, keyAllowAnyTypeOptionName) + } + } + cfgRoot, err := cmdenv.GetConfigRoot(env) if err != nil { return err diff --git a/test/sharness/t0165-keystore-data/README.md b/test/sharness/t0165-keystore-data/README.md index 33c77fbd376..4c0a68b5169 100644 --- a/test/sharness/t0165-keystore-data/README.md +++ b/test/sharness/t0165-keystore-data/README.md @@ -6,3 +6,21 @@ Created with commands: openssl genpkey -algorithm ED25519 > openssl_ed25519.pem openssl genpkey -algorithm RSA -pkeyopt rsa_keygen_bits:2048 > openssl_rsa.pem ``` + +secp key used in the 'restrict import key' test. +From: https://www.openssl.org/docs/man1.1.1/man1/openssl-genpkey.html +```bash +openssl genpkey -genparam -algorithm EC -out ecp.pem \ + -pkeyopt ec_paramgen_curve:secp384r1 \ + -pkeyopt ec_param_enc:named_curve +openssl genpkey -paramfile ecp.pem -out openssl_secp384r1.pem +rm ecp.pem +``` +Note: The Bitcoin `secp256k1` curve which is what `go-libp2p-core/crypto` +actually generates and would be of interest to test against is not +recognized by the Go library: +``` +Error: parsing PKCS8 format: x509: failed to parse EC private key embedded + in PKCS#8: x509: unknown elliptic curve +``` +We keep the `secp384r1` type instead from the original openssl example. diff --git a/test/sharness/t0165-keystore-data/openssl_secp384r1.pem b/test/sharness/t0165-keystore-data/openssl_secp384r1.pem new file mode 100644 index 00000000000..d9000993526 --- /dev/null +++ b/test/sharness/t0165-keystore-data/openssl_secp384r1.pem @@ -0,0 +1,6 @@ +-----BEGIN PRIVATE KEY----- +MIG2AgEAMBAGByqGSM49AgEGBSuBBAAiBIGeMIGbAgEBBDC8DksLZwPKGQS8tuWI +w+dNYiSHUyw30NkrK9YGmjgp84sVVa5NGrv0QniAnNWG1DqhZANiAATq0d5KV1MF +IIpF4beNX+YsmFdqB2oDLhznO/4xNsFCFKE39oGQmuMwnQhDNZZ2CQA8csfgZmuF +OSooe/Ru6ubyeGVKafcHJrOMBvl8hIg0tVWgIAhuXiTHq0UL0QTv9Vk= +-----END PRIVATE KEY----- diff --git a/test/sharness/t0165-keystore.sh b/test/sharness/t0165-keystore.sh index 4729a7e2e20..60089ecd7f2 100755 --- a/test/sharness/t0165-keystore.sh +++ b/test/sharness/t0165-keystore.sh @@ -74,6 +74,18 @@ ipfs key rm key_ed25519 test_openssl_compatibility_all_types + INVALID_KEY=../t0165-keystore-data/openssl_secp384r1.pem + test_expect_success "import key type we don't generate fails" ' + test_must_fail ipfs key import restricted-type -f pem-pkcs8-cleartext $INVALID_KEY 2>&1 | tee key_exp_out && + grep -q "Error: key type \*crypto.ECDSAPrivateKey is not allowed to be imported" key_exp_out && + rm key_exp_out + ' + + test_expect_success "import key type we don't generate succeeds with flag" ' + ipfs key import restricted-type --allow-any-key-type -f pem-pkcs8-cleartext $INVALID_KEY > /dev/null && + ipfs key rm restricted-type + ' + test_expect_success "test export file option" ' ipfs key export generated_rsa_key -o=named_rsa_export_file && test_cmp generated_rsa_key.key named_rsa_export_file && From ec46f1e6e4b6375bb098e33dc7cb779a143705f8 Mon Sep 17 00:00:00 2001 From: Marten Seemann Date: Fri, 25 Feb 2022 11:44:47 +0400 Subject: [PATCH 294/414] fix prioritization of stream muxers --- core/node/libp2p/libp2p.go | 4 ++-- core/node/libp2p/sec.go | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/core/node/libp2p/libp2p.go b/core/node/libp2p/libp2p.go index 3659b3c6179..309490bdc52 100644 --- a/core/node/libp2p/libp2p.go +++ b/core/node/libp2p/libp2p.go @@ -58,7 +58,7 @@ type priorityOption struct { func prioritizeOptions(opts []priorityOption) libp2p.Option { type popt struct { - priority int64 + priority int64 // lower priority values mean higher priority opt libp2p.Option } enabledOptions := make([]popt, 0, len(opts)) @@ -71,7 +71,7 @@ func prioritizeOptions(opts []priorityOption) libp2p.Option { } } sort.Slice(enabledOptions, func(i, j int) bool { - return enabledOptions[i].priority > enabledOptions[j].priority + return enabledOptions[i].priority < enabledOptions[j].priority }) p2pOpts := make([]libp2p.Option, len(enabledOptions)) for i, opt := range enabledOptions { diff --git a/core/node/libp2p/sec.go b/core/node/libp2p/sec.go index 65b440ec4a4..bef2efe476a 100644 --- a/core/node/libp2p/sec.go +++ b/core/node/libp2p/sec.go @@ -30,11 +30,11 @@ func Security(enabled bool, tptConfig config.Transports) interface{} { return func() (opts Libp2pOpts) { opts.Opts = append(opts.Opts, prioritizeOptions([]priorityOption{{ priority: tptConfig.Security.TLS, - defaultPriority: 100, + defaultPriority: 200, opt: libp2p.Security(tls.ID, tls.New), }, { priority: tptConfig.Security.Noise, - defaultPriority: 300, + defaultPriority: 100, opt: libp2p.Security(noise.ID, noise.New), }})) return opts From 3674b662db89a6820b4adfea1ccddec37b8ffe17 Mon Sep 17 00:00:00 2001 From: Marten Seemann Date: Mon, 28 Feb 2022 15:26:06 +0400 Subject: [PATCH 295/414] add a test case for libp2p option prioritization --- core/node/libp2p/libp2p_test.go | 58 +++++++++++++++++++++++++++++++++ 1 file changed, 58 insertions(+) create mode 100644 core/node/libp2p/libp2p_test.go diff --git a/core/node/libp2p/libp2p_test.go b/core/node/libp2p/libp2p_test.go new file mode 100644 index 00000000000..fa949130384 --- /dev/null +++ b/core/node/libp2p/libp2p_test.go @@ -0,0 +1,58 @@ +package libp2p + +import ( + "fmt" + "strconv" + "testing" + + "github.com/libp2p/go-libp2p" + ma "github.com/multiformats/go-multiaddr" + + "github.com/stretchr/testify/require" +) + +func TestPrioritize(t *testing.T) { + // The option is encoded into the port number of a TCP multiaddr. + // By extracting the port numbers obtained from the applied option, we can make sure that + // prioritization sorted the options correctly. + newOption := func(num int) libp2p.Option { + return func(cfg *libp2p.Config) error { + cfg.ListenAddrs = append(cfg.ListenAddrs, ma.StringCast(fmt.Sprintf("/ip4/127.0.0.1/tcp/%d", num))) + return nil + } + } + + extractNums := func(cfg *libp2p.Config) []int { + addrs := cfg.ListenAddrs + nums := make([]int, 0, len(addrs)) + for _, addr := range addrs { + _, comp := ma.SplitLast(addr) + num, err := strconv.Atoi(comp.Value()) + require.NoError(t, err) + nums = append(nums, num) + } + return nums + } + + t.Run("using default priorities", func(t *testing.T) { + opts := []priorityOption{ + {defaultPriority: 200, opt: newOption(200)}, + {defaultPriority: 1, opt: newOption(1)}, + {defaultPriority: 300, opt: newOption(300)}, + } + var cfg libp2p.Config + require.NoError(t, prioritizeOptions(opts)(&cfg)) + require.Equal(t, extractNums(&cfg), []int{1, 200, 300}) + }) + + t.Run("using custom priorities", func(t *testing.T) { + opts := []priorityOption{ + {defaultPriority: 200, priority: 1, opt: newOption(1)}, + {defaultPriority: 1, priority: 300, opt: newOption(300)}, + {defaultPriority: 300, priority: 20, opt: newOption(20)}, + } + var cfg libp2p.Config + require.NoError(t, prioritizeOptions(opts)(&cfg)) + require.Equal(t, extractNums(&cfg), []int{1, 20, 300}) + }) +} From 10ff11b4ca6a0ec7d07c31ccd2e625c08dd4438e Mon Sep 17 00:00:00 2001 From: Gus Eggert Date: Tue, 1 Mar 2022 10:35:19 -0500 Subject: [PATCH 296/414] chore: add instructions for Chocolatey release --- docs/RELEASE_ISSUE_TEMPLATE.md | 1 + 1 file changed, 1 insertion(+) diff --git a/docs/RELEASE_ISSUE_TEMPLATE.md b/docs/RELEASE_ISSUE_TEMPLATE.md index c23122bdcd0..3f276f26305 100644 --- a/docs/RELEASE_ISSUE_TEMPLATE.md +++ b/docs/RELEASE_ISSUE_TEMPLATE.md @@ -82,6 +82,7 @@ Checklist: - [ ] to [dist.ipfs.io](https://dist.ipfs.io) - [ ] to [npm-go-ipfs](https://github.com/ipfs/npm-go-ipfs) - [ ] to [chocolatey](https://chocolatey.org/packages/go-ipfs) + - [ ] Manually run [the release workflow](https://github.com/ipfs/choco-go-ipfs/actions/workflows/main.yml) - [ ] to [snap](https://snapcraft.io/ipfs) - [ ] to [github](https://github.com/ipfs/go-ipfs/releases) - [ ] use the artifacts built in CI for dist.ipfs.io: `wget "https://ipfs.io/api/v0/get?arg=/ipns/dist.ipfs.io/go-ipfs/$(curl -s https://dist.ipfs.io/go-ipfs/versions | tail -n 1)"` From caba3b264340d77f0848bd5362472822e95ea101 Mon Sep 17 00:00:00 2001 From: Marcin Rataj Date: Tue, 1 Mar 2022 18:04:31 +0100 Subject: [PATCH 297/414] feat: X-Ipfs-Roots for smarter HTTP caches (#8720) --- core/corehttp/gateway_handler.go | 54 +++++++ test/sharness/t0116-gateway-cache.sh | 150 ++++++++++++++++++ ...0116-prometheus.sh => t0119-prometheus.sh} | 0 3 files changed, 204 insertions(+) create mode 100755 test/sharness/t0116-gateway-cache.sh rename test/sharness/{t0116-prometheus.sh => t0119-prometheus.sh} (100%) diff --git a/core/corehttp/gateway_handler.go b/core/corehttp/gateway_handler.go index 1262101be0f..d6e45ba927a 100644 --- a/core/corehttp/gateway_handler.go +++ b/core/corehttp/gateway_handler.go @@ -327,6 +327,13 @@ func (i *gatewayHandler) getOrHeadHandler(w http.ResponseWriter, r *http.Request w.Header().Set("X-IPFS-Path", urlPath) w.Header().Set("Etag", responseEtag) + if rootCids, err := i.buildIpfsRootsHeader(urlPath, r); err == nil { + w.Header().Set("X-Ipfs-Roots", rootCids) + } else { // this should never happen, as we resolved the urlPath already + webError(w, "error while resolving X-Ipfs-Roots", err, http.StatusInternalServerError) + return + } + // set these headers _after_ the error, for we may just not have it // and don't want the client to cache a 500 response... // and only if it's /ipfs! @@ -391,6 +398,9 @@ func (i *gatewayHandler) getOrHeadHandler(w http.ResponseWriter, r *http.Request internalWebError(w, files.ErrNotReader) return } + // static index.html → no need to generate dynamic dir-index-html + // replace mutable DirIndex Etag with immutable dir CID + w.Header().Set("Etag", `"`+resolvedPath.Cid().String()+`"`) logger.Debugw("serving index.html file", "path", idxPath) // write to request @@ -785,6 +795,50 @@ func (i *gatewayHandler) addUserHeaders(w http.ResponseWriter) { } } +// Set X-Ipfs-Roots with logical CID array for efficient HTTP cache invalidation. +func (i *gatewayHandler) buildIpfsRootsHeader(contentPath string, r *http.Request) (string, error) { + /* + These are logical roots where each CID represent one path segment + and resolves to either a directory or the root block of a file. + The main purpose of this header is allow HTTP caches to do smarter decisions + around cache invalidation (eg. keep specific subdirectory/file if it did not change) + + A good example is Wikipedia, which is HAMT-sharded, but we only care about + logical roots that represent each segment of the human-readable content + path: + + Given contentPath = /ipns/en.wikipedia-on-ipfs.org/wiki/Block_of_Wikipedia_in_Turkey + rootCidList is a generated by doing `ipfs resolve -r` on each sub path: + /ipns/en.wikipedia-on-ipfs.org → bafybeiaysi4s6lnjev27ln5icwm6tueaw2vdykrtjkwiphwekaywqhcjze + /ipns/en.wikipedia-on-ipfs.org/wiki/ → bafybeihn2f7lhumh4grizksi2fl233cyszqadkn424ptjajfenykpsaiw4 + /ipns/en.wikipedia-on-ipfs.org/wiki/Block_of_Wikipedia_in_Turkey → bafkreibn6euazfvoghepcm4efzqx5l3hieof2frhp254hio5y7n3hv5rma + + The result is an ordered array of values: + X-Ipfs-Roots: bafybeiaysi4s6lnjev27ln5icwm6tueaw2vdykrtjkwiphwekaywqhcjze,bafybeihn2f7lhumh4grizksi2fl233cyszqadkn424ptjajfenykpsaiw4,bafkreibn6euazfvoghepcm4efzqx5l3hieof2frhp254hio5y7n3hv5rma + + Note that while the top one will change every time any article is changed, + the last root (responsible for specific article) may not change at all. + */ + var sp strings.Builder + var pathRoots []string + pathSegments := strings.Split(contentPath[6:], "/") + sp.WriteString(contentPath[:5]) // /ipfs or /ipns + for _, root := range pathSegments { + if root == "" { + continue + } + sp.WriteString("/") + sp.WriteString(root) + resolvedSubPath, err := i.api.ResolvePath(r.Context(), ipath.New(sp.String())) + if err != nil { + return "", err + } + pathRoots = append(pathRoots, resolvedSubPath.Cid().String()) + } + rootCidList := strings.Join(pathRoots, ",") // convention from rfc2616#sec4.2 + return rootCidList, nil +} + func webError(w http.ResponseWriter, message string, err error, defaultCode int) { if _, ok := err.(resolver.ErrNoLink); ok { webErrorWithCode(w, message, err, http.StatusNotFound) diff --git a/test/sharness/t0116-gateway-cache.sh b/test/sharness/t0116-gateway-cache.sh new file mode 100755 index 00000000000..3e9e2af48b8 --- /dev/null +++ b/test/sharness/t0116-gateway-cache.sh @@ -0,0 +1,150 @@ +#!/usr/bin/env bash + +test_description="Test HTTP Gateway Cache Control Support" + +. lib/test-lib.sh + +test_init_ipfs +test_launch_ipfs_daemon_without_network + +# Cache control support is based on logical roots (each path segment == one logical root). +# To maximize the test surface, we want to test: +# - /ipfs/ content path +# - /ipns/ content path +# - at least 3 levels +# - separate tests for a directory listing and a file +# - have implicit index.html for a good measure +# /ipns/root1/root2/root3/ (/ipns/root1/root2/root3/index.html) + +# Note: we cover important edge case here: +# ROOT3_CID - dir listing (dir-index-html response) +# ROOT4_CID - index.html returned as a root response (dir/), instead of generated dir-index-html +# FILE_CID - index.html returned directly, as a file + +test_expect_success "Add the test directory" ' + mkdir -p root2/root3/root4 && + echo "hello" > root2/root3/root4/index.html && + ROOT1_CID=$(ipfs add -Qrw --cid-version 1 root2) + ROOT2_CID=$(ipfs resolve -r /ipfs/$ROOT1_CID/root2 | cut -d "/" -f3) + ROOT3_CID=$(ipfs resolve -r /ipfs/$ROOT1_CID/root2/root3 | cut -d "/" -f3) + ROOT4_CID=$(ipfs resolve -r /ipfs/$ROOT1_CID/root2/root3/root4 | cut -d "/" -f3) + FILE_CID=$(ipfs resolve -r /ipfs/$ROOT1_CID/root2/root3/root4/index.html | cut -d "/" -f3) +' + +test_expect_success "Prepare IPNS unixfs content path for testing" ' + TEST_IPNS_ID=$(ipfs key gen --ipns-base=base36 --type=ed25519 cache_test_key | head -n1 | tr -d "\n") + ipfs name publish --key cache_test_key --allow-offline -Q "/ipfs/$ROOT1_CID" > name_publish_out && + test_check_peerid "${TEST_IPNS_ID}" && + ipfs name resolve "${TEST_IPNS_ID}" > output && + printf "/ipfs/%s\n" "$ROOT1_CID" > expected && + test_cmp expected output +' + +# GET /ipfs/ + test_expect_success "GET for /ipfs/ unixfs dir listing succeeds" ' + curl -svX GET "http://127.0.0.1:$GWAY_PORT/ipfs/$ROOT1_CID/root2/root3/" >/dev/null 2>curl_ipfs_dir_listing_output && + cat curl_ipfs_dir_listing_output + ' + test_expect_success "GET for /ipfs/ unixfs dir with index.html succeeds" ' + curl -svX GET "http://127.0.0.1:$GWAY_PORT/ipfs/$ROOT1_CID/root2/root3/root4/" >/dev/null 2>curl_ipfs_dir_index.html_output && + cat curl_ipfs_dir_index.html_output + ' + test_expect_success "GET for /ipfs/ unixfs file succeeds" ' + curl -svX GET "http://127.0.0.1:$GWAY_PORT/ipfs/$ROOT1_CID/root2/root3/root4/index.html" >/dev/null 2>curl_ipfs_file_output && + cat curl_ipfs_file_output + ' +# GET /ipns/ + test_expect_success "GET for /ipns/ unixfs dir listing succeeds" ' + curl -svX GET "http://127.0.0.1:$GWAY_PORT/ipns/$TEST_IPNS_ID/root2/root3/" >/dev/null 2>curl_ipns_dir_listing_output && + cat curl_ipns_dir_listing_output + ' + test_expect_success "GET for /ipns/ unixfs dir with index.html succeeds" ' + curl -svX GET "http://127.0.0.1:$GWAY_PORT/ipns/$TEST_IPNS_ID/root2/root3/root4/" >/dev/null 2>curl_ipns_dir_index.html_output && + cat curl_ipns_dir_index.html_output + ' + test_expect_success "GET for /ipns/ unixfs file succeeds" ' + curl -svX GET "http://127.0.0.1:$GWAY_PORT/ipns/$TEST_IPNS_ID/root2/root3/root4/index.html" >/dev/null 2>curl_ipns_file_output && + cat curl_ipns_file_output + ' + +# X-Ipfs-Path + + ## dir generated listing + test_expect_success "GET /ipfs/ dir listing response has original content path in X-Ipfs-Path" ' + grep "< X-Ipfs-Path: /ipfs/$ROOT1_CID/root2/root3" curl_ipfs_dir_listing_output + ' + test_expect_success "GET /ipns/ dir listing response has original content path in X-Ipfs-Path" ' + grep "< X-Ipfs-Path: /ipns/$TEST_IPNS_ID/root2/root3" curl_ipns_dir_listing_output + ' + + ## dir static index.html + test_expect_success "GET /ipfs/ dir index.html response has original content path in X-Ipfs-Path" ' + grep "< X-Ipfs-Path: /ipfs/$ROOT1_CID/root2/root3/root4/" curl_ipfs_dir_index.html_output + ' + test_expect_success "GET /ipns/ dir index.html response has original content path in X-Ipfs-Path" ' + grep "< X-Ipfs-Path: /ipns/$TEST_IPNS_ID/root2/root3/root4/" curl_ipns_dir_index.html_output + ' + + # file + test_expect_success "GET /ipfs/ file response has original content path in X-Ipfs-Path" ' + grep "< X-Ipfs-Path: /ipfs/$ROOT1_CID/root2/root3/root4/index.html" curl_ipfs_file_output + ' + test_expect_success "GET /ipns/ file response has original content path in X-Ipfs-Path" ' + grep "< X-Ipfs-Path: /ipns/$TEST_IPNS_ID/root2/root3/root4/index.html" curl_ipns_file_output + ' + +# X-Ipfs-Roots + + ## dir generated listing + test_expect_success "GET /ipfs/ dir listing response has logical CID roots in X-Ipfs-Roots" ' + grep "< X-Ipfs-Roots: ${ROOT1_CID},${ROOT2_CID},${ROOT3_CID}" curl_ipfs_dir_listing_output + ' + test_expect_success "GET /ipns/ dir listing response has logical CID roots in X-Ipfs-Roots" ' + grep "< X-Ipfs-Roots: ${ROOT1_CID},${ROOT2_CID},${ROOT3_CID}" curl_ipns_dir_listing_output + ' + + ## dir static index.html + test_expect_success "GET /ipfs/ dir index.html response has logical CID roots in X-Ipfs-Roots" ' + grep "< X-Ipfs-Roots: ${ROOT1_CID},${ROOT2_CID},${ROOT3_CID},${ROOT4_CID}" curl_ipfs_dir_index.html_output + ' + test_expect_success "GET /ipns/ dir index.html response has logical CID roots in X-Ipfs-Roots" ' + grep "< X-Ipfs-Roots: ${ROOT1_CID},${ROOT2_CID},${ROOT3_CID},${ROOT4_CID}" curl_ipns_dir_index.html_output + ' + + ## file + test_expect_success "GET /ipfs/ file response has logical CID roots in X-Ipfs-Roots" ' + grep "< X-Ipfs-Roots: ${ROOT1_CID},${ROOT2_CID},${ROOT3_CID},${ROOT4_CID},${FILE_CID}" curl_ipfs_file_output + ' + test_expect_success "GET /ipns/ file response has logical CID roots in X-Ipfs-Roots" ' + grep "< X-Ipfs-Roots: ${ROOT1_CID},${ROOT2_CID},${ROOT3_CID},${ROOT4_CID},${FILE_CID}" curl_ipns_file_output + ' + +# Etag + + ## dir generated listing + test_expect_success "GET /ipfs/ dir response has special Etag for generated dir listing" ' + grep -E "< Etag: \"DirIndex-.+_CID-${ROOT3_CID}\"" curl_ipfs_dir_listing_output + ' + test_expect_success "GET /ipns/ dir response has special Etag for generated dir listing" ' + grep -E "< Etag: \"DirIndex-.+_CID-${ROOT3_CID}\"" curl_ipns_dir_listing_output + ' + + ## dir static index.html should use CID of the index.html file for improved HTTP caching + test_expect_success "GET /ipfs/ dir index.html response has dir CID as Etag" ' + grep "< Etag: \"${ROOT4_CID}\"" curl_ipfs_dir_index.html_output + ' + test_expect_success "GET /ipns/ dir index.html response has dir CID as Etag" ' + grep "< Etag: \"${ROOT4_CID}\"" curl_ipns_dir_index.html_output + ' + + ## file + test_expect_success "GET /ipfs/ response has CID as Etag for a file" ' + grep "< Etag: \"${FILE_CID}\"" curl_ipfs_file_output + ' + test_expect_success "GET /ipns/ response has CID as Etag for a file" ' + grep "< Etag: \"${FILE_CID}\"" curl_ipns_file_output + ' + +test_kill_ipfs_daemon + +test_done diff --git a/test/sharness/t0116-prometheus.sh b/test/sharness/t0119-prometheus.sh similarity index 100% rename from test/sharness/t0116-prometheus.sh rename to test/sharness/t0119-prometheus.sh From d5ad847e05865e81957c43f526600860c06dbb84 Mon Sep 17 00:00:00 2001 From: Marcin Rataj Date: Tue, 1 Mar 2022 19:03:06 +0100 Subject: [PATCH 298/414] feat: ipfs-webui v2.15 (#8712) Release Notes: https://github.com/ipfs/ipfs-webui/releases/tag/v2.15.0 --- core/corehttp/webui.go | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/core/corehttp/webui.go b/core/corehttp/webui.go index 72656751a95..0ed60f760db 100644 --- a/core/corehttp/webui.go +++ b/core/corehttp/webui.go @@ -1,11 +1,12 @@ package corehttp // TODO: move to IPNS -const WebUIPath = "/ipfs/bafybeihcyruaeza7uyjd6ugicbcrqumejf6uf353e5etdkhotqffwtguva" // v2.13.0 +const WebUIPath = "/ipfs/bafybeiednzu62vskme5wpoj4bjjikeg3xovfpp4t7vxk5ty2jxdi4mv4bu" // v2.15.0 // this is a list of all past webUI paths. var WebUIPaths = []string{ WebUIPath, + "/ipfs/bafybeihcyruaeza7uyjd6ugicbcrqumejf6uf353e5etdkhotqffwtguva", "/ipfs/bafybeiflkjt66aetfgcrgvv75izymd5kc47g6luepqmfq6zsf5w6ueth6y", "/ipfs/bafybeid26vjplsejg7t3nrh7mxmiaaxriebbm4xxrxxdunlk7o337m5sqq", "/ipfs/bafybeif4zkmu7qdhkpf3pnhwxipylqleof7rl6ojbe7mq3fzogz6m4xk3i", From 7bb3bfbc336860c08a951dc3d77a564661df56ed Mon Sep 17 00:00:00 2001 From: Hector Sanjuan Date: Wed, 2 Mar 2022 16:25:37 +0100 Subject: [PATCH 299/414] Bubble ErrNotFound improvements --- blocks/blockstoreutil/remove.go | 3 ++- core/commands/dag/export.go | 3 +-- core/commands/files.go | 2 +- core/coreapi/block.go | 2 ++ fuse/readonly/readonly_unix.go | 6 +----- gc/gc.go | 2 +- go.mod | 16 ++++++++-------- go.sum | 28 ++++++++++++++++++---------- 8 files changed, 34 insertions(+), 28 deletions(-) diff --git a/blocks/blockstoreutil/remove.go b/blocks/blockstoreutil/remove.go index 880f033656f..b4e944fdfcb 100644 --- a/blocks/blockstoreutil/remove.go +++ b/blocks/blockstoreutil/remove.go @@ -9,6 +9,7 @@ import ( cid "github.com/ipfs/go-cid" bs "github.com/ipfs/go-ipfs-blockstore" pin "github.com/ipfs/go-ipfs-pinner" + format "github.com/ipfs/go-ipld-format" ) // RemovedBlock is used to represent the result of removing a block. @@ -54,7 +55,7 @@ func RmBlocks(ctx context.Context, blocks bs.GCBlockstore, pins pin.Pinner, cids continue } if !has && !opts.Force { - out <- &RemovedBlock{Hash: c.String(), Error: bs.ErrNotFound.Error()} + out <- &RemovedBlock{Hash: c.String(), Error: format.ErrNotFound{Cid: c}.Error()} continue } diff --git a/core/commands/dag/export.go b/core/commands/dag/export.go index 7290002e7f0..530bf4d5788 100644 --- a/core/commands/dag/export.go +++ b/core/commands/dag/export.go @@ -63,8 +63,7 @@ func dagExport(req *cmds.Request, res cmds.ResponseEmitter, env cmds.Environment err = <-errCh // minimal user friendliness - if err != nil && - err == ipld.ErrNotFound { + if ipld.IsNotFound(err) { explicitOffline, _ := req.Options["offline"].(bool) if explicitOffline { err = fmt.Errorf("%s (currently offline, perhaps retry without the offline flag)", err) diff --git a/core/commands/files.go b/core/commands/files.go index 879f1fab10e..4c403f7688a 100644 --- a/core/commands/files.go +++ b/core/commands/files.go @@ -297,7 +297,7 @@ func walkBlock(ctx context.Context, dagserv ipld.DAGService, nd ipld.Node) (bool for _, link := range nd.Links() { child, err := dagserv.Get(ctx, link.Cid) - if err == ipld.ErrNotFound { + if ipld.IsNotFound(err) { local = false continue } diff --git a/core/coreapi/block.go b/core/coreapi/block.go index e1ad9badc05..a1d5984d412 100644 --- a/core/coreapi/block.go +++ b/core/coreapi/block.go @@ -107,6 +107,8 @@ func (api *BlockAPI) Rm(ctx context.Context, p path.Path, opts ...caopts.BlockRm return errors.New("got unexpected output from util.RmBlocks") } + // Because errors come as strings we lose information about + // the error type. if remBlock.Error != "" { return errors.New(remBlock.Error) } diff --git a/fuse/readonly/readonly_unix.go b/fuse/readonly/readonly_unix.go index 1fbb473106d..af961221ca7 100644 --- a/fuse/readonly/readonly_unix.go +++ b/fuse/readonly/readonly_unix.go @@ -188,13 +188,9 @@ func (s *Node) Lookup(ctx context.Context, name string) (fs.Node, error) { } nd, err := s.Ipfs.DAG.Get(ctx, link.Cid) - switch err { - case ipld.ErrNotFound: - default: + if err != nil && !ipld.IsNotFound(err) { log.Errorf("fuse lookup %q: %s", name, err) return nil, err - case nil: - // noop } return &Node{Ipfs: s.Ipfs, Nd: nd}, nil diff --git a/gc/gc.go b/gc/gc.go index a77142e103a..e3b0fda68f9 100644 --- a/gc/gc.go +++ b/gc/gc.go @@ -233,7 +233,7 @@ func ColoredSet(ctx context.Context, pn pin.Pinner, ng ipld.NodeGetter, bestEffo bestEffortGetLinks := func(ctx context.Context, cid cid.Cid) ([]*ipld.Link, error) { links, err := ipld.GetLinks(ctx, ng, cid) - if err != nil && err != ipld.ErrNotFound { + if err != nil && !ipld.IsNotFound(err) { errors = true select { case output <- Result{Error: &CannotFetchLinksError{cid, err}}: diff --git a/go.mod b/go.mod index 8546b9057b3..f87cb2edbc8 100644 --- a/go.mod +++ b/go.mod @@ -13,9 +13,9 @@ require ( github.com/gabriel-vasile/mimetype v1.4.0 github.com/go-bindata/go-bindata/v3 v3.1.3 github.com/hashicorp/go-multierror v1.1.1 - github.com/ipfs/go-bitswap v0.5.1 + github.com/ipfs/go-bitswap v0.5.2-0.20220302142610-595ae6937936 github.com/ipfs/go-block-format v0.0.3 - github.com/ipfs/go-blockservice v0.2.1 + github.com/ipfs/go-blockservice v0.2.2-0.20220302144055-931fbecb724e github.com/ipfs/go-cid v0.1.0 github.com/ipfs/go-cidutil v0.0.2 github.com/ipfs/go-datastore v0.5.1 @@ -25,15 +25,15 @@ require ( github.com/ipfs/go-ds-leveldb v0.5.0 github.com/ipfs/go-ds-measure v0.2.0 github.com/ipfs/go-fetcher v1.6.1 - github.com/ipfs/go-filestore v1.1.0 + github.com/ipfs/go-filestore v1.1.1-0.20220302151633-1dfe2386cda8 github.com/ipfs/go-fs-lock v0.0.7 github.com/ipfs/go-graphsync v0.11.0 - github.com/ipfs/go-ipfs-blockstore v1.1.2 + github.com/ipfs/go-ipfs-blockstore v1.1.3-0.20220302142350-af197de1c3da github.com/ipfs/go-ipfs-chunker v0.0.5 github.com/ipfs/go-ipfs-cmds v0.6.0 github.com/ipfs/go-ipfs-config v0.19.0 github.com/ipfs/go-ipfs-exchange-interface v0.1.0 - github.com/ipfs/go-ipfs-exchange-offline v0.1.1 + github.com/ipfs/go-ipfs-exchange-offline v0.1.2-0.20220302144615-a919970e8153 github.com/ipfs/go-ipfs-files v0.0.9 github.com/ipfs/go-ipfs-keystore v0.0.2 github.com/ipfs/go-ipfs-pinner v0.2.1 @@ -42,12 +42,12 @@ require ( github.com/ipfs/go-ipfs-routing v0.2.1 github.com/ipfs/go-ipfs-util v0.0.2 github.com/ipfs/go-ipld-cbor v0.0.5 - github.com/ipfs/go-ipld-format v0.2.0 + github.com/ipfs/go-ipld-format v0.2.1-0.20220302134852-d02e0e18fc65 github.com/ipfs/go-ipld-git v0.1.1 github.com/ipfs/go-ipld-legacy v0.1.0 github.com/ipfs/go-ipns v0.1.2 github.com/ipfs/go-log v1.0.5 - github.com/ipfs/go-merkledag v0.5.1 + github.com/ipfs/go-merkledag v0.5.2-0.20220302145706-4c7f7bfbe598 github.com/ipfs/go-metrics-interface v0.0.1 github.com/ipfs/go-metrics-prometheus v0.0.2 github.com/ipfs/go-mfs v0.2.1 @@ -57,7 +57,7 @@ require ( github.com/ipfs/go-unixfs v0.3.1 github.com/ipfs/go-unixfsnode v1.1.3 github.com/ipfs/go-verifcid v0.0.1 - github.com/ipfs/interface-go-ipfs-core v0.5.2 + github.com/ipfs/interface-go-ipfs-core v0.5.3-0.20220302172844-ebde7297b2a0 github.com/ipfs/tar-utils v0.0.2 github.com/ipld/go-car v0.3.2 github.com/ipld/go-codec-dagpb v1.3.0 diff --git a/go.sum b/go.sum index e791d5ea3cf..d5a4e09a87c 100644 --- a/go.sum +++ b/go.sum @@ -397,8 +397,9 @@ github.com/ipfs/go-bitswap v0.1.0/go.mod h1:FFJEf18E9izuCqUtHxbWEvq+reg7o4CW5wSA github.com/ipfs/go-bitswap v0.1.2/go.mod h1:qxSWS4NXGs7jQ6zQvoPY3+NmOfHHG47mhkiLzBpJQIs= github.com/ipfs/go-bitswap v0.1.8/go.mod h1:TOWoxllhccevbWFUR2N7B1MTSVVge1s6XSMiCSA4MzM= github.com/ipfs/go-bitswap v0.3.4/go.mod h1:4T7fvNv/LmOys+21tnLzGKncMeeXUYUd1nUiJ2teMvI= -github.com/ipfs/go-bitswap v0.5.1 h1:721YAEDBnLIrvcIMkCHCdqp34hA8jwL9yKMkyJpSpco= github.com/ipfs/go-bitswap v0.5.1/go.mod h1:P+ckC87ri1xFLvk74NlXdP0Kj9RmWAh4+H78sC6Qopo= +github.com/ipfs/go-bitswap v0.5.2-0.20220302142610-595ae6937936 h1:1Ps0PF7jFKqO8/QwHaFvwCpQ0AITuYSbOI50gts3OiM= +github.com/ipfs/go-bitswap v0.5.2-0.20220302142610-595ae6937936/go.mod h1:Ro9XYuNUQxtx/YIZm+OA5mEnADStr5fyowhSUIgZtaU= github.com/ipfs/go-block-format v0.0.1/go.mod h1:DK/YYcsSUIVAFNwo/KZCdIIbpN0ROH/baNLgayt4pFc= github.com/ipfs/go-block-format v0.0.2/go.mod h1:AWR46JfpcObNfg3ok2JHDUfdiHRgWhJgCQF+KIgOPJY= github.com/ipfs/go-block-format v0.0.3 h1:r8t66QstRp/pd/or4dpnbVfXT5Gt7lOqRvC+/dDTpMc= @@ -407,8 +408,9 @@ github.com/ipfs/go-blockservice v0.0.7/go.mod h1:EOfb9k/Y878ZTRY/CH0x5+ATtaipfbR github.com/ipfs/go-blockservice v0.1.0/go.mod h1:hzmMScl1kXHg3M2BjTymbVPjv627N7sYcvYaKbop39M= github.com/ipfs/go-blockservice v0.1.4/go.mod h1:OTZhFpkgY48kNzbgyvcexW9cHrpjBYIjSR0KoDOFOLU= github.com/ipfs/go-blockservice v0.1.7/go.mod h1:GmS+BAt4hrwBKkzE11AFDQUrnvqjwFatGS2MY7wOjEM= -github.com/ipfs/go-blockservice v0.2.1 h1:NJ4j/cwEfIg60rzAWcCIxRtOwbf6ZPK49MewNxObCPQ= github.com/ipfs/go-blockservice v0.2.1/go.mod h1:k6SiwmgyYgs4M/qt+ww6amPeUH9EISLRBnvUurKJhi8= +github.com/ipfs/go-blockservice v0.2.2-0.20220302144055-931fbecb724e h1:Nqyg2HAa7lS19g6N7UTpbiJQFHKSO7yp+DvcqY4iBFk= +github.com/ipfs/go-blockservice v0.2.2-0.20220302144055-931fbecb724e/go.mod h1:0rezJNcrjTA32XEEXiV/DQAztHZrVduLb7GiktRq6lg= github.com/ipfs/go-cid v0.0.1/go.mod h1:GHWU/WuQdMPmIosc4Yn1bcCT7dSeX4lBafM7iqUPQvM= github.com/ipfs/go-cid v0.0.2/go.mod h1:GHWU/WuQdMPmIosc4Yn1bcCT7dSeX4lBafM7iqUPQvM= github.com/ipfs/go-cid v0.0.3/go.mod h1:GHWU/WuQdMPmIosc4Yn1bcCT7dSeX4lBafM7iqUPQvM= @@ -455,8 +457,8 @@ github.com/ipfs/go-ds-measure v0.2.0/go.mod h1:SEUD/rE2PwRa4IQEC5FuNAmjJCyYObZr9 github.com/ipfs/go-fetcher v1.5.0/go.mod h1:5pDZ0393oRF/fHiLmtFZtpMNBQfHOYNPtryWedVuSWE= github.com/ipfs/go-fetcher v1.6.1 h1:UFuRVYX5AIllTiRhi5uK/iZkfhSpBCGX7L70nSZEmK8= github.com/ipfs/go-fetcher v1.6.1/go.mod h1:27d/xMV8bodjVs9pugh/RCjjK2OZ68UgAMspMdingNo= -github.com/ipfs/go-filestore v1.1.0 h1:Pu4tLBi1bucu6/HU9llaOmb9yLFk/sgP+pW764zNDoE= -github.com/ipfs/go-filestore v1.1.0/go.mod h1:6e1/5Y6NvLuCRdmda/KA4GUhXJQ3Uat6vcWm2DJfxc8= +github.com/ipfs/go-filestore v1.1.1-0.20220302151633-1dfe2386cda8 h1:e92gjZ0hO8CCcdi7UN18ghULbd/ZoP524Qm9iZltaF0= +github.com/ipfs/go-filestore v1.1.1-0.20220302151633-1dfe2386cda8/go.mod h1:EQKwAmJqrW20KGt+xU2DVK2RBFgcwYTF9eNM/M0EfKs= github.com/ipfs/go-fs-lock v0.0.7 h1:6BR3dajORFrFTkb5EpCUFIAypsoxpGpDSVUdFwzgL9U= github.com/ipfs/go-fs-lock v0.0.7/go.mod h1:Js8ka+FNYmgQRLrRXzU3CB/+Csr1BwrRilEcvYrHhhc= github.com/ipfs/go-graphsync v0.11.0 h1:PiiD5CnoC3xEHMW8d6uBGqGcoTwiMB5d9CORIEyF6iA= @@ -466,9 +468,8 @@ github.com/ipfs/go-ipfs-blockstore v0.1.0/go.mod h1:5aD0AvHPi7mZc6Ci1WCAhiBQu2Is github.com/ipfs/go-ipfs-blockstore v0.1.4/go.mod h1:Jxm3XMVjh6R17WvxFEiyKBLUGr86HgIYJW/D/MwqeYQ= github.com/ipfs/go-ipfs-blockstore v0.1.6/go.mod h1:Jxm3XMVjh6R17WvxFEiyKBLUGr86HgIYJW/D/MwqeYQ= github.com/ipfs/go-ipfs-blockstore v0.2.1/go.mod h1:jGesd8EtCM3/zPgx+qr0/feTXGUeRai6adgwC+Q+JvE= -github.com/ipfs/go-ipfs-blockstore v1.1.1/go.mod h1:w51tNR9y5+QXB0wkNcHt4O2aSZjTdqaEWaQdSxEyUOY= -github.com/ipfs/go-ipfs-blockstore v1.1.2 h1:WCXoZcMYnvOTmlpX+RSSnhVN0uCmbWTeepTGX5lgiXw= -github.com/ipfs/go-ipfs-blockstore v1.1.2/go.mod h1:w51tNR9y5+QXB0wkNcHt4O2aSZjTdqaEWaQdSxEyUOY= +github.com/ipfs/go-ipfs-blockstore v1.1.3-0.20220302142350-af197de1c3da h1:/TU6rnYvsuKOwqpWxQXtO/K1Uj7IYY2GFE0WUr4Gh2Y= +github.com/ipfs/go-ipfs-blockstore v1.1.3-0.20220302142350-af197de1c3da/go.mod h1:dFOiy6XAxbK5x1Jvx7OAO1rQsrcyHxaXdTLWN085QoE= github.com/ipfs/go-ipfs-blocksutil v0.0.1 h1:Eh/H4pc1hsvhzsQoMEP3Bke/aW5P5rVM1IWFJMcGIPQ= github.com/ipfs/go-ipfs-blocksutil v0.0.1/go.mod h1:Yq4M86uIOmxmGPUHv/uI7uKqZNtLb449gwKqXjIsnRk= github.com/ipfs/go-ipfs-chunker v0.0.1/go.mod h1:tWewYK0we3+rMbOh7pPFGDyypCtvGcBFymgY4rSDLAw= @@ -489,8 +490,9 @@ github.com/ipfs/go-ipfs-exchange-interface v0.0.1/go.mod h1:c8MwfHjtQjPoDyiy9cFq github.com/ipfs/go-ipfs-exchange-interface v0.1.0 h1:TiMekCrOGQuWYtZO3mf4YJXDIdNgnKWZ9IE3fGlnWfo= github.com/ipfs/go-ipfs-exchange-interface v0.1.0/go.mod h1:ych7WPlyHqFvCi/uQI48zLZuAWVP5iTQPXEfVaw5WEI= github.com/ipfs/go-ipfs-exchange-offline v0.0.1/go.mod h1:WhHSFCVYX36H/anEKQboAzpUws3x7UeEGkzQc3iNkM0= -github.com/ipfs/go-ipfs-exchange-offline v0.1.1 h1:mEiXWdbMN6C7vtDG21Fphx8TGCbZPpQnz/496w/PL4g= github.com/ipfs/go-ipfs-exchange-offline v0.1.1/go.mod h1:vTiBRIbzSwDD0OWm+i3xeT0mO7jG2cbJYatp3HPk5XY= +github.com/ipfs/go-ipfs-exchange-offline v0.1.2-0.20220302144615-a919970e8153 h1:GtLORXk45GpVMfhPz+IyZ9YNAe36BQ+rKZvem5Bo49Y= +github.com/ipfs/go-ipfs-exchange-offline v0.1.2-0.20220302144615-a919970e8153/go.mod h1:fjwwh1LDdR2LrZ0qYeDbWx4pgdTq+Tw48YaLBjCS2qk= github.com/ipfs/go-ipfs-files v0.0.3/go.mod h1:INEFm0LL2LWXBhNJ2PMIIb2w45hpXgPjNoE7yA8Y1d4= github.com/ipfs/go-ipfs-files v0.0.8/go.mod h1:wiN/jSG8FKyk7N0WyctKSvq3ljIa2NNTiZB55kpTdOs= github.com/ipfs/go-ipfs-files v0.0.9 h1:OFyOfmuVDu9c5YtjSDORmwXzE6fmZikzZpzsnNkgFEg= @@ -520,8 +522,9 @@ github.com/ipfs/go-ipld-cbor v0.0.5 h1:ovz4CHKogtG2KB/h1zUp5U0c/IzZrL435rCh5+K/5 github.com/ipfs/go-ipld-cbor v0.0.5/go.mod h1:BkCduEx3XBCO6t2Sfo5BaHzuok7hbhdMm9Oh8B2Ftq4= github.com/ipfs/go-ipld-format v0.0.1/go.mod h1:kyJtbkDALmFHv3QR6et67i35QzO3S0dCDnkOJhcZkms= github.com/ipfs/go-ipld-format v0.0.2/go.mod h1:4B6+FM2u9OJ9zCV+kSbgFAZlOrv1Hqbf0INGQgiKf9k= -github.com/ipfs/go-ipld-format v0.2.0 h1:xGlJKkArkmBvowr+GMCX0FEZtkro71K1AwiKnL37mwA= github.com/ipfs/go-ipld-format v0.2.0/go.mod h1:3l3C1uKoadTPbeNfrDi+xMInYKlx2Cvg1BuydPSdzQs= +github.com/ipfs/go-ipld-format v0.2.1-0.20220302134852-d02e0e18fc65 h1:xxnD+fUS7hziDAnfrn3qsl0ql18DOjq4rwvzBTCr1iA= +github.com/ipfs/go-ipld-format v0.2.1-0.20220302134852-d02e0e18fc65/go.mod h1:co/SdBE8h99968X0hViiw1MNlh6fvxxnHpvVLnH7jSM= github.com/ipfs/go-ipld-git v0.1.1 h1:TWGnZjS0htmEmlMFEkA3ogrNCqWjIxwr16x1OsdhG+Y= github.com/ipfs/go-ipld-git v0.1.1/go.mod h1:+VyMqF5lMcJh4rwEppV0e6g4nCCHXThLYYDpKUkJubI= github.com/ipfs/go-ipld-legacy v0.1.0 h1:wxkkc4k8cnvIGIjPO0waJCe7SHEyFgl+yQdafdjGrpA= @@ -545,8 +548,9 @@ github.com/ipfs/go-merkledag v0.0.6/go.mod h1:QYPdnlvkOg7GnQRofu9XZimC5ZW5Wi3bKy github.com/ipfs/go-merkledag v0.2.3/go.mod h1:SQiXrtSts3KGNmgOzMICy5c0POOpUNQLvB3ClKnBAlk= github.com/ipfs/go-merkledag v0.3.2/go.mod h1:fvkZNNZixVW6cKSZ/JfLlON5OlgTXNdRLz0p6QG/I2M= github.com/ipfs/go-merkledag v0.4.0/go.mod h1:XshXBkhyeS63YNGisLL1uDSfuTyrQIxVUOg3ojR5MOE= -github.com/ipfs/go-merkledag v0.5.1 h1:tr17GPP5XtPhvPPiWtu20tSGZiZDuTaJRXBLcr79Umk= github.com/ipfs/go-merkledag v0.5.1/go.mod h1:cLMZXx8J08idkp5+id62iVftUQV+HlYJ3PIhDfZsjA4= +github.com/ipfs/go-merkledag v0.5.2-0.20220302145706-4c7f7bfbe598 h1:LBBmuAf+riiqOFU/YbErKaHF2kZ5ajc1cjy2puuNyLs= +github.com/ipfs/go-merkledag v0.5.2-0.20220302145706-4c7f7bfbe598/go.mod h1:nYh/2ZlUEAHL8glS7y93pPA3Ut7JHkY5fYThsrp8+RY= github.com/ipfs/go-metrics-interface v0.0.1 h1:j+cpbjYvu4R8zbleSs36gvB7jR+wsL2fGD6n0jO4kdg= github.com/ipfs/go-metrics-interface v0.0.1/go.mod h1:6s6euYU4zowdslK0GKHmqaIZ3j/b/tL7HTWtJ4VPgWY= github.com/ipfs/go-metrics-prometheus v0.0.2 h1:9i2iljLg12S78OhC6UAiXi176xvQGiZaGVF1CUVdE+s= @@ -580,6 +584,10 @@ github.com/ipfs/go-verifcid v0.0.1/go.mod h1:5Hrva5KBeIog4A+UpqlaIU+DEstipcJYQQZ github.com/ipfs/interface-go-ipfs-core v0.4.0/go.mod h1:UJBcU6iNennuI05amq3FQ7g0JHUkibHFAfhfUIy927o= github.com/ipfs/interface-go-ipfs-core v0.5.2 h1:m1/5U+WpOK2ZE7Qzs5iIu80QM1ZA3aWYi2Ilwpi+tdg= github.com/ipfs/interface-go-ipfs-core v0.5.2/go.mod h1:lNBJrdXHtWS46evMPBdWtDQMDsrKcGbxCOGoKLkztOE= +github.com/ipfs/interface-go-ipfs-core v0.5.3-0.20220302154624-b7f863f05698 h1:PidDOk6cfYYKsO+1LVRpKQUccKJMxB/7It75TATpruA= +github.com/ipfs/interface-go-ipfs-core v0.5.3-0.20220302154624-b7f863f05698/go.mod h1:1wpi0hALzziD775jYmRiehbakCmxZA3XTlTlF3D2z2c= +github.com/ipfs/interface-go-ipfs-core v0.5.3-0.20220302172844-ebde7297b2a0 h1:Y+PmGrp9gF9UTIQHMc6PGEMvV6Ylk5zAQJYyIg8z5Mk= +github.com/ipfs/interface-go-ipfs-core v0.5.3-0.20220302172844-ebde7297b2a0/go.mod h1:1wpi0hALzziD775jYmRiehbakCmxZA3XTlTlF3D2z2c= github.com/ipfs/tar-utils v0.0.2 h1:UNgHB4x/PPzbMkmJi+7EqC9LNMPDztOVSnx1HAqSNg4= github.com/ipfs/tar-utils v0.0.2/go.mod h1:4qlnRWgTVljIMhSG2SqRYn66NT+3wrv/kZt9V+eqxDM= github.com/ipld/go-car v0.3.2 h1:V9wt/80FNfbMRWSD98W5br6fyjUAyVgI2lDOTZX16Lg= From eb86f3659a2b8b551220f37959dc99658e3d14eb Mon Sep 17 00:00:00 2001 From: Hector Sanjuan Date: Wed, 2 Mar 2022 18:40:10 +0100 Subject: [PATCH 300/414] Fix sharness for new not found error messages --- test/sharness/t0050-block.sh | 4 ++-- test/sharness/t0054-dag-car-import-export.sh | 2 +- test/sharness/t0080-repo.sh | 2 +- test/sharness/t0081-repo-pinning.sh | 2 +- 4 files changed, 5 insertions(+), 5 deletions(-) diff --git a/test/sharness/t0050-block.sh b/test/sharness/t0050-block.sh index 70639f623e9..b83b0ae3132 100755 --- a/test/sharness/t0050-block.sh +++ b/test/sharness/t0050-block.sh @@ -134,9 +134,9 @@ test_expect_success "multi-block 'ipfs block rm '" ' ' test_expect_success "multi-block 'ipfs block rm ' output looks good" ' - echo "cannot remove $RANDOMHASH: blockstore: block not found" >> expect_mixed_rm && + echo "cannot remove $RANDOMHASH: ipld: $RANDOMHASH not found" >> expect_mixed_rm && echo "removed $TESTHASH" >> expect_mixed_rm && - echo "cannot remove $RANDOMHASH: blockstore: block not found" >> expect_mixed_rm && + echo "cannot remove $RANDOMHASH: ipld: $RANDOMHASH not found" >> expect_mixed_rm && echo "Error: some blocks not removed" >> expect_mixed_rm test_cmp actual_mixed_rm expect_mixed_rm ' diff --git a/test/sharness/t0054-dag-car-import-export.sh b/test/sharness/t0054-dag-car-import-export.sh index 311833748f0..725321472eb 100755 --- a/test/sharness/t0054-dag-car-import-export.sh +++ b/test/sharness/t0054-dag-car-import-export.sh @@ -179,7 +179,7 @@ test_expect_success "basic offline export of 'getting started' dag works" ' ' -echo "Error: merkledag: not found (currently offline, perhaps retry after attaching to the network)" > offline_fetch_error_expected +echo "Error: block was not found locally (offline): ipld: QmYwAPJXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX not found (currently offline, perhaps retry after attaching to the network)" > offline_fetch_error_expected test_expect_success "basic offline export of nonexistent cid" ' ! ipfs dag export QmYwAPJXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX 2> offline_fetch_error_actual >/dev/null ' diff --git a/test/sharness/t0080-repo.sh b/test/sharness/t0080-repo.sh index 839e651d1c5..0c5d3561503 100755 --- a/test/sharness/t0080-repo.sh +++ b/test/sharness/t0080-repo.sh @@ -64,7 +64,7 @@ test_expect_success "'ipfs repo gc --silent' succeeds (no output)" ' ipfs repo gc --silent >gc_out_empty && test_cmp /dev/null gc_out_empty && test_must_fail ipfs cat "$HASH2" 2>err_expected1 && - grep "Error: merkledag: not found" err_expected1 + grep "Error: ipld: $HASH2 not found" err_expected1 ' test_kill_ipfs_daemon diff --git a/test/sharness/t0081-repo-pinning.sh b/test/sharness/t0081-repo-pinning.sh index 121051ee18a..9c69b9eb34b 100755 --- a/test/sharness/t0081-repo-pinning.sh +++ b/test/sharness/t0081-repo-pinning.sh @@ -238,7 +238,7 @@ test_expect_success "some are no longer there" ' test_launch_ipfs_daemon_without_network test_expect_success "recursive pin fails without objects" ' test_must_fail ipfs pin add -r "$HASH_DIR1" 2>err_expected8 && - grep "pin: merkledag: not found" err_expected8 || + grep "Error: pin: block was not found locally (offline): ipld: $HASH_DIR1 not found" err_expected8 || test_fsh cat err_expected8 ' From 04048f46a2fec22c726310b7cd0f0bb4cf978a19 Mon Sep 17 00:00:00 2001 From: Hector Sanjuan Date: Wed, 2 Mar 2022 19:14:35 +0100 Subject: [PATCH 301/414] Try to fix sharness error --- test/sharness/t0081-repo-pinning.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/sharness/t0081-repo-pinning.sh b/test/sharness/t0081-repo-pinning.sh index 9c69b9eb34b..941cd730195 100755 --- a/test/sharness/t0081-repo-pinning.sh +++ b/test/sharness/t0081-repo-pinning.sh @@ -238,7 +238,7 @@ test_expect_success "some are no longer there" ' test_launch_ipfs_daemon_without_network test_expect_success "recursive pin fails without objects" ' test_must_fail ipfs pin add -r "$HASH_DIR1" 2>err_expected8 && - grep "Error: pin: block was not found locally (offline): ipld: $HASH_DIR1 not found" err_expected8 || + grep "$HASH_DIR1 not found" err_expected8 || test_fsh cat err_expected8 ' From 6c6830c8228bc76c0c56aafa49624e286c6c01f2 Mon Sep 17 00:00:00 2001 From: Hector Sanjuan Date: Wed, 2 Mar 2022 19:30:38 +0100 Subject: [PATCH 302/414] Fix sharness --- test/sharness/t0081-repo-pinning.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/sharness/t0081-repo-pinning.sh b/test/sharness/t0081-repo-pinning.sh index 941cd730195..656698fae06 100755 --- a/test/sharness/t0081-repo-pinning.sh +++ b/test/sharness/t0081-repo-pinning.sh @@ -238,7 +238,7 @@ test_expect_success "some are no longer there" ' test_launch_ipfs_daemon_without_network test_expect_success "recursive pin fails without objects" ' test_must_fail ipfs pin add -r "$HASH_DIR1" 2>err_expected8 && - grep "$HASH_DIR1 not found" err_expected8 || + grep "not found" err_expected8 || test_fsh cat err_expected8 ' From e1d14441a090e893a145112dc2f26a6b20c9cf4b Mon Sep 17 00:00:00 2001 From: Kyle Huntsman <3432646+kylehuntsman@users.noreply.github.com> Date: Wed, 2 Mar 2022 20:26:56 -0700 Subject: [PATCH 303/414] fix(fsrepo): deep merge when setting config --- repo/common/common.go | 30 +++++++ repo/common/common_test.go | 132 +++++++++++++++++++++++++++++++ repo/fsrepo/fsrepo.go | 6 +- test/sharness/t0250-files-api.sh | 2 +- 4 files changed, 165 insertions(+), 5 deletions(-) create mode 100644 repo/common/common_test.go diff --git a/repo/common/common.go b/repo/common/common.go index dc1e7c50360..1f1f0cd570a 100644 --- a/repo/common/common.go +++ b/repo/common/common.go @@ -54,3 +54,33 @@ func MapSetKV(v map[string]interface{}, key string, value interface{}) error { } return nil } + +// Merges the right map into the left map, recursively traversing child maps +// until a non-map value is found +func MapMergeDeep(left, right map[string]interface{}) map[string]interface{} { + // We want to alter a copy of the map, not the original + result := make(map[string]interface{}) + for k, v := range left { + result[k] = v + } + + for key, rightVal := range right { + // If right value is a map + if rightMap, ok := rightVal.(map[string]interface{}); ok { + // If key is in left + if leftVal, found := result[key]; found { + // If left value is also a map + if leftMap, ok := leftVal.(map[string]interface{}); ok { + // Merge nested map + result[key] = MapMergeDeep(leftMap, rightMap) + continue + } + } + } + + // Otherwise set new value to result + result[key] = rightVal + } + + return result +} diff --git a/repo/common/common_test.go b/repo/common/common_test.go new file mode 100644 index 00000000000..5f62b688c8f --- /dev/null +++ b/repo/common/common_test.go @@ -0,0 +1,132 @@ +package common + +import ( + "testing" + + "github.com/ipfs/go-ipfs/thirdparty/assert" +) + +func TestMapMergeDeepReturnsNew(t *testing.T) { + leftMap := make(map[string]interface{}) + leftMap["A"] = "Hello World" + + rightMap := make(map[string]interface{}) + rightMap["A"] = "Foo" + + MapMergeDeep(leftMap, rightMap) + + assert.True(leftMap["A"] == "Hello World", t, "MapMergeDeep should return a new map instance") +} + +func TestMapMergeDeepNewKey(t *testing.T) { + leftMap := make(map[string]interface{}) + leftMap["A"] = "Hello World" + /* + leftMap + { + A: "Hello World" + } + */ + + rightMap := make(map[string]interface{}) + rightMap["B"] = "Bar" + /* + rightMap + { + B: "Bar" + } + */ + + result := MapMergeDeep(leftMap, rightMap) + /* + expected + { + A: "Hello World" + B: "Bar" + } + */ + + assert.True(result["B"] == "Bar", t, "New keys in right map should exist in resulting map") +} + +func TestMapMergeDeepRecursesOnMaps(t *testing.T) { + leftMapA := make(map[string]interface{}) + leftMapA["B"] = "A value!" + leftMapA["C"] = "Another value!" + + leftMap := make(map[string]interface{}) + leftMap["A"] = leftMapA + /* + leftMap + { + A: { + B: "A value!" + C: "Another value!" + } + } + */ + + rightMapA := make(map[string]interface{}) + rightMapA["C"] = "A different value!" + + rightMap := make(map[string]interface{}) + rightMap["A"] = rightMapA + /* + rightMap + { + A: { + C: "A different value!" + } + } + */ + + result := MapMergeDeep(leftMap, rightMap) + /* + expected + { + A: { + B: "A value!" + C: "A different value!" + } + } + */ + + resultA := result["A"].(map[string]interface{}) + assert.True(resultA["B"] == "A value!", t, "Unaltered values should not change") + assert.True(resultA["C"] == "A different value!", t, "Nested values should be altered") +} + +func TestMapMergeDeepRightNotAMap(t *testing.T) { + leftMapA := make(map[string]interface{}) + leftMapA["B"] = "A value!" + + leftMap := make(map[string]interface{}) + leftMap["A"] = leftMapA + /* + origMap + { + A: { + B: "A value!" + } + } + */ + + rightMap := make(map[string]interface{}) + rightMap["A"] = "Not a map!" + /* + newMap + { + A: "Not a map!" + } + */ + + result := MapMergeDeep(leftMap, rightMap) + /* + expected + { + A: "Not a map!" + } + */ + + assert.True(result["A"] == "Not a map!", t, "Right values that are not a map should be set on the result") +} diff --git a/repo/fsrepo/fsrepo.go b/repo/fsrepo/fsrepo.go index 2aa4a5e46c8..a4234dc491a 100644 --- a/repo/fsrepo/fsrepo.go +++ b/repo/fsrepo/fsrepo.go @@ -559,10 +559,8 @@ func (r *FSRepo) setConfigUnsynced(updated *config.Config) error { if err != nil { return err } - for k, v := range m { - mapconf[k] = v - } - if err := serialize.WriteConfigFile(configFilename, mapconf); err != nil { + mergedMap := common.MapMergeDeep(mapconf, m) + if err := serialize.WriteConfigFile(configFilename, mergedMap); err != nil { return err } // Do not use `*r.config = ...`. This will modify the *shared* config diff --git a/test/sharness/t0250-files-api.sh b/test/sharness/t0250-files-api.sh index c91dd123b33..78cfc39a2cf 100755 --- a/test/sharness/t0250-files-api.sh +++ b/test/sharness/t0250-files-api.sh @@ -876,7 +876,7 @@ test_expect_success "set up automatic sharding/unsharding data" ' ' # TODO: This does not need to report an error https://github.com/ipfs/go-ipfs/issues/8088 -test_expect_failure "reset automatic sharding" ' +test_expect_success "reset automatic sharding" ' ipfs config --json Internal.UnixFSShardingSizeThreshold null ' From c9cf47dad5a35e36bbf355ffe009b6d7a54ecbe5 Mon Sep 17 00:00:00 2001 From: Laurent Senta Date: Fri, 25 Feb 2022 18:50:04 +0100 Subject: [PATCH 304/414] config: remove go-ipfs-config code --- README.md | 1 - go.mod | 1 + 2 files changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 8c279efe046..f8d17ad20a3 100644 --- a/README.md +++ b/README.md @@ -412,7 +412,6 @@ Listing of the main packages used in the IPFS ecosystem. There are also three sp | **Namesys** | | [`go-ipns`](//github.com/ipfs/go-ipns) | [![Travis CI](https://flat.badgen.net/travis/ipfs/go-ipns/master)](https://travis-ci.com/ipfs/go-ipns) | [![codecov](https://codecov.io/gh/ipfs/go-ipns/branch/master/graph/badge.svg?style=flat-square)](https://codecov.io/gh/ipfs/go-ipns) | IPNS datastructures and validation logic | | **Repo** | -| [`go-ipfs-config`](//github.com/ipfs/go-ipfs-config) | [![Travis CI](https://flat.badgen.net/travis/ipfs/go-ipfs-config/master)](https://travis-ci.com/ipfs/go-ipfs-config) | [![codecov](https://codecov.io/gh/ipfs/go-ipfs-config/branch/master/graph/badge.svg?style=flat-square)](https://codecov.io/gh/ipfs/go-ipfs-config) | go-ipfs config file definitions | | [`go-fs-lock`](//github.com/ipfs/go-fs-lock) | [![Travis CI](https://flat.badgen.net/travis/ipfs/go-fs-lock/master)](https://travis-ci.com/ipfs/go-fs-lock) | [![codecov](https://codecov.io/gh/ipfs/go-fs-lock/branch/master/graph/badge.svg?style=flat-square)](https://codecov.io/gh/ipfs/go-fs-lock) | lockfile management functions | | [`fs-repo-migrations`](//github.com/ipfs/fs-repo-migrations) | [![Travis CI](https://flat.badgen.net/travis/ipfs/fs-repo-migrations/master)](https://travis-ci.com/ipfs/fs-repo-migrations) | [![codecov](https://codecov.io/gh/ipfs/fs-repo-migrations/branch/master/graph/badge.svg?style=flat-square)](https://codecov.io/gh/ipfs/fs-repo-migrations) | repo migrations | | **IPLD** | diff --git a/go.mod b/go.mod index 8546b9057b3..92c15f6ccea 100644 --- a/go.mod +++ b/go.mod @@ -9,6 +9,7 @@ require ( github.com/coreos/go-systemd/v22 v22.3.2 github.com/dustin/go-humanize v1.0.0 github.com/elgris/jsondiff v0.0.0-20160530203242-765b5c24c302 + github.com/facebookgo/atomicfile v0.0.0-20151019160806-2de1f203e7d5 github.com/fsnotify/fsnotify v1.5.1 github.com/gabriel-vasile/mimetype v1.4.0 github.com/go-bindata/go-bindata/v3 v3.1.3 From 8d549f03f3e02ef6c5efad11c9aab969fc6861ed Mon Sep 17 00:00:00 2001 From: Laurent Senta Date: Wed, 2 Mar 2022 14:48:24 +0100 Subject: [PATCH 305/414] fix: rewrite dependencies over the go-ipfs-config package --- cmd/ipfs/daemon.go | 4 ++-- cmd/ipfs/init.go | 2 +- cmd/ipfs/main.go | 2 +- cmd/ipfs/pinmfs.go | 2 +- cmd/ipfs/pinmfs_test.go | 2 +- cmd/ipfswatch/main.go | 3 ++- commands/context.go | 2 +- config/serialize/serialize.go | 2 +- config/serialize/serialize_test.go | 2 +- core/commands/bootstrap.go | 2 +- core/commands/cmdenv/env.go | 2 +- core/commands/config.go | 2 +- core/commands/keystore.go | 2 +- core/commands/mount_unix.go | 3 ++- core/commands/pin/remotepin.go | 2 +- core/commands/swarm.go | 2 +- core/core_test.go | 2 +- core/coreapi/test/api_test.go | 6 +++--- core/corehttp/commands.go | 2 +- core/corehttp/gateway_test.go | 2 +- core/corehttp/hostname.go | 2 +- core/corehttp/hostname_test.go | 2 +- core/coreunix/add_test.go | 2 +- core/mock/mock.go | 2 +- core/node/bitswap.go | 2 +- core/node/builder.go | 2 +- core/node/dns.go | 2 +- core/node/groups.go | 2 +- core/node/libp2p/libp2p.go | 2 +- core/node/libp2p/nat.go | 2 +- core/node/libp2p/relay.go | 2 +- core/node/libp2p/sec.go | 2 +- core/node/libp2p/smux.go | 2 +- core/node/libp2p/transport.go | 2 +- core/node/storage.go | 2 +- go.mod | 1 - go.sum | 2 -- package-list.json | 1 - plugin/loader/loader.go | 4 ++-- repo/fsrepo/config_test.go | 2 +- repo/fsrepo/fsrepo.go | 4 ++-- repo/fsrepo/fsrepo_test.go | 2 +- repo/fsrepo/migrations/ipfsfetcher/ipfsfetcher.go | 2 +- repo/fsrepo/migrations/migrations.go | 2 +- repo/fsrepo/migrations/migrations_test.go | 2 +- repo/fsrepo/misc.go | 2 +- repo/mock.go | 2 +- repo/repo.go | 2 +- test/bench/bench_cli_ipfs_add/main.go | 2 +- test/bench/offline_add/main.go | 2 +- 50 files changed, 54 insertions(+), 56 deletions(-) diff --git a/cmd/ipfs/daemon.go b/cmd/ipfs/daemon.go index 5de7e056eac..a2c65b5b99e 100644 --- a/cmd/ipfs/daemon.go +++ b/cmd/ipfs/daemon.go @@ -17,10 +17,10 @@ import ( multierror "github.com/hashicorp/go-multierror" version "github.com/ipfs/go-ipfs" - config "github.com/ipfs/go-ipfs-config" - cserial "github.com/ipfs/go-ipfs-config/serialize" utilmain "github.com/ipfs/go-ipfs/cmd/ipfs/util" oldcmds "github.com/ipfs/go-ipfs/commands" + config "github.com/ipfs/go-ipfs/config" + cserial "github.com/ipfs/go-ipfs/config/serialize" "github.com/ipfs/go-ipfs/core" commands "github.com/ipfs/go-ipfs/core/commands" "github.com/ipfs/go-ipfs/core/coreapi" diff --git a/cmd/ipfs/init.go b/cmd/ipfs/init.go index de3ad1180fa..dfbf01bb3a6 100644 --- a/cmd/ipfs/init.go +++ b/cmd/ipfs/init.go @@ -19,8 +19,8 @@ import ( unixfs "github.com/ipfs/go-unixfs" cmds "github.com/ipfs/go-ipfs-cmds" - config "github.com/ipfs/go-ipfs-config" files "github.com/ipfs/go-ipfs-files" + config "github.com/ipfs/go-ipfs/config" options "github.com/ipfs/interface-go-ipfs-core/options" ) diff --git a/cmd/ipfs/main.go b/cmd/ipfs/main.go index d975d18971f..11b21c89905 100644 --- a/cmd/ipfs/main.go +++ b/cmd/ipfs/main.go @@ -24,8 +24,8 @@ import ( cmds "github.com/ipfs/go-ipfs-cmds" "github.com/ipfs/go-ipfs-cmds/cli" cmdhttp "github.com/ipfs/go-ipfs-cmds/http" - config "github.com/ipfs/go-ipfs-config" u "github.com/ipfs/go-ipfs-util" + config "github.com/ipfs/go-ipfs/config" logging "github.com/ipfs/go-log" loggables "github.com/libp2p/go-libp2p-loggables" ma "github.com/multiformats/go-multiaddr" diff --git a/cmd/ipfs/pinmfs.go b/cmd/ipfs/pinmfs.go index 8ea9d2dcc8e..5eadef5a7e8 100644 --- a/cmd/ipfs/pinmfs.go +++ b/cmd/ipfs/pinmfs.go @@ -13,7 +13,7 @@ import ( logging "github.com/ipfs/go-log" pinclient "github.com/ipfs/go-pinning-service-http-client" - config "github.com/ipfs/go-ipfs-config" + config "github.com/ipfs/go-ipfs/config" "github.com/ipfs/go-ipfs/core" ) diff --git a/cmd/ipfs/pinmfs_test.go b/cmd/ipfs/pinmfs_test.go index e38e196beb3..63c8af070ee 100644 --- a/cmd/ipfs/pinmfs_test.go +++ b/cmd/ipfs/pinmfs_test.go @@ -7,7 +7,7 @@ import ( "testing" "time" - config "github.com/ipfs/go-ipfs-config" + config "github.com/ipfs/go-ipfs/config" ipld "github.com/ipfs/go-ipld-format" merkledag "github.com/ipfs/go-merkledag" "github.com/libp2p/go-libp2p-core/host" diff --git a/cmd/ipfswatch/main.go b/cmd/ipfswatch/main.go index e0bd00e17dc..f810ada12c8 100644 --- a/cmd/ipfswatch/main.go +++ b/cmd/ipfswatch/main.go @@ -1,3 +1,4 @@ +//go:build !plan9 // +build !plan9 package main @@ -18,8 +19,8 @@ import ( fsrepo "github.com/ipfs/go-ipfs/repo/fsrepo" fsnotify "github.com/fsnotify/fsnotify" - config "github.com/ipfs/go-ipfs-config" files "github.com/ipfs/go-ipfs-files" + config "github.com/ipfs/go-ipfs/config" process "github.com/jbenet/goprocess" homedir "github.com/mitchellh/go-homedir" ) diff --git a/commands/context.go b/commands/context.go index e43672eee49..984071a05cd 100644 --- a/commands/context.go +++ b/commands/context.go @@ -11,7 +11,7 @@ import ( loader "github.com/ipfs/go-ipfs/plugin/loader" cmds "github.com/ipfs/go-ipfs-cmds" - config "github.com/ipfs/go-ipfs-config" + config "github.com/ipfs/go-ipfs/config" logging "github.com/ipfs/go-log" coreiface "github.com/ipfs/interface-go-ipfs-core" options "github.com/ipfs/interface-go-ipfs-core/options" diff --git a/config/serialize/serialize.go b/config/serialize/serialize.go index 04492c5f38f..e51e9211575 100644 --- a/config/serialize/serialize.go +++ b/config/serialize/serialize.go @@ -8,7 +8,7 @@ import ( "os" "path/filepath" - "github.com/ipfs/go-ipfs-config" + "github.com/ipfs/go-ipfs/config" "github.com/facebookgo/atomicfile" ) diff --git a/config/serialize/serialize_test.go b/config/serialize/serialize_test.go index e5abdb852f3..0c8e12f40c0 100644 --- a/config/serialize/serialize_test.go +++ b/config/serialize/serialize_test.go @@ -5,7 +5,7 @@ import ( "runtime" "testing" - config "github.com/ipfs/go-ipfs-config" + config "github.com/ipfs/go-ipfs/config" ) func TestConfig(t *testing.T) { diff --git a/core/commands/bootstrap.go b/core/commands/bootstrap.go index 1aaa6456501..d572e8c079b 100644 --- a/core/commands/bootstrap.go +++ b/core/commands/bootstrap.go @@ -11,7 +11,7 @@ import ( fsrepo "github.com/ipfs/go-ipfs/repo/fsrepo" cmds "github.com/ipfs/go-ipfs-cmds" - config "github.com/ipfs/go-ipfs-config" + config "github.com/ipfs/go-ipfs/config" peer "github.com/libp2p/go-libp2p-core/peer" ma "github.com/multiformats/go-multiaddr" ) diff --git a/core/commands/cmdenv/env.go b/core/commands/cmdenv/env.go index c21612c3305..06d401db4cf 100644 --- a/core/commands/cmdenv/env.go +++ b/core/commands/cmdenv/env.go @@ -9,7 +9,7 @@ import ( "github.com/ipfs/go-ipfs/core" cmds "github.com/ipfs/go-ipfs-cmds" - config "github.com/ipfs/go-ipfs-config" + config "github.com/ipfs/go-ipfs/config" logging "github.com/ipfs/go-log" coreiface "github.com/ipfs/interface-go-ipfs-core" options "github.com/ipfs/interface-go-ipfs-core/options" diff --git a/core/commands/config.go b/core/commands/config.go index 86037ceb4f9..7a6e5abaf07 100644 --- a/core/commands/config.go +++ b/core/commands/config.go @@ -16,7 +16,7 @@ import ( "github.com/elgris/jsondiff" cmds "github.com/ipfs/go-ipfs-cmds" - config "github.com/ipfs/go-ipfs-config" + config "github.com/ipfs/go-ipfs/config" ) // ConfigUpdateOutput is config profile apply command's output diff --git a/core/commands/keystore.go b/core/commands/keystore.go index 5596ceee03a..4f7ca4af80f 100644 --- a/core/commands/keystore.go +++ b/core/commands/keystore.go @@ -14,9 +14,9 @@ import ( "text/tabwriter" cmds "github.com/ipfs/go-ipfs-cmds" - config "github.com/ipfs/go-ipfs-config" keystore "github.com/ipfs/go-ipfs-keystore" oldcmds "github.com/ipfs/go-ipfs/commands" + config "github.com/ipfs/go-ipfs/config" cmdenv "github.com/ipfs/go-ipfs/core/commands/cmdenv" "github.com/ipfs/go-ipfs/core/commands/e" ke "github.com/ipfs/go-ipfs/core/commands/keyencode" diff --git a/core/commands/mount_unix.go b/core/commands/mount_unix.go index c6678d17585..1c72c6bd990 100644 --- a/core/commands/mount_unix.go +++ b/core/commands/mount_unix.go @@ -1,3 +1,4 @@ +//go:build !windows && !nofuse // +build !windows,!nofuse package commands @@ -10,7 +11,7 @@ import ( nodeMount "github.com/ipfs/go-ipfs/fuse/node" cmds "github.com/ipfs/go-ipfs-cmds" - config "github.com/ipfs/go-ipfs-config" + config "github.com/ipfs/go-ipfs/config" ) const ( diff --git a/core/commands/pin/remotepin.go b/core/commands/pin/remotepin.go index 0e4bf373ee0..495a1400367 100644 --- a/core/commands/pin/remotepin.go +++ b/core/commands/pin/remotepin.go @@ -17,7 +17,7 @@ import ( cid "github.com/ipfs/go-cid" cmds "github.com/ipfs/go-ipfs-cmds" - config "github.com/ipfs/go-ipfs-config" + config "github.com/ipfs/go-ipfs/config" "github.com/ipfs/go-ipfs/core/commands/cmdenv" fsrepo "github.com/ipfs/go-ipfs/repo/fsrepo" logging "github.com/ipfs/go-log" diff --git a/core/commands/swarm.go b/core/commands/swarm.go index 7c7ee3e814f..00899eacbed 100644 --- a/core/commands/swarm.go +++ b/core/commands/swarm.go @@ -16,7 +16,7 @@ import ( fsrepo "github.com/ipfs/go-ipfs/repo/fsrepo" cmds "github.com/ipfs/go-ipfs-cmds" - config "github.com/ipfs/go-ipfs-config" + config "github.com/ipfs/go-ipfs/config" inet "github.com/libp2p/go-libp2p-core/network" peer "github.com/libp2p/go-libp2p-core/peer" ma "github.com/multiformats/go-multiaddr" diff --git a/core/core_test.go b/core/core_test.go index 051b812c11a..e1563789e73 100644 --- a/core/core_test.go +++ b/core/core_test.go @@ -9,7 +9,7 @@ import ( datastore "github.com/ipfs/go-datastore" syncds "github.com/ipfs/go-datastore/sync" - config "github.com/ipfs/go-ipfs-config" + config "github.com/ipfs/go-ipfs/config" ) func TestInitialization(t *testing.T) { diff --git a/core/coreapi/test/api_test.go b/core/coreapi/test/api_test.go index 54f3b48ca43..5c078558b7f 100644 --- a/core/coreapi/test/api_test.go +++ b/core/coreapi/test/api_test.go @@ -9,7 +9,7 @@ import ( "testing" "github.com/ipfs/go-filestore" - "github.com/ipfs/go-ipfs-keystore" + keystore "github.com/ipfs/go-ipfs-keystore" "github.com/ipfs/go-ipfs/core" "github.com/ipfs/go-ipfs/core/bootstrap" "github.com/ipfs/go-ipfs/core/coreapi" @@ -19,12 +19,12 @@ import ( "github.com/ipfs/go-datastore" syncds "github.com/ipfs/go-datastore/sync" - "github.com/ipfs/go-ipfs-config" + "github.com/ipfs/go-ipfs/config" coreiface "github.com/ipfs/interface-go-ipfs-core" "github.com/ipfs/interface-go-ipfs-core/tests" "github.com/libp2p/go-libp2p-core/crypto" peer "github.com/libp2p/go-libp2p-core/peer" - "github.com/libp2p/go-libp2p/p2p/net/mock" + mocknet "github.com/libp2p/go-libp2p/p2p/net/mock" ) const testPeerID = "QmTFauExutTsy4XP6JbMFcw2Wa9645HJt2bTqL6qYDCKfe" diff --git a/core/corehttp/commands.go b/core/corehttp/commands.go index c5443f6eb3f..8de1e6be44a 100644 --- a/core/corehttp/commands.go +++ b/core/corehttp/commands.go @@ -16,7 +16,7 @@ import ( cmds "github.com/ipfs/go-ipfs-cmds" cmdsHttp "github.com/ipfs/go-ipfs-cmds/http" - config "github.com/ipfs/go-ipfs-config" + config "github.com/ipfs/go-ipfs/config" path "github.com/ipfs/go-path" ) diff --git a/core/corehttp/gateway_test.go b/core/corehttp/gateway_test.go index 8cccde0e22a..ae010421767 100644 --- a/core/corehttp/gateway_test.go +++ b/core/corehttp/gateway_test.go @@ -19,8 +19,8 @@ import ( datastore "github.com/ipfs/go-datastore" syncds "github.com/ipfs/go-datastore/sync" - config "github.com/ipfs/go-ipfs-config" files "github.com/ipfs/go-ipfs-files" + config "github.com/ipfs/go-ipfs/config" path "github.com/ipfs/go-path" iface "github.com/ipfs/interface-go-ipfs-core" nsopts "github.com/ipfs/interface-go-ipfs-core/options/namesys" diff --git a/core/corehttp/hostname.go b/core/corehttp/hostname.go index 57c2c2191a6..6c0ad5bca13 100644 --- a/core/corehttp/hostname.go +++ b/core/corehttp/hostname.go @@ -18,7 +18,7 @@ import ( mbase "github.com/multiformats/go-multibase" - config "github.com/ipfs/go-ipfs-config" + config "github.com/ipfs/go-ipfs/config" iface "github.com/ipfs/interface-go-ipfs-core" options "github.com/ipfs/interface-go-ipfs-core/options" nsopts "github.com/ipfs/interface-go-ipfs-core/options/namesys" diff --git a/core/corehttp/hostname_test.go b/core/corehttp/hostname_test.go index f7ba89a8c9b..df0f4f22971 100644 --- a/core/corehttp/hostname_test.go +++ b/core/corehttp/hostname_test.go @@ -7,8 +7,8 @@ import ( "testing" cid "github.com/ipfs/go-cid" - config "github.com/ipfs/go-ipfs-config" files "github.com/ipfs/go-ipfs-files" + config "github.com/ipfs/go-ipfs/config" coreapi "github.com/ipfs/go-ipfs/core/coreapi" path "github.com/ipfs/go-path" ) diff --git a/core/coreunix/add_test.go b/core/coreunix/add_test.go index 7dd2b0cec65..de326559c3f 100644 --- a/core/coreunix/add_test.go +++ b/core/coreunix/add_test.go @@ -21,9 +21,9 @@ import ( "github.com/ipfs/go-datastore" syncds "github.com/ipfs/go-datastore/sync" blockstore "github.com/ipfs/go-ipfs-blockstore" - config "github.com/ipfs/go-ipfs-config" files "github.com/ipfs/go-ipfs-files" pi "github.com/ipfs/go-ipfs-posinfo" + config "github.com/ipfs/go-ipfs/config" dag "github.com/ipfs/go-merkledag" coreiface "github.com/ipfs/interface-go-ipfs-core" ) diff --git a/core/mock/mock.go b/core/mock/mock.go index d0a5cd7f65c..65c028ac5e8 100644 --- a/core/mock/mock.go +++ b/core/mock/mock.go @@ -13,7 +13,7 @@ import ( "github.com/ipfs/go-datastore" syncds "github.com/ipfs/go-datastore/sync" - config "github.com/ipfs/go-ipfs-config" + config "github.com/ipfs/go-ipfs/config" "github.com/libp2p/go-libp2p" "github.com/libp2p/go-libp2p-core/host" diff --git a/core/node/bitswap.go b/core/node/bitswap.go index a2548ab3ce6..44698f92123 100644 --- a/core/node/bitswap.go +++ b/core/node/bitswap.go @@ -6,8 +6,8 @@ import ( "github.com/ipfs/go-bitswap" "github.com/ipfs/go-bitswap/network" blockstore "github.com/ipfs/go-ipfs-blockstore" - config "github.com/ipfs/go-ipfs-config" exchange "github.com/ipfs/go-ipfs-exchange-interface" + config "github.com/ipfs/go-ipfs/config" "github.com/libp2p/go-libp2p-core/host" "github.com/libp2p/go-libp2p-core/routing" "go.uber.org/fx" diff --git a/core/node/builder.go b/core/node/builder.go index 803caf51885..689f151b17a 100644 --- a/core/node/builder.go +++ b/core/node/builder.go @@ -14,7 +14,7 @@ import ( ds "github.com/ipfs/go-datastore" dsync "github.com/ipfs/go-datastore/sync" - cfg "github.com/ipfs/go-ipfs-config" + cfg "github.com/ipfs/go-ipfs/config" "github.com/libp2p/go-libp2p-core/crypto" peer "github.com/libp2p/go-libp2p-core/peer" ) diff --git a/core/node/dns.go b/core/node/dns.go index aeec23de145..2fc6327635c 100644 --- a/core/node/dns.go +++ b/core/node/dns.go @@ -6,7 +6,7 @@ import ( "strings" "time" - config "github.com/ipfs/go-ipfs-config" + config "github.com/ipfs/go-ipfs/config" doh "github.com/libp2p/go-doh-resolver" madns "github.com/multiformats/go-multiaddr-dns" diff --git a/core/node/groups.go b/core/node/groups.go index 80367156e55..26b2fae8475 100644 --- a/core/node/groups.go +++ b/core/node/groups.go @@ -7,8 +7,8 @@ import ( "time" blockstore "github.com/ipfs/go-ipfs-blockstore" - config "github.com/ipfs/go-ipfs-config" util "github.com/ipfs/go-ipfs-util" + config "github.com/ipfs/go-ipfs/config" "github.com/ipfs/go-log" "github.com/libp2p/go-libp2p-core/peer" pubsub "github.com/libp2p/go-libp2p-pubsub" diff --git a/core/node/libp2p/libp2p.go b/core/node/libp2p/libp2p.go index 309490bdc52..9d864ad467b 100644 --- a/core/node/libp2p/libp2p.go +++ b/core/node/libp2p/libp2p.go @@ -6,7 +6,7 @@ import ( "time" version "github.com/ipfs/go-ipfs" - config "github.com/ipfs/go-ipfs-config" + config "github.com/ipfs/go-ipfs/config" logging "github.com/ipfs/go-log" "github.com/libp2p/go-libp2p" diff --git a/core/node/libp2p/nat.go b/core/node/libp2p/nat.go index ce0ca345f70..28560662d2c 100644 --- a/core/node/libp2p/nat.go +++ b/core/node/libp2p/nat.go @@ -3,7 +3,7 @@ package libp2p import ( "time" - config "github.com/ipfs/go-ipfs-config" + config "github.com/ipfs/go-ipfs/config" "github.com/libp2p/go-libp2p" ) diff --git a/core/node/libp2p/relay.go b/core/node/libp2p/relay.go index 33d958d5c9d..d30adcfaed9 100644 --- a/core/node/libp2p/relay.go +++ b/core/node/libp2p/relay.go @@ -1,7 +1,7 @@ package libp2p import ( - config "github.com/ipfs/go-ipfs-config" + config "github.com/ipfs/go-ipfs/config" "github.com/libp2p/go-libp2p-core/peer" "github.com/libp2p/go-libp2p" diff --git a/core/node/libp2p/sec.go b/core/node/libp2p/sec.go index bef2efe476a..6246d2fe30d 100644 --- a/core/node/libp2p/sec.go +++ b/core/node/libp2p/sec.go @@ -1,7 +1,7 @@ package libp2p import ( - config "github.com/ipfs/go-ipfs-config" + config "github.com/ipfs/go-ipfs/config" "github.com/libp2p/go-libp2p" noise "github.com/libp2p/go-libp2p-noise" tls "github.com/libp2p/go-libp2p-tls" diff --git a/core/node/libp2p/smux.go b/core/node/libp2p/smux.go index 8ce540109ce..a405e5a3274 100644 --- a/core/node/libp2p/smux.go +++ b/core/node/libp2p/smux.go @@ -5,7 +5,7 @@ import ( "os" "strings" - config "github.com/ipfs/go-ipfs-config" + config "github.com/ipfs/go-ipfs/config" "github.com/libp2p/go-libp2p" smux "github.com/libp2p/go-libp2p-core/mux" mplex "github.com/libp2p/go-libp2p-mplex" diff --git a/core/node/libp2p/transport.go b/core/node/libp2p/transport.go index c5112e9c0b8..303a70d8061 100644 --- a/core/node/libp2p/transport.go +++ b/core/node/libp2p/transport.go @@ -3,7 +3,7 @@ package libp2p import ( "fmt" - config "github.com/ipfs/go-ipfs-config" + config "github.com/ipfs/go-ipfs/config" libp2p "github.com/libp2p/go-libp2p" metrics "github.com/libp2p/go-libp2p-core/metrics" libp2pquic "github.com/libp2p/go-libp2p-quic-transport" diff --git a/core/node/storage.go b/core/node/storage.go index 3e3e90fa174..6a647ffd7bc 100644 --- a/core/node/storage.go +++ b/core/node/storage.go @@ -3,7 +3,7 @@ package node import ( "github.com/ipfs/go-datastore" blockstore "github.com/ipfs/go-ipfs-blockstore" - config "github.com/ipfs/go-ipfs-config" + config "github.com/ipfs/go-ipfs/config" "go.uber.org/fx" "github.com/ipfs/go-filestore" diff --git a/go.mod b/go.mod index 92c15f6ccea..af332571d8c 100644 --- a/go.mod +++ b/go.mod @@ -32,7 +32,6 @@ require ( github.com/ipfs/go-ipfs-blockstore v1.1.2 github.com/ipfs/go-ipfs-chunker v0.0.5 github.com/ipfs/go-ipfs-cmds v0.6.0 - github.com/ipfs/go-ipfs-config v0.19.0 github.com/ipfs/go-ipfs-exchange-interface v0.1.0 github.com/ipfs/go-ipfs-exchange-offline v0.1.1 github.com/ipfs/go-ipfs-files v0.0.9 diff --git a/go.sum b/go.sum index e791d5ea3cf..49abc3cac6d 100644 --- a/go.sum +++ b/go.sum @@ -476,8 +476,6 @@ github.com/ipfs/go-ipfs-chunker v0.0.5 h1:ojCf7HV/m+uS2vhUGWcogIIxiO5ubl5O57Q7Na github.com/ipfs/go-ipfs-chunker v0.0.5/go.mod h1:jhgdF8vxRHycr00k13FM8Y0E+6BoalYeobXmUyTreP8= github.com/ipfs/go-ipfs-cmds v0.6.0 h1:yAxdowQZzoFKjcLI08sXVNnqVj3jnABbf9smrPQmBsw= github.com/ipfs/go-ipfs-cmds v0.6.0/go.mod h1:ZgYiWVnCk43ChwoH8hAmI1IRbuVtq3GSTHwtRB/Kqhk= -github.com/ipfs/go-ipfs-config v0.19.0 h1:OuKIL+BkOZgJ+hb4Wg/9ynCtE/BaZBWcGy8hgdMepAo= -github.com/ipfs/go-ipfs-config v0.19.0/go.mod h1:wz2lKzOjgJeYJa6zx8W9VT7mz+iSd0laBMqS/9wmX6A= github.com/ipfs/go-ipfs-delay v0.0.0-20181109222059-70721b86a9a8/go.mod h1:8SP1YXK1M1kXuc4KJZINY3TQQ03J2rwBG9QfXmbRPrw= github.com/ipfs/go-ipfs-delay v0.0.1 h1:r/UXYyRcddO6thwOnhiznIAiSvxMECGgtv35Xs1IeRQ= github.com/ipfs/go-ipfs-delay v0.0.1/go.mod h1:8SP1YXK1M1kXuc4KJZINY3TQQ03J2rwBG9QfXmbRPrw= diff --git a/package-list.json b/package-list.json index 934e5e34515..7dfc5648cf0 100644 --- a/package-list.json +++ b/package-list.json @@ -42,7 +42,6 @@ ["ipfs/go-ipns", "go-ipns", "IPNS datastructures and validation logic"], "Repo", - ["ipfs/go-ipfs-config", "go-ipfs-config", "go-ipfs config file definitions"], ["ipfs/go-fs-lock", "go-fs-lock", "lockfile management functions"], ["ipfs/fs-repo-migrations", "fs-repo-migrations", "repo migrations"], diff --git a/plugin/loader/loader.go b/plugin/loader/loader.go index 167e1b3090b..6bf13a370c0 100644 --- a/plugin/loader/loader.go +++ b/plugin/loader/loader.go @@ -8,8 +8,8 @@ import ( "runtime" "strings" - config "github.com/ipfs/go-ipfs-config" - cserialize "github.com/ipfs/go-ipfs-config/serialize" + config "github.com/ipfs/go-ipfs/config" + cserialize "github.com/ipfs/go-ipfs/config/serialize" "github.com/ipld/go-ipld-prime/multicodec" "github.com/ipfs/go-ipfs/core" diff --git a/repo/fsrepo/config_test.go b/repo/fsrepo/config_test.go index f7c19c30765..0ffdababe27 100644 --- a/repo/fsrepo/config_test.go +++ b/repo/fsrepo/config_test.go @@ -10,7 +10,7 @@ import ( "github.com/ipfs/go-ipfs/plugin/loader" "github.com/ipfs/go-ipfs/repo/fsrepo" - "github.com/ipfs/go-ipfs-config" + "github.com/ipfs/go-ipfs/config" ) // note: to test sorting of the mountpoints in the disk spec they are diff --git a/repo/fsrepo/fsrepo.go b/repo/fsrepo/fsrepo.go index 2aa4a5e46c8..176ac46189b 100644 --- a/repo/fsrepo/fsrepo.go +++ b/repo/fsrepo/fsrepo.go @@ -20,9 +20,9 @@ import ( ds "github.com/ipfs/go-datastore" measure "github.com/ipfs/go-ds-measure" lockfile "github.com/ipfs/go-fs-lock" - config "github.com/ipfs/go-ipfs-config" - serialize "github.com/ipfs/go-ipfs-config/serialize" util "github.com/ipfs/go-ipfs-util" + config "github.com/ipfs/go-ipfs/config" + serialize "github.com/ipfs/go-ipfs/config/serialize" "github.com/ipfs/go-ipfs/repo/fsrepo/migrations" logging "github.com/ipfs/go-log" homedir "github.com/mitchellh/go-homedir" diff --git a/repo/fsrepo/fsrepo_test.go b/repo/fsrepo/fsrepo_test.go index cd2d66618a5..cf9aeabec0e 100644 --- a/repo/fsrepo/fsrepo_test.go +++ b/repo/fsrepo/fsrepo_test.go @@ -11,7 +11,7 @@ import ( "github.com/ipfs/go-ipfs/thirdparty/assert" datastore "github.com/ipfs/go-datastore" - config "github.com/ipfs/go-ipfs-config" + config "github.com/ipfs/go-ipfs/config" ) // swap arg order diff --git a/repo/fsrepo/migrations/ipfsfetcher/ipfsfetcher.go b/repo/fsrepo/migrations/ipfsfetcher/ipfsfetcher.go index 11203ed5a05..21a6038a7eb 100644 --- a/repo/fsrepo/migrations/ipfsfetcher/ipfsfetcher.go +++ b/repo/fsrepo/migrations/ipfsfetcher/ipfsfetcher.go @@ -12,8 +12,8 @@ import ( "strings" "sync" - "github.com/ipfs/go-ipfs-config" files "github.com/ipfs/go-ipfs-files" + "github.com/ipfs/go-ipfs/config" "github.com/ipfs/go-ipfs/core" "github.com/ipfs/go-ipfs/core/coreapi" "github.com/ipfs/go-ipfs/core/node/libp2p" diff --git a/repo/fsrepo/migrations/migrations.go b/repo/fsrepo/migrations/migrations.go index 5eac91b2932..726870ea004 100644 --- a/repo/fsrepo/migrations/migrations.go +++ b/repo/fsrepo/migrations/migrations.go @@ -15,7 +15,7 @@ import ( "strings" "sync" - config "github.com/ipfs/go-ipfs-config" + config "github.com/ipfs/go-ipfs/config" ) const ( diff --git a/repo/fsrepo/migrations/migrations_test.go b/repo/fsrepo/migrations/migrations_test.go index 0e52b3a65ed..2472d4706aa 100644 --- a/repo/fsrepo/migrations/migrations_test.go +++ b/repo/fsrepo/migrations/migrations_test.go @@ -9,7 +9,7 @@ import ( "strings" "testing" - config "github.com/ipfs/go-ipfs-config" + config "github.com/ipfs/go-ipfs/config" ) func TestFindMigrations(t *testing.T) { diff --git a/repo/fsrepo/misc.go b/repo/fsrepo/misc.go index 7f0c01640a2..71b640331d4 100644 --- a/repo/fsrepo/misc.go +++ b/repo/fsrepo/misc.go @@ -3,7 +3,7 @@ package fsrepo import ( "os" - config "github.com/ipfs/go-ipfs-config" + config "github.com/ipfs/go-ipfs/config" homedir "github.com/mitchellh/go-homedir" ) diff --git a/repo/mock.go b/repo/mock.go index 0576498716a..15313ab373c 100644 --- a/repo/mock.go +++ b/repo/mock.go @@ -7,7 +7,7 @@ import ( filestore "github.com/ipfs/go-filestore" keystore "github.com/ipfs/go-ipfs-keystore" - config "github.com/ipfs/go-ipfs-config" + config "github.com/ipfs/go-ipfs/config" ma "github.com/multiformats/go-multiaddr" ) diff --git a/repo/repo.go b/repo/repo.go index 744bfdf5d57..00735eb94ee 100644 --- a/repo/repo.go +++ b/repo/repo.go @@ -9,7 +9,7 @@ import ( keystore "github.com/ipfs/go-ipfs-keystore" ds "github.com/ipfs/go-datastore" - config "github.com/ipfs/go-ipfs-config" + config "github.com/ipfs/go-ipfs/config" ma "github.com/multiformats/go-multiaddr" ) diff --git a/test/bench/bench_cli_ipfs_add/main.go b/test/bench/bench_cli_ipfs_add/main.go index 727a87aea2f..b11b5f83c7d 100644 --- a/test/bench/bench_cli_ipfs_add/main.go +++ b/test/bench/bench_cli_ipfs_add/main.go @@ -12,7 +12,7 @@ import ( "github.com/ipfs/go-ipfs/thirdparty/unit" - config "github.com/ipfs/go-ipfs-config" + config "github.com/ipfs/go-ipfs/config" random "github.com/jbenet/go-random" ) diff --git a/test/bench/offline_add/main.go b/test/bench/offline_add/main.go index 94e8cac23ba..5d3f27fed1a 100644 --- a/test/bench/offline_add/main.go +++ b/test/bench/offline_add/main.go @@ -11,7 +11,7 @@ import ( "github.com/ipfs/go-ipfs/thirdparty/unit" - config "github.com/ipfs/go-ipfs-config" + config "github.com/ipfs/go-ipfs/config" random "github.com/jbenet/go-random" ) From 6379013e41ffbd4e3e1b9ee0e4d7e364a3073a06 Mon Sep 17 00:00:00 2001 From: Laurent Senta Date: Thu, 3 Mar 2022 14:46:31 +0100 Subject: [PATCH 306/414] ci: tweak example testing to pass with internal config package --- .circleci/main.yml | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/.circleci/main.yml b/.circleci/main.yml index 78ff3d707db..9838b0f4de5 100644 --- a/.circleci/main.yml +++ b/.circleci/main.yml @@ -120,11 +120,18 @@ jobs: # make sure the examples run against the current version of go-ipfs go mod edit -replace github.com/ipfs/go-ipfs=./../../.. go mod tidy + + # use the internal config package when we test the current version of go-ipfs + sed -i.bak 's;"github.com/ipfs/go-ipfs-config";"github.com/ipfs/go-ipfs/config";' ./main.go + go test -v ./... # restore the go.mod and go.sum files to their original state mv go.mod.bak go.mod mv go.sum.bak go.sum + + # restore the main.go to its original state + mv main.go.bak main.go working_directory: ~/ipfs/go-ipfs/docs/examples/go-ipfs-as-a-library - run: From a09b6c205eea1ecaaae1e9ba0b45e4a091308694 Mon Sep 17 00:00:00 2001 From: Kyle Huntsman <3432646+kylehuntsman@users.noreply.github.com> Date: Mon, 7 Mar 2022 17:00:49 -0700 Subject: [PATCH 307/414] fix(repo/common): improve MapGetKV not found error --- repo/common/common.go | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/repo/common/common.go b/repo/common/common.go index 1f1f0cd570a..e9c56e65ee3 100644 --- a/repo/common/common.go +++ b/repo/common/common.go @@ -21,7 +21,13 @@ func MapGetKV(v map[string]interface{}, key string) (interface{}, error) { cursor, ok = mcursor[part] if !ok { - return nil, fmt.Errorf("%s key has no attributes", sofar) + // Construct the current path traversed to print a nice error message + var path string + if len(sofar) > 0 { + path += sofar + "." + } + path += part + return nil, fmt.Errorf("%s not found", path) } } return cursor, nil From be3dbc2bd293e200e8b0f85cbdb73cc1b1bcb612 Mon Sep 17 00:00:00 2001 From: godcong Date: Wed, 9 Mar 2022 23:08:24 +0800 Subject: [PATCH 308/414] fix(discovery): fix daemon not starting due to mdns startup failure (#8704) --- core/node/libp2p/discovery.go | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/core/node/libp2p/discovery.go b/core/node/libp2p/discovery.go index 64860ce5c66..dbc2b0beaad 100644 --- a/core/node/libp2p/discovery.go +++ b/core/node/libp2p/discovery.go @@ -42,7 +42,8 @@ func SetupDiscovery(useMdns bool, mdnsInterval int) func(helpers.MetricsCtx, fx. if useMdns { service := mdns.NewMdnsService(host, mdns.ServiceName, handler) if err := service.Start(); err != nil { - return err + log.Error("error starting mdns service: ", err) + return nil } if mdnsInterval == 0 { From 816a128aaf963d72c4930852ce32b9a4e31924a1 Mon Sep 17 00:00:00 2001 From: Gus Eggert Date: Wed, 9 Mar 2022 10:31:07 -0500 Subject: [PATCH 309/414] fix: listen on loopback for API and gateway ports in docker-compose.yaml (#8773) --- docker-compose.yaml | 13 ++++++++++--- 1 file changed, 10 insertions(+), 3 deletions(-) diff --git a/docker-compose.yaml b/docker-compose.yaml index eaf947cb395..447a1474b73 100644 --- a/docker-compose.yaml +++ b/docker-compose.yaml @@ -10,11 +10,18 @@ services: environment: - IPFS_PATH=/data/ipfs ports: + # Swarm listens on all interfaces, so is remotely reachable. - 4001:4001/tcp - 4001:4001/udp - - 5001:5001 - - 8080:8080 - - 8081:8081 + + # The following ports only listen on the loopback interface, so are not remotely reachable by default. + # If you want to override these or add more ports, see https://docs.docker.com/compose/extends/ . + + # API port, which includes admin operations, so you probably don't want this remotely accessible. + - 127.0.0.1:5001:5001 + + # HTTP Gateway + - 127.0.0.1:8080:8080 volumes: ipfs_path: ipfs_fuse: From eafa1c73455d91850da61f09068af4535cf499e6 Mon Sep 17 00:00:00 2001 From: Adin Schmahmann Date: Thu, 10 Mar 2022 10:42:33 +0100 Subject: [PATCH 310/414] docs: note the default reprovider strategy as all (#8603) --- docs/config.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/config.md b/docs/config.md index c0b622685bb..2c935190923 100644 --- a/docs/config.md +++ b/docs/config.md @@ -1265,7 +1265,7 @@ Tells reprovider what should be announced. Valid strategies are: Default: all -Type: `string` (or unset for the default) +Type: `string` (or unset for the default, which is "all") ## `Routing` From 199659ab77235bbe199392849b92309df13115ec Mon Sep 17 00:00:00 2001 From: Lucas Molas Date: Fri, 11 Mar 2022 16:25:46 -0300 Subject: [PATCH 311/414] fix(cmds): option for progress bar in cat/get (#8686) * fix(cmds): option for progress bar in cat/get * defer bar.Finish() --- core/commands/cat.go | 14 ++++++++++++-- core/commands/get.go | 29 ++++++++++++++++++++--------- 2 files changed, 32 insertions(+), 11 deletions(-) diff --git a/core/commands/cat.go b/core/commands/cat.go index 8aff890284a..98a0e41bd2c 100644 --- a/core/commands/cat.go +++ b/core/commands/cat.go @@ -8,6 +8,7 @@ import ( "github.com/ipfs/go-ipfs/core/commands/cmdenv" + "github.com/cheggaaa/pb" "github.com/ipfs/go-ipfs-cmds" "github.com/ipfs/go-ipfs-files" "github.com/ipfs/interface-go-ipfs-core" @@ -32,6 +33,7 @@ var CatCmd = &cmds.Command{ Options: []cmds.Option{ cmds.Int64Option(offsetOptionName, "o", "Byte offset to begin reading from."), cmds.Int64Option(lengthOptionName, "l", "Maximum number of bytes to read."), + cmds.BoolOption(progressOptionName, "p", "Stream progress data.").WithDefault(true), }, Run: func(req *cmds.Request, res cmds.ResponseEmitter, env cmds.Environment) error { api, err := cmdenv.GetApi(env, req) @@ -96,8 +98,16 @@ var CatCmd = &cmds.Command{ switch val := v.(type) { case io.Reader: - bar, reader := progressBarForReader(os.Stderr, val, int64(res.Length())) - bar.Start() + reader := val + + req := res.Request() + progress, _ := req.Options[progressOptionName].(bool) + if progress { + var bar *pb.ProgressBar + bar, reader = progressBarForReader(os.Stderr, val, int64(res.Length())) + bar.Start() + defer bar.Finish() + } err = re.Emit(reader) if err != nil { diff --git a/core/commands/get.go b/core/commands/get.go index 7fb53467f5d..b7826cf30fb 100644 --- a/core/commands/get.go +++ b/core/commands/get.go @@ -54,6 +54,7 @@ may also specify the level of compression by specifying '-l=<1-9>'. cmds.BoolOption(archiveOptionName, "a", "Output a TAR archive."), cmds.BoolOption(compressOptionName, "C", "Compress the output with GZIP compression."), cmds.IntOption(compressionLevelOptionName, "l", "The level of compression (1-9)."), + cmds.BoolOption(progressOptionName, "p", "Stream progress data.").WithDefault(true), }, PreRun: func(req *cmds.Request, env cmds.Environment) error { _, err := getCompressOptions(req) @@ -114,6 +115,7 @@ may also specify the level of compression by specifying '-l=<1-9>'. } archive, _ := req.Options[archiveOptionName].(bool) + progress, _ := req.Options[progressOptionName].(bool) gw := getWriter{ Out: os.Stdout, @@ -121,6 +123,7 @@ may also specify the level of compression by specifying '-l=<1-9>'. Archive: archive, Compression: cmplvl, Size: int64(res.Length()), + Progress: progress, } return gw.Write(outReader, outPath) @@ -181,6 +184,7 @@ type getWriter struct { Archive bool Compression int Size int64 + Progress bool } func (gw *getWriter) Write(r io.Reader, fpath string) error { @@ -213,22 +217,29 @@ func (gw *getWriter) writeArchive(r io.Reader, fpath string) error { defer file.Close() fmt.Fprintf(gw.Out, "Saving archive to %s\n", fpath) - bar, barR := progressBarForReader(gw.Err, r, gw.Size) - bar.Start() - defer bar.Finish() + if gw.Progress { + var bar *pb.ProgressBar + bar, r = progressBarForReader(gw.Err, r, gw.Size) + bar.Start() + defer bar.Finish() + } - _, err = io.Copy(file, barR) + _, err = io.Copy(file, r) return err } func (gw *getWriter) writeExtracted(r io.Reader, fpath string) error { fmt.Fprintf(gw.Out, "Saving file(s) to %s\n", fpath) - bar := makeProgressBar(gw.Err, gw.Size) - bar.Start() - defer bar.Finish() - defer bar.Set64(gw.Size) + var progressCb func(int64) int64 + if gw.Progress { + bar := makeProgressBar(gw.Err, gw.Size) + bar.Start() + defer bar.Finish() + defer bar.Set64(gw.Size) + progressCb = bar.Add64 + } - extractor := &tar.Extractor{Path: fpath, Progress: bar.Add64} + extractor := &tar.Extractor{Path: fpath, Progress: progressCb} return extractor.Extract(r) } From 0487f03eaea8f0207e2dec65809bc678813a1ec3 Mon Sep 17 00:00:00 2001 From: Gus Eggert Date: Fri, 11 Mar 2022 14:32:59 -0500 Subject: [PATCH 312/414] feat: add endpoint for enabling block profiling (#8469) --- cmd/ipfs/daemon.go | 1 + core/corehttp/mutex_profile.go | 35 ++++++++++++++++++++++++++++++++++ test/sharness/t0110-gateway.sh | 13 +++++++++++++ 3 files changed, 49 insertions(+) diff --git a/cmd/ipfs/daemon.go b/cmd/ipfs/daemon.go index a2c65b5b99e..c22dc805415 100644 --- a/cmd/ipfs/daemon.go +++ b/cmd/ipfs/daemon.go @@ -661,6 +661,7 @@ func serveHTTPApi(req *cmds.Request, cctx *oldcmds.Context) (<-chan error, error defaultMux("/debug/vars"), defaultMux("/debug/pprof/"), corehttp.MutexFractionOption("/debug/pprof-mutex/"), + corehttp.BlockProfileRateOption("/debug/pprof-block/"), corehttp.MetricsScrapingOption("/debug/metrics/prometheus"), corehttp.LogOption(), } diff --git a/core/corehttp/mutex_profile.go b/core/corehttp/mutex_profile.go index fbb23340d00..a8265326c5e 100644 --- a/core/corehttp/mutex_profile.go +++ b/core/corehttp/mutex_profile.go @@ -41,3 +41,38 @@ func MutexFractionOption(path string) ServeOption { return mux, nil } } + +// BlockProfileRateOption allows to set runtime.SetBlockProfileRate via HTTP +// using POST request with parameter 'rate'. +// The profiler tries to sample 1 event every nanoseconds. +// If rate == 1, then the profiler samples every blocking event. +// To disable, set rate = 0. +func BlockProfileRateOption(path string) ServeOption { + return func(_ *core.IpfsNode, _ net.Listener, mux *http.ServeMux) (*http.ServeMux, error) { + mux.HandleFunc(path, func(w http.ResponseWriter, r *http.Request) { + if r.Method != http.MethodPost { + http.Error(w, "only POST allowed", http.StatusMethodNotAllowed) + return + } + if err := r.ParseForm(); err != nil { + http.Error(w, err.Error(), http.StatusBadRequest) + return + } + + rateStr := r.Form.Get("rate") + if len(rateStr) == 0 { + http.Error(w, "parameter 'rate' must be set", http.StatusBadRequest) + return + } + + rate, err := strconv.Atoi(rateStr) + if err != nil { + http.Error(w, err.Error(), http.StatusBadRequest) + return + } + log.Infof("Setting BlockProfileRate to %d", rate) + runtime.SetBlockProfileRate(rate) + }) + return mux, nil + } +} diff --git a/test/sharness/t0110-gateway.sh b/test/sharness/t0110-gateway.sh index 276c90b2228..e1ee6496244 100755 --- a/test/sharness/t0110-gateway.sh +++ b/test/sharness/t0110-gateway.sh @@ -163,6 +163,19 @@ test_expect_success "test failure conditions of mutex pprof endpoint" ' test_must_fail curl -f -X GET "http://127.0.0.1:$apiport/debug/pprof-mutex/?fraction=-1" ' +curl_pprofblock() { + curl -f -X POST "http://127.0.0.1:$apiport/debug/pprof-block/?rate=$1" +} + +test_expect_success "set blocking profiler rate for pprof (0 so it doesn't enable)" ' + curl_pprofblock 0 +' + +test_expect_success "test failure conditions of mutex block endpoint" ' + test_must_fail curl_pprofblock && + test_must_fail curl_pprofblock that_is_string && + test_must_fail curl -f -X GET "http://127.0.0.1:$apiport/debug/pprof-block/?rate=0" +' test_expect_success "setup index hash" ' mkdir index && From 04e7e9502e09959171c31bb880255ddda17ed848 Mon Sep 17 00:00:00 2001 From: Lucas Molas Date: Fri, 11 Mar 2022 19:23:11 -0300 Subject: [PATCH 313/414] feat(cmds): extend block size check for dag|block put (#8751) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * feat(cmds): extend block size check for dag|block put * feat(cmds): block size check for dag import * style: dag-pb → UnixFS, 1MB → 1MiB Co-authored-by: Marcin Rataj --- core/commands/block.go | 6 +++ core/commands/cmdutils/utils.go | 51 ++++++++++++++++++++ core/commands/dag/dag.go | 3 ++ core/commands/dag/import.go | 4 ++ core/commands/dag/put.go | 5 ++ core/commands/get.go | 2 +- core/commands/object/patch.go | 43 +++-------------- test/sharness/t0050-block.sh | 14 ++++++ test/sharness/t0051-object.sh | 4 +- test/sharness/t0053-dag.sh | 14 ++++++ test/sharness/t0054-dag-car-import-export.sh | 13 +++++ 11 files changed, 120 insertions(+), 39 deletions(-) create mode 100644 core/commands/cmdutils/utils.go diff --git a/core/commands/block.go b/core/commands/block.go index a06bfe0683e..4cfe1fc6ef9 100644 --- a/core/commands/block.go +++ b/core/commands/block.go @@ -10,6 +10,7 @@ import ( util "github.com/ipfs/go-ipfs/blocks/blockstoreutil" cmdenv "github.com/ipfs/go-ipfs/core/commands/cmdenv" + "github.com/ipfs/go-ipfs/core/commands/cmdutils" cmds "github.com/ipfs/go-ipfs-cmds" options "github.com/ipfs/interface-go-ipfs-core/options" @@ -138,6 +139,7 @@ other than 'sha2-256' or format to anything other than 'v0' will result in CIDv1 cmds.StringOption(mhtypeOptionName, "multihash hash function").WithDefault("sha2-256"), cmds.IntOption(mhlenOptionName, "multihash hash length").WithDefault(-1), cmds.BoolOption(pinOptionName, "pin added blocks recursively").WithDefault(false), + cmdutils.AllowBigBlockOption, }, Run: func(req *cmds.Request, res cmds.ResponseEmitter, env cmds.Environment) error { api, err := cmdenv.GetApi(env, req) @@ -182,6 +184,10 @@ other than 'sha2-256' or format to anything other than 'v0' will result in CIDv1 return err } + if err := cmdutils.CheckBlockSize(req, uint64(p.Size())); err != nil { + return err + } + err = res.Emit(&BlockStat{ Key: p.Path().Cid().String(), Size: p.Size(), diff --git a/core/commands/cmdutils/utils.go b/core/commands/cmdutils/utils.go new file mode 100644 index 00000000000..ebbbca64e46 --- /dev/null +++ b/core/commands/cmdutils/utils.go @@ -0,0 +1,51 @@ +package cmdutils + +import ( + "fmt" + + cmds "github.com/ipfs/go-ipfs-cmds" + + "github.com/ipfs/go-cid" + coreiface "github.com/ipfs/interface-go-ipfs-core" +) + +const ( + AllowBigBlockOptionName = "allow-big-block" + SoftBlockLimit = 1024 * 1024 // https://github.com/ipfs/go-ipfs/issues/7421#issuecomment-910833499 +) + +var AllowBigBlockOption cmds.Option + +func init() { + AllowBigBlockOption = cmds.BoolOption(AllowBigBlockOptionName, "Disable block size check and allow creation of blocks bigger than 1MiB. WARNING: such blocks won't be transferable over the standard bitswap.").WithDefault(false) +} + +func CheckCIDSize(req *cmds.Request, c cid.Cid, dagAPI coreiface.APIDagService) error { + n, err := dagAPI.Get(req.Context, c) + if err != nil { + return fmt.Errorf("CheckCIDSize: getting dag: %w", err) + } + + nodeSize, err := n.Size() + if err != nil { + return fmt.Errorf("CheckCIDSize: getting node size: %w", err) + } + + return CheckBlockSize(req, nodeSize) +} + +func CheckBlockSize(req *cmds.Request, size uint64) error { + allowAnyBlockSize, _ := req.Options[AllowBigBlockOptionName].(bool) + if allowAnyBlockSize { + return nil + } + + // We do not allow producing blocks bigger than 1 MiB to avoid errors + // when transmitting them over BitSwap. The 1 MiB constant is an + // unenforced and undeclared rule of thumb hard-coded here. + if size > SoftBlockLimit { + return fmt.Errorf("produced block is over 1MiB: big blocks can't be exchanged with other peers. consider using UnixFS for automatic chunking of bigger files, or pass --allow-big-block to override") + } + return nil + +} diff --git a/core/commands/dag/dag.go b/core/commands/dag/dag.go index cbaf7f93fe1..6d2e480b284 100644 --- a/core/commands/dag/dag.go +++ b/core/commands/dag/dag.go @@ -5,6 +5,7 @@ import ( "io" "github.com/ipfs/go-ipfs/core/commands/cmdenv" + "github.com/ipfs/go-ipfs/core/commands/cmdutils" cid "github.com/ipfs/go-cid" cidenc "github.com/ipfs/go-cidutil/cidenc" @@ -88,6 +89,7 @@ into an object of the specified format. cmds.StringOption("input-codec", "Codec that the input object is encoded in").WithDefault("dag-json"), cmds.BoolOption("pin", "Pin this object when adding."), cmds.StringOption("hash", "Hash function to use").WithDefault("sha2-256"), + cmdutils.AllowBigBlockOption, }, Run: dagPut, Type: OutputObject{}, @@ -205,6 +207,7 @@ Maximum supported CAR version: 1 cmds.BoolOption(pinRootsOptionName, "Pin optional roots listed in the .car headers after importing.").WithDefault(true), cmds.BoolOption(silentOptionName, "No output."), cmds.BoolOption(statsOptionName, "Output stats."), + cmdutils.AllowBigBlockOption, }, Type: CarImportOutput{}, Run: dagImport, diff --git a/core/commands/dag/import.go b/core/commands/dag/import.go index e206652ce36..476b986c825 100644 --- a/core/commands/dag/import.go +++ b/core/commands/dag/import.go @@ -8,6 +8,7 @@ import ( cid "github.com/ipfs/go-cid" files "github.com/ipfs/go-ipfs-files" "github.com/ipfs/go-ipfs/core/commands/cmdenv" + "github.com/ipfs/go-ipfs/core/commands/cmdutils" ipld "github.com/ipfs/go-ipld-format" iface "github.com/ipfs/interface-go-ipfs-core" "github.com/ipfs/interface-go-ipfs-core/options" @@ -180,6 +181,9 @@ func importWorker(req *cmds.Request, re cmds.ResponseEmitter, api iface.CoreAPI, } else if block == nil { break } + if err := cmdutils.CheckBlockSize(req, uint64(len(block.RawData()))); err != nil { + return err + } // the double-decode is suboptimal, but we need it for batching nd, err := ipld.Decode(block) diff --git a/core/commands/dag/put.go b/core/commands/dag/put.go index 0bb7fd2ae50..e741f11124d 100644 --- a/core/commands/dag/put.go +++ b/core/commands/dag/put.go @@ -7,6 +7,7 @@ import ( blocks "github.com/ipfs/go-block-format" "github.com/ipfs/go-cid" "github.com/ipfs/go-ipfs/core/commands/cmdenv" + "github.com/ipfs/go-ipfs/core/commands/cmdutils" ipldlegacy "github.com/ipfs/go-ipld-legacy" "github.com/ipld/go-ipld-prime/multicodec" basicnode "github.com/ipld/go-ipld-prime/node/basic" @@ -102,6 +103,10 @@ func dagPut(req *cmds.Request, res cmds.ResponseEmitter, env cmds.Environment) e Node: n, } + if err := cmdutils.CheckBlockSize(req, uint64(bd.Len())); err != nil { + return err + } + if err := b.Add(req.Context, &ln); err != nil { return err } diff --git a/core/commands/get.go b/core/commands/get.go index b7826cf30fb..65ab46aa57c 100644 --- a/core/commands/get.go +++ b/core/commands/get.go @@ -257,7 +257,7 @@ func getCompressOptions(req *cmds.Request) (int, error) { return cmplvl, nil } -// DefaultBufSize is the buffer size for gets. for now, 1MB, which is ~4 blocks. +// DefaultBufSize is the buffer size for gets. for now, 1MiB, which is ~4 blocks. // TODO: does this need to be configurable? var DefaultBufSize = 1048576 diff --git a/core/commands/object/patch.go b/core/commands/object/patch.go index 78f92703254..ab76ebb23f4 100644 --- a/core/commands/object/patch.go +++ b/core/commands/object/patch.go @@ -4,20 +4,14 @@ import ( "fmt" "io" - "github.com/ipfs/go-cid" cmds "github.com/ipfs/go-ipfs-cmds" "github.com/ipfs/go-ipfs/core/commands/cmdenv" - coreiface "github.com/ipfs/interface-go-ipfs-core" + "github.com/ipfs/go-ipfs/core/commands/cmdutils" "github.com/ipfs/interface-go-ipfs-core/options" "github.com/ipfs/interface-go-ipfs-core/path" ) -const ( - softBlockLimit = 1024 * 1024 // https://github.com/ipfs/go-ipfs/issues/7421#issuecomment-910833499 - allowBigBlock = "allow-big-block" -) - var ObjectPatchCmd = &cmds.Command{ Helptext: cmds.HelpText{ Tagline: "Deprecated way to create a new merkledag object based on an existing one. Use MFS with 'files cp|rm' instead.", @@ -49,7 +43,7 @@ For modern use cases, use MFS with 'files' commands: 'ipfs files --help'. "set-data": patchSetDataCmd, }, Options: []cmds.Option{ - cmds.BoolOption(allowBigBlock, "Disable block size check and allow creation of blocks bigger than 1MB. WARNING: such blocks won't be transferable over the standard bitswap.").WithDefault(false), + cmdutils.AllowBigBlockOption, }, } @@ -64,7 +58,7 @@ Example: $ echo "hello" | ipfs object patch $HASH append-data NOTE: This does not append data to a file - it modifies the actual raw -data within a dag-pb object. Blocks have a max size of 1MB and objects larger than +data within a dag-pb object. Blocks have a max size of 1MiB and objects larger than the limit will not be respected by the network. DEPRECATED and provided for legacy reasons. Use 'ipfs add' or 'ipfs files' instead. @@ -92,7 +86,7 @@ DEPRECATED and provided for legacy reasons. Use 'ipfs add' or 'ipfs files' inste return err } - if err := checkBlockSize(req, p.Cid(), api.Dag()); err != nil { + if err := cmdutils.CheckCIDSize(req, p.Cid(), api.Dag()); err != nil { return err } @@ -142,7 +136,7 @@ DEPRECATED and provided for legacy reasons. Use 'files cp' and 'dag put' instead return err } - if err := checkBlockSize(req, p.Cid(), api.Dag()); err != nil { + if err := cmdutils.CheckCIDSize(req, p.Cid(), api.Dag()); err != nil { return err } @@ -184,7 +178,7 @@ DEPRECATED and provided for legacy reasons. Use 'files rm' instead. return err } - if err := checkBlockSize(req, p.Cid(), api.Dag()); err != nil { + if err := cmdutils.CheckCIDSize(req, p.Cid(), api.Dag()); err != nil { return err } @@ -254,7 +248,7 @@ Use MFS and 'files' commands instead: return err } - if err := checkBlockSize(req, p.Cid(), api.Dag()); err != nil { + if err := cmdutils.CheckCIDSize(req, p.Cid(), api.Dag()); err != nil { return err } @@ -268,26 +262,3 @@ Use MFS and 'files' commands instead: }), }, } - -func checkBlockSize(req *cmds.Request, c cid.Cid, dagAPI coreiface.APIDagService) error { - allowAnyBlockSize, _ := req.Options[allowBigBlock].(bool) - if allowAnyBlockSize { - return nil - } - - // We do not allow producing blocks bigger than 1 MiB to avoid errors - // when transmitting them over BitSwap. The 1 MiB constant is an - // unenforced and undeclared rule of thumb hard-coded here. - modifiedNode, err := dagAPI.Get(req.Context, c) - if err != nil { - return err - } - modifiedNodeSize, err := modifiedNode.Size() - if err != nil { - return err - } - if modifiedNodeSize > softBlockLimit { - return fmt.Errorf("produced block is over 1MB, object API is deprecated and does not support HAMT-sharding: to create big directories, please use the files API (MFS)") - } - return nil -} diff --git a/test/sharness/t0050-block.sh b/test/sharness/t0050-block.sh index 70639f623e9..9f0a533dbb7 100755 --- a/test/sharness/t0050-block.sh +++ b/test/sharness/t0050-block.sh @@ -248,4 +248,18 @@ test_expect_success "put with sha3 and cidv0 fails" ' echo "foooo" | test_must_fail ipfs block put --mhtype=sha3 --mhlen=20 --format=v0 ' +test_expect_success "'ipfs block put' check block size" ' + dd if=/dev/zero bs=2MB count=1 > 2-MB-file && + test_expect_code 1 ipfs block put 2-MB-file >block_put_out 2>&1 + ' + + test_expect_success "ipfs block put output has the correct error" ' + grep "produced block is over 1MiB" block_put_out + ' + + test_expect_success "ipfs block put --allow-big-block=true works" ' + test_expect_code 0 ipfs block put 2-MB-file --allow-big-block=true && + rm 2-MB-file + ' + test_done diff --git a/test/sharness/t0051-object.sh b/test/sharness/t0051-object.sh index 875548411b4..316c220abd5 100755 --- a/test/sharness/t0051-object.sh +++ b/test/sharness/t0051-object.sh @@ -229,12 +229,12 @@ test_object_cmd() { do DIR=$(ipfs object patch "$DIR" add-link "$DIR.jpg" "$DIR") done - # Fail when new block goes over the BS limit of 1MB, but allow manual override + # Fail when new block goes over the BS limit of 1MiB, but allow manual override test_expect_code 1 ipfs object patch "$DIR" add-link "$DIR.jpg" "$DIR" >patch_out 2>&1 ' test_expect_success "ipfs object patch add-link output has the correct error" ' - grep "produced block is over 1MB, object API is deprecated and does not support HAMT-sharding: to create big directories, please use the files API (MFS)" patch_out + grep "produced block is over 1MiB" patch_out ' test_expect_success "ipfs object patch --allow-big-block=true add-link works" ' diff --git a/test/sharness/t0053-dag.sh b/test/sharness/t0053-dag.sh index c46dcc8c19a..7514476be6e 100755 --- a/test/sharness/t0053-dag.sh +++ b/test/sharness/t0053-dag.sh @@ -44,6 +44,20 @@ test_dag_cmd() { test $EXPHASH = $IPLDHASH ' +test_expect_success "'ipfs dag put' check block size" ' + dd if=/dev/zero bs=2MB count=1 > 2-MB-file && + test_expect_code 1 ipfs dag put --input-codec=raw --store-codec=raw 2-MB-file >dag_put_out 2>&1 + ' + + test_expect_success "ipfs dag put output has the correct error" ' + grep "produced block is over 1MiB" dag_put_out + ' + + test_expect_success "ipfs dag put --allow-big-block=true works" ' + test_expect_code 0 ipfs dag put --input-codec=raw --store-codec=raw 2-MB-file --allow-big-block=true && + rm 2-MB-file + ' + test_expect_success "can add an ipld object using dag-json to dag-json" ' IPLDHASH=$(cat ipld_object | ipfs dag put --input-codec dag-json --store-codec dag-json) ' diff --git a/test/sharness/t0054-dag-car-import-export.sh b/test/sharness/t0054-dag-car-import-export.sh index 311833748f0..13c2100279a 100755 --- a/test/sharness/t0054-dag-car-import-export.sh +++ b/test/sharness/t0054-dag-car-import-export.sh @@ -233,4 +233,17 @@ test_expect_success "naked root import expected output" ' test_cmp_sorted naked_root_import_json_expected naked_root_import_json_actual ' +test_expect_success "'ipfs dag import' check block size" ' + BIG_CID=$(dd if=/dev/zero bs=2MB count=1 | ipfs dag put --input-codec=raw --store-codec=raw --allow-big-block) && + ipfs dag export $BIG_CID > 2-MB-block.car && + test_expect_code 1 ipfs dag import 2-MB-block.car >dag_import_out 2>&1 +' +test_expect_success "ipfs dag import output has the correct error" ' + grep "block is over 1MiB" dag_import_out +' + +test_expect_success "ipfs dag import --allow-big-block works" ' + test_expect_code 0 ipfs dag import --allow-big-block 2-MB-block.car +' + test_done From 76128272b7fbf431eb3c1daf160cd9921a7a1802 Mon Sep 17 00:00:00 2001 From: Lucas Molas Date: Tue, 15 Mar 2022 18:00:25 -0300 Subject: [PATCH 314/414] unroll setConfigUnsynced --- repo/fsrepo/fsrepo.go | 38 ++++++++++++++++++++++++-------------- 1 file changed, 24 insertions(+), 14 deletions(-) diff --git a/repo/fsrepo/fsrepo.go b/repo/fsrepo/fsrepo.go index a4234dc491a..baafb6630bc 100644 --- a/repo/fsrepo/fsrepo.go +++ b/repo/fsrepo/fsrepo.go @@ -542,8 +542,26 @@ func (r *FSRepo) BackupConfig(prefix string) (string, error) { return orig.Name(), nil } -// setConfigUnsynced is for private use. -func (r *FSRepo) setConfigUnsynced(updated *config.Config) error { +// SetConfig updates the FSRepo's config. The user must not modify the config +// object after calling this method. +// FIXME: There is an inherent contradiction with storing non-user-generated +// Go config.Config structures as user-generated JSON nested maps. This is +// evidenced by the issue of `omitempty` property of fields that aren't defined +// by the user and Go still needs to initialize them to its default (which +// is not reflected in the repo's config file, see +// https://github.com/ipfs/go-ipfs/issues/8088 for more details). +// In general we should call this API with a JSON nested maps as argument +// (`map[string]interface{}`). Many calls to this function are forced to +// synthesize the config.Config struct from their available JSON map just to +// satisfy this (causing incompatibilities like the `omitempty` one above). +// We need to comb SetConfig calls and replace them when possible with a +// JSON map variant. +func (r *FSRepo) SetConfig(updated *config.Config) error { + + // packageLock is held to provide thread-safety. + packageLock.Lock() + defer packageLock.Unlock() + configFilename, err := config.Filename(r.path) if err != nil { return err @@ -569,17 +587,6 @@ func (r *FSRepo) setConfigUnsynced(updated *config.Config) error { return nil } -// SetConfig updates the FSRepo's config. The user must not modify the config -// object after calling this method. -func (r *FSRepo) SetConfig(updated *config.Config) error { - - // packageLock is held to provide thread-safety. - packageLock.Lock() - defer packageLock.Unlock() - - return r.setConfigUnsynced(updated) -} - // GetConfigKey retrieves only the value of a particular key. func (r *FSRepo) GetConfigKey(key string) (interface{}, error) { packageLock.Lock() @@ -643,10 +650,13 @@ func (r *FSRepo) SetConfigKey(key string, value interface{}) error { if err != nil { return err } + r.config = conf + if err := serialize.WriteConfigFile(filename, mapconf); err != nil { return err } - return r.setConfigUnsynced(conf) // TODO roll this into this method + + return nil } // Datastore returns a repo-owned datastore. If FSRepo is Closed, return value From 5e1b2248c576a5ff1ad8b1d681ccdb347aa63556 Mon Sep 17 00:00:00 2001 From: Gus Eggert Date: Wed, 16 Mar 2022 09:42:22 -0400 Subject: [PATCH 315/414] feat: add full goroutine stack dump (#8790) --- bin/collect-profiles.sh | 2 ++ cmd/ipfs/daemon.go | 1 + cmd/ipfs/debug.go | 15 +++++++++++++++ core/commands/profile.go | 30 ++++++++++++++++++++++++++++++ test/sharness/t0152-profile.sh | 4 ++++ 5 files changed, 52 insertions(+) create mode 100644 cmd/ipfs/debug.go diff --git a/bin/collect-profiles.sh b/bin/collect-profiles.sh index eba6495f8c8..25032a4655b 100755 --- a/bin/collect-profiles.sh +++ b/bin/collect-profiles.sh @@ -24,6 +24,8 @@ fi echo Collecting goroutine stacks curl -s -o goroutines.stacks "$SOURCE_URL"'/debug/pprof/goroutine?debug=2' +curl -s -o goroutines.stacks.full "$SOURCE_URL"'/debug/stack' + echo Collecting goroutine profile go tool pprof -symbolize=remote -svg -output goroutine.svg "$SOURCE_URL/debug/pprof/goroutine" diff --git a/cmd/ipfs/daemon.go b/cmd/ipfs/daemon.go index c22dc805415..858f3899791 100644 --- a/cmd/ipfs/daemon.go +++ b/cmd/ipfs/daemon.go @@ -660,6 +660,7 @@ func serveHTTPApi(req *cmds.Request, cctx *oldcmds.Context) (<-chan error, error corehttp.VersionOption(), defaultMux("/debug/vars"), defaultMux("/debug/pprof/"), + defaultMux("/debug/stack"), corehttp.MutexFractionOption("/debug/pprof-mutex/"), corehttp.BlockProfileRateOption("/debug/pprof-block/"), corehttp.MetricsScrapingOption("/debug/metrics/prometheus"), diff --git a/cmd/ipfs/debug.go b/cmd/ipfs/debug.go new file mode 100644 index 00000000000..d3fa90940b9 --- /dev/null +++ b/cmd/ipfs/debug.go @@ -0,0 +1,15 @@ +package main + +import ( + "net/http" + + "github.com/ipfs/go-ipfs/core/commands" +) + +func init() { + http.HandleFunc("/debug/stack", + func(w http.ResponseWriter, _ *http.Request) { + _ = commands.WriteAllGoroutineStacks(w) + }, + ) +} diff --git a/core/commands/profile.go b/core/commands/profile.go index 46c3ee19b8c..f92c3169a7c 100644 --- a/core/commands/profile.go +++ b/core/commands/profile.go @@ -121,6 +121,25 @@ However, it could reveal: }, } +func WriteAllGoroutineStacks(w io.Writer) error { + // this is based on pprof.writeGoroutineStacks, and removes the 64 MB limit + buf := make([]byte, 1<<20) + for i := 0; ; i++ { + n := runtime.Stack(buf, true) + if n < len(buf) { + buf = buf[:n] + break + } + // if len(buf) >= 64<<20 { + // // Filled 64 MB - stop there. + // break + // } + buf = make([]byte, 2*len(buf)) + } + _, err := w.Write(buf) + return err +} + func writeProfiles(ctx context.Context, cpuProfileTime time.Duration, w io.Writer) error { archive := zip.NewWriter(w) @@ -143,6 +162,17 @@ func writeProfiles(ctx context.Context, cpuProfileTime time.Duration, w io.Write file: "heap.pprof", }} + { + out, err := archive.Create("goroutines-all.stacks") + if err != nil { + return err + } + err = WriteAllGoroutineStacks(out) + if err != nil { + return err + } + } + for _, profile := range profiles { prof := pprof.Lookup(profile.name) out, err := archive.Create(profile.file) diff --git a/test/sharness/t0152-profile.sh b/test/sharness/t0152-profile.sh index 6a45dbf167e..13b40517b8d 100755 --- a/test/sharness/t0152-profile.sh +++ b/test/sharness/t0152-profile.sh @@ -61,4 +61,8 @@ test_expect_success "goroutines stacktrace is valid" ' grep -q "goroutine" "profiles/goroutines.stacks" ' +test_expect_success "full goroutines stacktrace is valid" ' + grep -q "goroutine" "profiles/goroutines-all.stacks" +' + test_done From bc33ed4c3503be721e1ae44f2744accfeddc1bf2 Mon Sep 17 00:00:00 2001 From: Gus Eggert Date: Wed, 16 Mar 2022 17:50:46 -0400 Subject: [PATCH 316/414] Update PATCH_RELEASE_TEMPLATE.md --- docs/PATCH_RELEASE_TEMPLATE.md | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/docs/PATCH_RELEASE_TEMPLATE.md b/docs/PATCH_RELEASE_TEMPLATE.md index cd2a1819dba..1cce02a4f27 100644 --- a/docs/PATCH_RELEASE_TEMPLATE.md +++ b/docs/PATCH_RELEASE_TEMPLATE.md @@ -2,12 +2,15 @@ This process handles patch releases from version `vX.Y.Z` to `vX.Y.Z+1` assuming that `vX.Y.Z` is the latest released version of go-ipfs. +- [ ] Get temporary permissions to force-push to `release-*` branches - [ ] Fork a new branch (`release-vX.Y.Z`) from `release` and cherry-pick the relevant commits from master (or custom fixes) onto this branch -- [ ] Make a minimal changelog update tracking the relevant fixes to CHANGELOG. -- [ ] version string in `version.go` has been updated (in the `release-vX.Y.Z+1` branch). + - [ ] Use `git cherry-pick -x` so that the commit message says `(cherry picked from commit ...)` +- [ ] Make a minimal changelog update tracking the relevant fixes to CHANGELOG, as its own commit e.g. `docs: update changelog vX.Y.Z+1` +- [ ] version string in `version.go` has been updated (in the `release-vX.Y.Z+1` branch), as its own commit. - [ ] Make a PR merging `release-vX.Y.Z+1` into the release branch -- [ ] tag the merge commit in the `release` branch with `vX.Y.Z+1` -- [ ] upload to dist.ipfs.io + - This may be unnecessary, e.g. for backports +- [ ] Tag the merge commit in the `release` branch with `vX.Y.Z+1` (ensure the tag is signed) +- [ ] Upload to dist.ipfs.io 1. Build: https://github.com/ipfs/distributions#usage. 2. Pin the resulting release. 3. Make a PR against ipfs/distributions with the updated versions, including the new hash in the PR comment. From 3c09c260bff4eb40e2d75091c1778fc918508168 Mon Sep 17 00:00:00 2001 From: Lucas Molas Date: Wed, 16 Mar 2022 19:03:03 -0300 Subject: [PATCH 317/414] remove todo --- test/sharness/t0250-files-api.sh | 1 - 1 file changed, 1 deletion(-) diff --git a/test/sharness/t0250-files-api.sh b/test/sharness/t0250-files-api.sh index 78cfc39a2cf..382758a0551 100755 --- a/test/sharness/t0250-files-api.sh +++ b/test/sharness/t0250-files-api.sh @@ -875,7 +875,6 @@ test_expect_success "set up automatic sharding/unsharding data" ' done ' -# TODO: This does not need to report an error https://github.com/ipfs/go-ipfs/issues/8088 test_expect_success "reset automatic sharding" ' ipfs config --json Internal.UnixFSShardingSizeThreshold null ' From 519863ecab4db26d33d9a4af8f5284acf4b5ca29 Mon Sep 17 00:00:00 2001 From: Lucas Molas Date: Wed, 5 Jan 2022 11:25:30 -0300 Subject: [PATCH 318/414] fix(core/node): unwrap fx error in node construction --- cmd/ipfs/daemon.go | 1 - core/builder.go | 50 ++++++++++++++++++++++++++++++++++++++++++++-- go.mod | 1 + go.sum | 3 ++- 4 files changed, 51 insertions(+), 4 deletions(-) diff --git a/cmd/ipfs/daemon.go b/cmd/ipfs/daemon.go index a2c65b5b99e..7bf79426542 100644 --- a/cmd/ipfs/daemon.go +++ b/cmd/ipfs/daemon.go @@ -427,7 +427,6 @@ func daemonFunc(req *cmds.Request, re cmds.ResponseEmitter, env cmds.Environment node, err := core.NewNode(req.Context, ncfg) if err != nil { - log.Error("error from node construction: ", err) return err } node.IsDaemon = true diff --git a/core/builder.go b/core/builder.go index e93ceddb2e3..c6bb9919206 100644 --- a/core/builder.go +++ b/core/builder.go @@ -2,6 +2,8 @@ package core import ( "context" + "fmt" + "reflect" "sync" "time" @@ -9,6 +11,7 @@ import ( "github.com/ipfs/go-ipfs/core/node" "github.com/ipfs/go-metrics-interface" + "go.uber.org/dig" "go.uber.org/fx" ) @@ -75,11 +78,11 @@ func NewNode(ctx context.Context, cfg *BuildCfg) (*IpfsNode, error) { }() if app.Err() != nil { - return nil, app.Err() + return nil, logAndUnwrapFxError(app.Err()) } if err := app.Start(ctx); err != nil { - return nil, err + return nil, logAndUnwrapFxError(err) } // TODO: How soon will bootstrap move to libp2p? @@ -89,3 +92,46 @@ func NewNode(ctx context.Context, cfg *BuildCfg) (*IpfsNode, error) { return n, n.Bootstrap(bootstrap.DefaultBootstrapConfig) } + +// Log the entire `app.Err()` but return only the innermost one to the user +// given the full error can be very long (as it can expose the entire build +// graph in a single string). +// +// The fx.App error exposed through `app.Err()` normally contains un-exported +// errors from its low-level `dig` package: +// * https://github.com/uber-go/dig/blob/5e5a20d/error.go#L82 +// These usually wrap themselves in many layers to expose where in the build +// chain did the error happen. Although useful for a developer that needs to +// debug it, it can be very confusing for a user that just wants the IPFS error +// that he can probably fix without being aware of the entire chain. +// Unwrapping everything is not the best solution as there can be useful +// information in the intermediate errors, mainly in the next to last error +// that locates which component is the build error coming from, but it's the +// best we can do at the moment given all errors in dig are private and we +// just have the generic `RootCause` API. +func logAndUnwrapFxError(fxAppErr error) error { + if fxAppErr == nil { + return nil + } + + log.Error("constructing the node: ", fxAppErr) + + err := fxAppErr + for { + extractedErr := dig.RootCause(err) + // Note that the `RootCause` name is misleading as it just unwraps only + // *one* error layer at a time, so we need to continuously call it. + if !reflect.TypeOf(extractedErr).Comparable() { + // Some internal errors are not comparable (e.g., `dig.errMissingTypes` + // which is a slice) and we can't go further. + break + } + if extractedErr == err { + // We didn't unwrap any new error in the last call, reached the innermost one. + break + } + err = extractedErr + } + + return fmt.Errorf("constructing the node (see log for full detail): %w", err) +} diff --git a/go.mod b/go.mod index af332571d8c..6dbb86e3a15 100644 --- a/go.mod +++ b/go.mod @@ -104,6 +104,7 @@ require ( github.com/whyrusleeping/go-sysinfo v0.0.0-20190219211824-4a357d4b90b1 github.com/whyrusleeping/multiaddr-filter v0.0.0-20160516205228-e903e4adabd7 go.opencensus.io v0.23.0 + go.uber.org/dig v1.14.0 go.uber.org/fx v1.16.0 go.uber.org/zap v1.21.0 golang.org/x/crypto v0.0.0-20210921155107-089bfa567519 diff --git a/go.sum b/go.sum index 49abc3cac6d..e874965cbc0 100644 --- a/go.sum +++ b/go.sum @@ -1418,8 +1418,9 @@ go.uber.org/atomic v1.6.0/go.mod h1:sABNBOSYdrvTF6hTgEIbc7YasKWGhgEQZyfxyTvoXHQ= go.uber.org/atomic v1.7.0/go.mod h1:fEN4uk6kAWBTFdckzkM89CLk9XfWZrxpCo0nPH17wJc= go.uber.org/atomic v1.9.0 h1:ECmE8Bn/WFTYwEW/bpKD3M8VtR/zQVbavAoalC1PYyE= go.uber.org/atomic v1.9.0/go.mod h1:fEN4uk6kAWBTFdckzkM89CLk9XfWZrxpCo0nPH17wJc= -go.uber.org/dig v1.12.0 h1:l1GQeZpEbss0/M4l/ZotuBndCrkMdjnygzgcuOjAdaY= go.uber.org/dig v1.12.0/go.mod h1:X34SnWGr8Fyla9zQNO2GSO2D+TIuqB14OS8JhYocIyw= +go.uber.org/dig v1.14.0 h1:VmGvIH45/aapXPQkaOrK5u4B5B7jxZB98HM/utx0eME= +go.uber.org/dig v1.14.0/go.mod h1:jHAn/z1Ld1luVVyGKOAIFYz/uBFqKjjEEdIqVAqfQ2o= go.uber.org/fx v1.16.0 h1:N8i80+X1DCX+qMRiKzM+jPPZiIiyK/bVCysga3+B+1w= go.uber.org/fx v1.16.0/go.mod h1:OMoT5BnXcOaiexlpjtpE4vcAmzyDKyRs9TRYXCzamx8= go.uber.org/goleak v1.0.0/go.mod h1:8a7PlsEVH3e/a/GLqe5IIrQx6GzcnRmZEufDUTk4A7A= From 6774ef9dfdd5aa1e7b34cdd048cb8efedee4e305 Mon Sep 17 00:00:00 2001 From: Dave Justice Date: Wed, 16 Mar 2022 19:07:52 -0400 Subject: [PATCH 319/414] fix: allow ipfs-companion browser extension to access RPC API (#8690) * fix: add companion ids to allow origins - fixes #8689 - Adds the chrome-extension ids for ipfs-companion and ipfs-companion-beta to the allowed origins list, this allows us to accesss ipfs api from a manifest v3 extension. - added tests in t0401-api-browser-security.sh * fix: companion when custom CORS *-Origin is set Companion extension should be able to access RPC API even when custom Access-Control-Allow-Origin is set Co-authored-by: Marcin Rataj --- core/corehttp/commands.go | 12 +++++++---- test/sharness/t0401-api-browser-security.sh | 24 +++++++++++++++++++++ 2 files changed, 32 insertions(+), 4 deletions(-) diff --git a/core/corehttp/commands.go b/core/corehttp/commands.go index 8de1e6be44a..14b503ff528 100644 --- a/core/corehttp/commands.go +++ b/core/corehttp/commands.go @@ -46,6 +46,11 @@ var defaultLocalhostOrigins = []string{ "https://localhost:", } +var companionBrowserExtensionOrigins = []string{ + "chrome-extension://nibjojkomfdiaoajekhjakgkdhaomnch", // ipfs-companion + "chrome-extension://hjoieblefckbooibpepigmacodalfndh", // ipfs-companion-beta +} + func addCORSFromEnv(c *cmdsHttp.ServerConfig) { origin := os.Getenv(originEnvKey) if origin != "" { @@ -84,10 +89,9 @@ func addHeadersFromConfig(c *cmdsHttp.ServerConfig, nc *config.Config) { } func addCORSDefaults(c *cmdsHttp.ServerConfig) { - // by default use localhost origins - if len(c.AllowedOrigins()) == 0 { - c.SetAllowedOrigins(defaultLocalhostOrigins...) - } + // always safelist certain origins + c.AppendAllowedOrigins(defaultLocalhostOrigins...) + c.AppendAllowedOrigins(companionBrowserExtensionOrigins...) // by default, use GET, PUT, POST if len(c.AllowedMethods()) == 0 { diff --git a/test/sharness/t0401-api-browser-security.sh b/test/sharness/t0401-api-browser-security.sh index 1e36bcead32..f288259d5f6 100755 --- a/test/sharness/t0401-api-browser-security.sh +++ b/test/sharness/t0401-api-browser-security.sh @@ -39,6 +39,22 @@ test_expect_success "browser is able to access API if Origin is the API port on grep "HTTP/1.1 200 OK" curl_output && grep "$PEERID" curl_output ' +test_expect_success "Random browser extension is unable to access RPC API due to invalid Origin" ' + curl -sD - -X POST -A "Mozilla" -H "Origin: chrome-extension://invalidextensionid" "http://127.0.0.1:$API_PORT/api/v0/id" >curl_output && + grep "HTTP/1.1 403 Forbidden" curl_output +' + +test_expect_success "Companion extension is able to access RPC API on localhost" ' + curl -sD - -X POST -A "Mozilla" -H "Origin: chrome-extension://nibjojkomfdiaoajekhjakgkdhaomnch" "http://127.0.0.1:$API_PORT/api/v0/id" >curl_output && + cat curl_output && + grep "HTTP/1.1 200 OK" curl_output && grep "$PEERID" curl_output +' + +test_expect_success "Companion beta extension is able to access API on localhost" ' + curl -sD - -X POST -A "Mozilla" -H "Origin: chrome-extension://hjoieblefckbooibpepigmacodalfndh" "http://127.0.0.1:$API_PORT/api/v0/id" >curl_output && + grep "HTTP/1.1 200 OK" curl_output && grep "$PEERID" curl_output +' + test_kill_ipfs_daemon test_expect_success "setting CORS in API.HTTPHeaders works via CLI" " @@ -49,6 +65,14 @@ test_expect_success "setting CORS in API.HTTPHeaders works via CLI" " test_launch_ipfs_daemon +test_expect_success "Companion extension is able to access RPC API even when custom Access-Control-Allow-Origin is set" ' + ipfs config --json API.HTTPHeaders.Access-Control-Allow-Origin | grep -q valid.example.com && + curl -sD - -X POST -A "Mozilla" -H "Origin: chrome-extension://nibjojkomfdiaoajekhjakgkdhaomnch" "http://127.0.0.1:$API_PORT/api/v0/id" >curl_output && + cat curl_output && + grep "HTTP/1.1 200 OK" curl_output && + grep "$PEERID" curl_output +' + # https://developer.mozilla.org/en-US/docs/Glossary/Preflight_request test_expect_success "OPTIONS with preflight request to API with CORS allowlist succeeds" ' curl -svX OPTIONS -A "Mozilla" -H "Origin: https://valid.example.com" -H "Access-Control-Request-Method: POST" -H "Access-Control-Request-Headers: origin, x-requested-with" "http://127.0.0.1:$API_PORT/api/v0/id" 2>curl_output && From 4cabdfefbf9b5d13e5064cedab37b01af18d78b5 Mon Sep 17 00:00:00 2001 From: Marcin Rataj Date: Thu, 17 Mar 2022 17:15:24 +0100 Subject: [PATCH 320/414] feat(gateway): Block and CAR response formats (#8758) * feat: serveRawBlock implements ?format=block * feat: serveCar implements ?format=car * feat(gw): ?format= or Accept HTTP header - extracted file-like content type responses to separate .go files - Accept HTTP header with support for application/vnd.ipld.* types * fix: use .bin for raw block content-disposition .raw may be handled by something, depending on OS, and .bin seems to be universally "binary file" across all systems: https://en.wikipedia.org/wiki/List_of_filename_extensions_(A%E2%80%93E) * refactor: gateway_handler_unixfs.go - Moved UnixFS response handling to gateway_handler_unixfs*.go files. - Removed support for X-Ipfs-Gateway-Prefix (Closes #7702) * refactor: prefix cleanup and readable paths - removed dead code after X-Ipfs-Gateway-Prefix is gone (https://github.com/ipfs/go-ipfs/issues/7702) - escaped special characters in content paths returned with http.Error making them both safer and easier to reason about (e.g. when invisible whitespace Unicode is used) --- core/corehttp/gateway_handler.go | 474 ++++++------------ core/corehttp/gateway_handler_block.go | 38 ++ core/corehttp/gateway_handler_car.go | 72 +++ core/corehttp/gateway_handler_unixfs.go | 37 ++ core/corehttp/gateway_handler_unixfs_dir.go | 197 ++++++++ core/corehttp/gateway_handler_unixfs_file.go | 83 +++ core/corehttp/gateway_test.go | 90 +--- docs/gateway.md | 37 +- test/sharness/lib/test-lib.sh | 13 + test/sharness/t0117-gateway-block.sh | 70 +++ test/sharness/t0118-gateway-car.sh | 116 +++++ test/sharness/t0118-gateway-car/README.md | 10 + .../t0118-gateway-car/carv1-basic.car | Bin 0 -> 715 bytes .../t0118-gateway-car/carv1-basic.json | 159 ++++++ 14 files changed, 992 insertions(+), 404 deletions(-) create mode 100644 core/corehttp/gateway_handler_block.go create mode 100644 core/corehttp/gateway_handler_car.go create mode 100644 core/corehttp/gateway_handler_unixfs.go create mode 100644 core/corehttp/gateway_handler_unixfs_dir.go create mode 100644 core/corehttp/gateway_handler_unixfs_file.go create mode 100755 test/sharness/t0117-gateway-block.sh create mode 100755 test/sharness/t0118-gateway-car.sh create mode 100644 test/sharness/t0118-gateway-car/README.md create mode 100644 test/sharness/t0118-gateway-car/carv1-basic.car create mode 100644 test/sharness/t0118-gateway-car/carv1-basic.json diff --git a/core/corehttp/gateway_handler.go b/core/corehttp/gateway_handler.go index d6e45ba927a..45356271d20 100644 --- a/core/corehttp/gateway_handler.go +++ b/core/corehttp/gateway_handler.go @@ -5,7 +5,6 @@ import ( "fmt" "html/template" "io" - "mime" "net/http" "net/url" "os" @@ -16,11 +15,8 @@ import ( "strings" "time" - humanize "github.com/dustin/go-humanize" - "github.com/gabriel-vasile/mimetype" - "github.com/ipfs/go-cid" + cid "github.com/ipfs/go-cid" files "github.com/ipfs/go-ipfs-files" - assets "github.com/ipfs/go-ipfs/assets" dag "github.com/ipfs/go-merkledag" mfs "github.com/ipfs/go-mfs" path "github.com/ipfs/go-path" @@ -32,11 +28,13 @@ import ( ) const ( - ipfsPathPrefix = "/ipfs/" - ipnsPathPrefix = "/ipns/" + ipfsPathPrefix = "/ipfs/" + ipnsPathPrefix = "/ipns/" + immutableCacheControl = "public, max-age=29030400, immutable" ) var onlyAscii = regexp.MustCompile("[[:^ascii:]]") +var noModtime = time.Unix(0, 0) // disables Last-Modified header if passed as modtime // HTML-based redirect for errors which can be recovered from, but we want // to provide hint to people that they should fix things on their end. @@ -89,6 +87,7 @@ func (sw *statusResponseWriter) WriteHeader(code int) { func newGatewayHandler(c GatewayConfig, api coreiface.CoreAPI) *gatewayHandler { unixfsGetMetric := prometheus.NewSummaryVec( + // TODO: deprecate and switch to content type agnostic metrics: https://github.com/ipfs/go-ipfs/issues/8441 prometheus.SummaryOpts{ Namespace: "ipfs", Subsystem: "http", @@ -196,38 +195,17 @@ func (i *gatewayHandler) optionsHandler(w http.ResponseWriter, r *http.Request) func (i *gatewayHandler) getOrHeadHandler(w http.ResponseWriter, r *http.Request) { begin := time.Now() - urlPath := r.URL.Path - escapedURLPath := r.URL.EscapedPath() logger := log.With("from", r.RequestURI) logger.Debug("http request received") - // If the gateway is behind a reverse proxy and mounted at a sub-path, - // the prefix header can be set to signal this sub-path. - // It will be prepended to links in directory listings and the index.html redirect. - // TODO: this feature is deprecated and will be removed (https://github.com/ipfs/go-ipfs/issues/7702) - prefix := "" - if prfx := r.Header.Get("X-Ipfs-Gateway-Prefix"); len(prfx) > 0 { - for _, p := range i.config.PathPrefixes { - if prfx == p || strings.HasPrefix(prfx, p+"/") { - prefix = prfx - break - } - } - logger.Debugw("sub-path (deprecrated)", "prefix", prefix) - } - - // HostnameOption might have constructed an IPNS/IPFS path using the Host header. - // In this case, we need the original path for constructing redirects - // and links that match the requested URL. - // For example, http://example.net would become /ipns/example.net, and - // the redirects and links would end up as http://example.net/ipns/example.net - requestURI, err := url.ParseRequestURI(r.RequestURI) - if err != nil { - webError(w, "failed to parse request path", err, http.StatusInternalServerError) + // X-Ipfs-Gateway-Prefix was removed (https://github.com/ipfs/go-ipfs/issues/7702) + // TODO: remove this after go-ipfs 0.13 ships + if prfx := r.Header.Get("X-Ipfs-Gateway-Prefix"); prfx != "" { + err := fmt.Errorf("X-Ipfs-Gateway-Prefix support was removed: https://github.com/ipfs/go-ipfs/issues/7702") + webError(w, "unsupported HTTP header", err, http.StatusBadRequest) return } - originalUrlPath := prefix + requestURI.Path // ?uri query param support for requests produced by web browsers // via navigator.registerProtocolHandler Web API @@ -248,7 +226,7 @@ func (i *gatewayHandler) getOrHeadHandler(w http.ResponseWriter, r *http.Request path = path + "?" + u.RawQuery } - redirectURL := gopath.Join("/", prefix, u.Scheme, u.Host, path) + redirectURL := gopath.Join("/", u.Scheme, u.Host, path) logger.Debugw("uri param, redirect", "to", redirectURL, "status", http.StatusMovedPermanently) http.Redirect(w, r, redirectURL, http.StatusMovedPermanently) return @@ -266,9 +244,9 @@ func (i *gatewayHandler) getOrHeadHandler(w http.ResponseWriter, r *http.Request } } - parsedPath := ipath.New(urlPath) - if pathErr := parsedPath.IsValid(); pathErr != nil { - if prefix == "" && fixupSuperfluousNamespace(w, urlPath, r.URL.RawQuery) { + contentPath := ipath.New(r.URL.Path) + if pathErr := contentPath.IsValid(); pathErr != nil { + if fixupSuperfluousNamespace(w, r.URL.Path, r.URL.RawQuery) { // the error was due to redundant namespace, which we were able to fix // by returning error/redirect page, nothing left to do here logger.Debugw("redundant namespace; noop") @@ -280,304 +258,75 @@ func (i *gatewayHandler) getOrHeadHandler(w http.ResponseWriter, r *http.Request } // Resolve path to the final DAG node for the ETag - resolvedPath, err := i.api.ResolvePath(r.Context(), parsedPath) + resolvedPath, err := i.api.ResolvePath(r.Context(), contentPath) switch err { case nil: case coreiface.ErrOffline: - webError(w, "ipfs resolve -r "+escapedURLPath, err, http.StatusServiceUnavailable) + webError(w, "ipfs resolve -r "+debugStr(contentPath.String()), err, http.StatusServiceUnavailable) return default: - if i.servePretty404IfPresent(w, r, parsedPath) { + // if Accept is text/html, see if ipfs-404.html is present + if i.servePretty404IfPresent(w, r, contentPath) { logger.Debugw("serve pretty 404 if present") return } - webError(w, "ipfs resolve -r "+escapedURLPath, err, http.StatusNotFound) - return - } - - dr, err := i.api.Unixfs().Get(r.Context(), resolvedPath) - if err != nil { - webError(w, "ipfs cat "+escapedURLPath, err, http.StatusNotFound) + webError(w, "ipfs resolve -r "+debugStr(contentPath.String()), err, http.StatusNotFound) return } - i.unixfsGetMetric.WithLabelValues(parsedPath.Namespace()).Observe(time.Since(begin).Seconds()) - - defer dr.Close() - - var responseEtag string + // Detect when explicit Accept header or ?format parameter are present + responseFormat := customResponseFormat(r) - // we need to figure out whether this is a directory before doing most of the heavy lifting below - _, ok := dr.(files.Directory) - - if ok && assets.BindataVersionHash != "" { - responseEtag = `"DirIndex-` + assets.BindataVersionHash + `_CID-` + resolvedPath.Cid().String() + `"` - } else { - responseEtag = `"` + resolvedPath.Cid().String() + `"` + // Finish early if client already has matching Etag + if r.Header.Get("If-None-Match") == getEtag(r, resolvedPath.Cid()) { + w.WriteHeader(http.StatusNotModified) + return } - // Check etag sent back to us - if r.Header.Get("If-None-Match") == responseEtag || r.Header.Get("If-None-Match") == `W/`+responseEtag { - w.WriteHeader(http.StatusNotModified) + // Update the global metric of the time it takes to read the final root block of the requested resource + // NOTE: for legacy reasons this happens before we go into content-type specific code paths + _, err = i.api.Block().Get(r.Context(), resolvedPath) + if err != nil { + webError(w, "ipfs block get "+resolvedPath.Cid().String(), err, http.StatusInternalServerError) return } + i.unixfsGetMetric.WithLabelValues(contentPath.Namespace()).Observe(time.Since(begin).Seconds()) + // HTTP Headers i.addUserHeaders(w) // ok, _now_ write user's headers. - w.Header().Set("X-IPFS-Path", urlPath) - w.Header().Set("Etag", responseEtag) + w.Header().Set("X-Ipfs-Path", contentPath.String()) - if rootCids, err := i.buildIpfsRootsHeader(urlPath, r); err == nil { + if rootCids, err := i.buildIpfsRootsHeader(contentPath.String(), r); err == nil { w.Header().Set("X-Ipfs-Roots", rootCids) - } else { // this should never happen, as we resolved the urlPath already + } else { // this should never happen, as we resolved the contentPath already webError(w, "error while resolving X-Ipfs-Roots", err, http.StatusInternalServerError) return } - // set these headers _after_ the error, for we may just not have it - // and don't want the client to cache a 500 response... - // and only if it's /ipfs! - // TODO: break this out when we split /ipfs /ipns routes. - modtime := time.Now() - - if f, ok := dr.(files.File); ok { - if strings.HasPrefix(urlPath, ipfsPathPrefix) { - w.Header().Set("Cache-Control", "public, max-age=29030400, immutable") - - // set modtime to a really long time ago, since files are immutable and should stay cached - modtime = time.Unix(1, 0) - } - - urlFilename := r.URL.Query().Get("filename") - var name string - if urlFilename != "" { - disposition := "inline" - if r.URL.Query().Get("download") == "true" { - disposition = "attachment" - } - utf8Name := url.PathEscape(urlFilename) - asciiName := url.PathEscape(onlyAscii.ReplaceAllLiteralString(urlFilename, "_")) - w.Header().Set("Content-Disposition", fmt.Sprintf("%s; filename=\"%s\"; filename*=UTF-8''%s", disposition, asciiName, utf8Name)) - name = urlFilename - } else { - name = getFilename(urlPath) - } - - logger.Debugw("serving file", "name", name) - i.serveFile(w, r, name, modtime, f) + // Support custom response formats passed via ?format or Accept HTTP header + switch responseFormat { + case "": // The implicit response format is UnixFS + logger.Debugw("serving unixfs", "path", contentPath) + i.serveUnixFs(w, r, resolvedPath, contentPath, logger) return - } - dir, ok := dr.(files.Directory) - if !ok { - internalWebError(w, fmt.Errorf("unsupported file type")) + case "application/vnd.ipld.raw": + logger.Debugw("serving raw block", "path", contentPath) + i.serveRawBlock(w, r, resolvedPath.Cid(), contentPath) return - } - - idxPath := ipath.Join(resolvedPath, "index.html") - idx, err := i.api.Unixfs().Get(r.Context(), idxPath) - switch err.(type) { - case nil: - dirwithoutslash := urlPath[len(urlPath)-1] != '/' - goget := r.URL.Query().Get("go-get") == "1" - if dirwithoutslash && !goget { - // See comment above where originalUrlPath is declared. - suffix := "/" - if r.URL.RawQuery != "" { - // preserve query parameters - suffix = suffix + "?" + r.URL.RawQuery - } - - redirectURL := originalUrlPath + suffix - logger.Debugw("serving index.html file", "to", redirectURL, "status", http.StatusFound, "path", idxPath) - http.Redirect(w, r, redirectURL, http.StatusFound) - return - } - - f, ok := idx.(files.File) - if !ok { - internalWebError(w, files.ErrNotReader) - return - } - // static index.html → no need to generate dynamic dir-index-html - // replace mutable DirIndex Etag with immutable dir CID - w.Header().Set("Etag", `"`+resolvedPath.Cid().String()+`"`) - - logger.Debugw("serving index.html file", "path", idxPath) - // write to request - i.serveFile(w, r, "index.html", modtime, f) - return - case resolver.ErrNoLink: - logger.Debugw("no index.html; noop", "path", idxPath) - default: - internalWebError(w, err) - return - } - - // See statusResponseWriter.WriteHeader - // and https://github.com/ipfs/go-ipfs/issues/7164 - // Note: this needs to occur before listingTemplate.Execute otherwise we get - // superfluous response.WriteHeader call from prometheus/client_golang - if w.Header().Get("Location") != "" { - logger.Debugw("location moved permanently", "status", http.StatusMovedPermanently) - w.WriteHeader(http.StatusMovedPermanently) + case "application/vnd.ipld.car", "application/vnd.ipld.car; version=1": + logger.Debugw("serving car stream", "path", contentPath) + i.serveCar(w, r, resolvedPath.Cid(), contentPath) return - } - - // A HTML directory index will be presented, be sure to set the correct - // type instead of relying on autodetection (which may fail). - w.Header().Set("Content-Type", "text/html") - if r.Method == http.MethodHead { - logger.Debug("return as request's HTTP method is HEAD") + default: // catch-all for unsuported application/vnd.* + err := fmt.Errorf("unsupported format %q", responseFormat) + webError(w, "failed respond with requested content type", err, http.StatusBadRequest) return } - - // storage for directory listing - var dirListing []directoryItem - dirit := dir.Entries() - for dirit.Next() { - size := "?" - if s, err := dirit.Node().Size(); err == nil { - // Size may not be defined/supported. Continue anyways. - size = humanize.Bytes(uint64(s)) - } - - resolved, err := i.api.ResolvePath(r.Context(), ipath.Join(resolvedPath, dirit.Name())) - if err != nil { - internalWebError(w, err) - return - } - hash := resolved.Cid().String() - - // See comment above where originalUrlPath is declared. - di := directoryItem{ - Size: size, - Name: dirit.Name(), - Path: gopath.Join(originalUrlPath, dirit.Name()), - Hash: hash, - ShortHash: shortHash(hash), - } - dirListing = append(dirListing, di) - } - if dirit.Err() != nil { - internalWebError(w, dirit.Err()) - return - } - - // construct the correct back link - // https://github.com/ipfs/go-ipfs/issues/1365 - var backLink string = originalUrlPath - - // don't go further up than /ipfs/$hash/ - pathSplit := path.SplitList(urlPath) - switch { - // keep backlink - case len(pathSplit) == 3: // url: /ipfs/$hash - - // keep backlink - case len(pathSplit) == 4 && pathSplit[3] == "": // url: /ipfs/$hash/ - - // add the correct link depending on whether the path ends with a slash - default: - if strings.HasSuffix(backLink, "/") { - backLink += "./.." - } else { - backLink += "/.." - } - } - - size := "?" - if s, err := dir.Size(); err == nil { - // Size may not be defined/supported. Continue anyways. - size = humanize.Bytes(uint64(s)) - } - - hash := resolvedPath.Cid().String() - - // Gateway root URL to be used when linking to other rootIDs. - // This will be blank unless subdomain or DNSLink resolution is being used - // for this request. - var gwURL string - - // Get gateway hostname and build gateway URL. - if h, ok := r.Context().Value("gw-hostname").(string); ok { - gwURL = "//" + h - } else { - gwURL = "" - } - - dnslink := hasDNSLinkOrigin(gwURL, urlPath) - - // See comment above where originalUrlPath is declared. - tplData := listingTemplateData{ - GatewayURL: gwURL, - DNSLink: dnslink, - Listing: dirListing, - Size: size, - Path: urlPath, - Breadcrumbs: breadcrumbs(urlPath, dnslink), - BackLink: backLink, - Hash: hash, - } - - logger.Debugw("request processed", "tplDataDNSLink", dnslink, "tplDataSize", size, "tplDataBackLink", backLink, "tplDataHash", hash, "duration", time.Since(begin)) - - if err := listingTemplate.Execute(w, tplData); err != nil { - internalWebError(w, err) - return - } -} - -func (i *gatewayHandler) serveFile(w http.ResponseWriter, req *http.Request, name string, modtime time.Time, file files.File) { - size, err := file.Size() - if err != nil { - http.Error(w, "cannot serve files with unknown sizes", http.StatusBadGateway) - return - } - - content := &lazySeeker{ - size: size, - reader: file, - } - - var ctype string - if _, isSymlink := file.(*files.Symlink); isSymlink { - // We should be smarter about resolving symlinks but this is the - // "most correct" we can be without doing that. - ctype = "inode/symlink" - } else { - ctype = mime.TypeByExtension(gopath.Ext(name)) - if ctype == "" { - // uses https://github.com/gabriel-vasile/mimetype library to determine the content type. - // Fixes https://github.com/ipfs/go-ipfs/issues/7252 - mimeType, err := mimetype.DetectReader(content) - if err != nil { - http.Error(w, fmt.Sprintf("cannot detect content-type: %s", err.Error()), http.StatusInternalServerError) - return - } - - ctype = mimeType.String() - _, err = content.Seek(0, io.SeekStart) - if err != nil { - http.Error(w, "seeker can't seek", http.StatusInternalServerError) - return - } - } - // Strip the encoding from the HTML Content-Type header and let the - // browser figure it out. - // - // Fixes https://github.com/ipfs/go-ipfs/issues/2203 - if strings.HasPrefix(ctype, "text/html;") { - ctype = "text/html" - } - } - w.Header().Set("Content-Type", ctype) - - w = &statusResponseWriter{w} - http.ServeContent(w, req, name, modtime, content) } -func (i *gatewayHandler) servePretty404IfPresent(w http.ResponseWriter, r *http.Request, parsedPath ipath.Path) bool { - resolved404Path, ctype, err := i.searchUpTreeFor404(r, parsedPath) +func (i *gatewayHandler) servePretty404IfPresent(w http.ResponseWriter, r *http.Request, contentPath ipath.Path) bool { + resolved404Path, ctype, err := i.searchUpTreeFor404(r, contentPath) if err != nil { return false } @@ -598,7 +347,7 @@ func (i *gatewayHandler) servePretty404IfPresent(w http.ResponseWriter, r *http. return false } - log.Debugw("using pretty 404 file", "path", parsedPath) + log.Debugw("using pretty 404 file", "path", contentPath) w.Header().Set("Content-Type", ctype) w.Header().Set("Content-Length", strconv.FormatInt(size, 10)) w.WriteHeader(http.StatusNotFound) @@ -795,6 +544,67 @@ func (i *gatewayHandler) addUserHeaders(w http.ResponseWriter) { } } +func addCacheControlHeaders(w http.ResponseWriter, r *http.Request, contentPath ipath.Path, fileCid cid.Cid) (modtime time.Time) { + // Set Etag to based on CID (override whatever was set before) + w.Header().Set("Etag", getEtag(r, fileCid)) + + // Set Cache-Control and Last-Modified based on contentPath properties + if contentPath.Mutable() { + // mutable namespaces such as /ipns/ can't be cached forever + + /* For now we set Last-Modified to Now() to leverage caching heuristics built into modern browsers: + * https://github.com/ipfs/go-ipfs/pull/8074#pullrequestreview-645196768 + * but we should not set it to fake values and use Cache-Control based on TTL instead */ + modtime = time.Now() + + // TODO: set Cache-Control based on TTL of IPNS/DNSLink: https://github.com/ipfs/go-ipfs/issues/1818#issuecomment-1015849462 + // TODO: set Last-Modified based on /ipns/ publishing timestamp? + + } else { + // immutable! CACHE ALL THE THINGS, FOREVER! wolololol + w.Header().Set("Cache-Control", immutableCacheControl) + + // Set modtime to 'zero time' to disable Last-Modified header (superseded by Cache-Control) + modtime = noModtime + + // TODO: set Last-Modified? - TBD - /ipfs/ modification metadata is present in unixfs 1.5 https://github.com/ipfs/go-ipfs/issues/6920? + } + + return modtime +} + +// Set Content-Disposition if filename URL query param is present, return preferred filename +func addContentDispositionHeader(w http.ResponseWriter, r *http.Request, contentPath ipath.Path) string { + /* This logic enables: + * - creation of HTML links that trigger "Save As.." dialog instead of being rendered by the browser + * - overriding the filename used when saving subresource assets on HTML page + * - providing a default filename for HTTP clients when downloading direct /ipfs/CID without any subpath + */ + + // URL param ?filename=cat.jpg triggers Content-Disposition: [..] filename + // which impacts default name used in "Save As.." dialog + name := getFilename(contentPath) + urlFilename := r.URL.Query().Get("filename") + if urlFilename != "" { + disposition := "inline" + // URL param ?download=true triggers Content-Disposition: [..] attachment + // which skips rendering and forces "Save As.." dialog in browsers + if r.URL.Query().Get("download") == "true" { + disposition = "attachment" + } + setContentDispositionHeader(w, urlFilename, disposition) + name = urlFilename + } + return name +} + +// Set Content-Disposition to arbitrary filename and disposition +func setContentDispositionHeader(w http.ResponseWriter, filename string, disposition string) { + utf8Name := url.PathEscape(filename) + asciiName := url.PathEscape(onlyAscii.ReplaceAllLiteralString(filename, "_")) + w.Header().Set("Content-Disposition", fmt.Sprintf("%s; filename=\"%s\"; filename*=UTF-8''%s", disposition, asciiName, utf8Name)) +} + // Set X-Ipfs-Roots with logical CID array for efficient HTTP cache invalidation. func (i *gatewayHandler) buildIpfsRootsHeader(contentPath string, r *http.Request) (string, error) { /* @@ -854,7 +664,7 @@ func webError(w http.ResponseWriter, message string, err error, defaultCode int) func webErrorWithCode(w http.ResponseWriter, message string, err error, code int) { http.Error(w, fmt.Sprintf("%s: %s", message, err), code) if code >= 500 { - log.Warnf("server error: %s: %s", err) + log.Warnf("server error: %s: %s", message, err) } } @@ -863,7 +673,8 @@ func internalWebError(w http.ResponseWriter, err error) { webErrorWithCode(w, "internalWebError", err, http.StatusInternalServerError) } -func getFilename(s string) string { +func getFilename(contentPath ipath.Path) string { + s := contentPath.String() if (strings.HasPrefix(s, ipfsPathPrefix) || strings.HasPrefix(s, ipnsPathPrefix)) && strings.Count(gopath.Clean(s), "/") <= 2 { // Don't want to treat ipfs.io in /ipns/ipfs.io as a filename. return "" @@ -871,13 +682,51 @@ func getFilename(s string) string { return gopath.Base(s) } -func (i *gatewayHandler) searchUpTreeFor404(r *http.Request, parsedPath ipath.Path) (ipath.Resolved, string, error) { +// generate Etag value based on HTTP request and CID +func getEtag(r *http.Request, cid cid.Cid) string { + prefix := `"` + suffix := `"` + responseFormat := customResponseFormat(r) + if responseFormat != "" { + // application/vnd.ipld.foo → foo + f := responseFormat[strings.LastIndex(responseFormat, ".")+1:] + // Etag: "cid.foo" (gives us nice compression together with Content-Disposition in block (raw) and car responses) + suffix = `.` + f + suffix + } + // TODO: include selector suffix when https://github.com/ipfs/go-ipfs/issues/8769 lands + return prefix + cid.String() + suffix +} + +// return explicit response format if specified in request as query parameter or via Accept HTTP header +func customResponseFormat(r *http.Request) string { + if formatParam := r.URL.Query().Get("format"); formatParam != "" { + // translate query param to a content type + switch formatParam { + case "raw": + return "application/vnd.ipld.raw" + case "car": + return "application/vnd.ipld.car" + } + } + // Browsers and other user agents will send Accept header with generic types like: + // Accept:text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,*/*;q=0.8 + // We only care about explciit, vendor-specific content-types. + for _, accept := range r.Header.Values("Accept") { + // respond to the very first ipld content type + if strings.HasPrefix(accept, "application/vnd.ipld") { + return accept + } + } + return "" +} + +func (i *gatewayHandler) searchUpTreeFor404(r *http.Request, contentPath ipath.Path) (ipath.Resolved, string, error) { filename404, ctype, err := preferred404Filename(r.Header.Values("Accept")) if err != nil { return nil, "", err } - pathComponents := strings.Split(parsedPath.String(), "/") + pathComponents := strings.Split(contentPath.String(), "/") for idx := len(pathComponents); idx >= 3; idx-- { pretty404 := gopath.Join(append(pathComponents[0:idx], filename404)...) @@ -913,6 +762,15 @@ func preferred404Filename(acceptHeaders []string) (string, string, error) { return "", "", fmt.Errorf("there is no 404 file for the requested content types") } +// returns unquoted path with all special characters revealed as \u codes +func debugStr(path string) string { + q := fmt.Sprintf("%+q", path) + if len(q) >= 3 { + q = q[1 : len(q)-1] + } + return q +} + // Attempt to fix redundant /ipfs/ namespace as long as resulting // 'intended' path is valid. This is in case gremlins were tickled // wrong way and user ended up at /ipfs/ipfs/{cid} or /ipfs/ipns/{id} diff --git a/core/corehttp/gateway_handler_block.go b/core/corehttp/gateway_handler_block.go new file mode 100644 index 00000000000..3b93851d214 --- /dev/null +++ b/core/corehttp/gateway_handler_block.go @@ -0,0 +1,38 @@ +package corehttp + +import ( + "bytes" + "io/ioutil" + "net/http" + + cid "github.com/ipfs/go-cid" + ipath "github.com/ipfs/interface-go-ipfs-core/path" +) + +// serveRawBlock returns bytes behind a raw block +func (i *gatewayHandler) serveRawBlock(w http.ResponseWriter, r *http.Request, blockCid cid.Cid, contentPath ipath.Path) { + blockReader, err := i.api.Block().Get(r.Context(), contentPath) + if err != nil { + webError(w, "ipfs block get "+blockCid.String(), err, http.StatusInternalServerError) + return + } + block, err := ioutil.ReadAll(blockReader) + if err != nil { + webError(w, "ipfs block get "+blockCid.String(), err, http.StatusInternalServerError) + return + } + content := bytes.NewReader(block) + + // Set Content-Disposition + name := blockCid.String() + ".bin" + setContentDispositionHeader(w, name, "attachment") + + // Set remaining headers + modtime := addCacheControlHeaders(w, r, contentPath, blockCid) + w.Header().Set("Content-Type", "application/vnd.ipld.raw") + w.Header().Set("X-Content-Type-Options", "nosniff") // no funny business in the browsers :^) + + // Done: http.ServeContent will take care of + // If-None-Match+Etag, Content-Length and range requests + http.ServeContent(w, r, name, modtime, content) +} diff --git a/core/corehttp/gateway_handler_car.go b/core/corehttp/gateway_handler_car.go new file mode 100644 index 00000000000..43ce99eef53 --- /dev/null +++ b/core/corehttp/gateway_handler_car.go @@ -0,0 +1,72 @@ +package corehttp + +import ( + "context" + "net/http" + + blocks "github.com/ipfs/go-block-format" + cid "github.com/ipfs/go-cid" + coreiface "github.com/ipfs/interface-go-ipfs-core" + ipath "github.com/ipfs/interface-go-ipfs-core/path" + gocar "github.com/ipld/go-car" + selectorparse "github.com/ipld/go-ipld-prime/traversal/selector/parse" +) + +// serveCar returns a CAR stream for specific DAG+selector +func (i *gatewayHandler) serveCar(w http.ResponseWriter, r *http.Request, rootCid cid.Cid, contentPath ipath.Path) { + ctx, cancel := context.WithCancel(r.Context()) + defer cancel() + + // Set Content-Disposition + name := rootCid.String() + ".car" + setContentDispositionHeader(w, name, "attachment") + + // Weak Etag W/ because we can't guarantee byte-for-byte identical responses + // (CAR is streamed, and in theory, blocks may arrive from datastore in non-deterministic order) + etag := `W/` + getEtag(r, rootCid) + w.Header().Set("Etag", etag) + + // Finish early if Etag match + if r.Header.Get("If-None-Match") == etag { + w.WriteHeader(http.StatusNotModified) + return + } + + // Make it clear we don't support range-requests over a car stream + // Partial downloads and resumes should be handled using + // IPLD selectors: https://github.com/ipfs/go-ipfs/issues/8769 + w.Header().Set("Accept-Ranges", "none") + + // Explicit Cache-Control to ensure fresh stream on retry. + // CAR stream could be interrupted, and client should be able to resume and get full response, not the truncated one + w.Header().Set("Cache-Control", "no-cache, no-transform") + + w.Header().Set("Content-Type", "application/vnd.ipld.car; version=1") + w.Header().Set("X-Content-Type-Options", "nosniff") // no funny business in the browsers :^) + + // Same go-car settings as dag.export command + store := dagStore{dag: i.api.Dag(), ctx: ctx} + + // TODO: support selectors passed as request param: https://github.com/ipfs/go-ipfs/issues/8769 + dag := gocar.Dag{Root: rootCid, Selector: selectorparse.CommonSelector_ExploreAllRecursively} + car := gocar.NewSelectiveCar(ctx, store, []gocar.Dag{dag}, gocar.TraverseLinksOnlyOnce()) + + if err := car.Write(w); err != nil { + // We return error as a trailer, however it is not something browsers can access + // (https://github.com/mdn/browser-compat-data/issues/14703) + // Due to this, we suggest client always verify that + // the received CAR stream response is matching requested DAG selector + w.Header().Set("X-Stream-Error", err.Error()) + return + } +} + +type dagStore struct { + dag coreiface.APIDagService + ctx context.Context +} + +func (ds dagStore) Get(c cid.Cid) (blocks.Block, error) { + obj, err := ds.dag.Get(ds.ctx, c) + return obj, err +} diff --git a/core/corehttp/gateway_handler_unixfs.go b/core/corehttp/gateway_handler_unixfs.go new file mode 100644 index 00000000000..6f476b2afe3 --- /dev/null +++ b/core/corehttp/gateway_handler_unixfs.go @@ -0,0 +1,37 @@ +package corehttp + +import ( + "fmt" + "html" + "net/http" + + files "github.com/ipfs/go-ipfs-files" + ipath "github.com/ipfs/interface-go-ipfs-core/path" + "go.uber.org/zap" +) + +func (i *gatewayHandler) serveUnixFs(w http.ResponseWriter, r *http.Request, resolvedPath ipath.Resolved, contentPath ipath.Path, logger *zap.SugaredLogger) { + // Handling UnixFS + dr, err := i.api.Unixfs().Get(r.Context(), resolvedPath) + if err != nil { + webError(w, "ipfs cat "+html.EscapeString(contentPath.String()), err, http.StatusNotFound) + return + } + defer dr.Close() + + // Handling Unixfs file + if f, ok := dr.(files.File); ok { + logger.Debugw("serving unixfs file", "path", contentPath) + i.serveFile(w, r, contentPath, resolvedPath.Cid(), f) + return + } + + // Handling Unixfs directory + dir, ok := dr.(files.Directory) + if !ok { + internalWebError(w, fmt.Errorf("unsupported UnixFs type")) + return + } + logger.Debugw("serving unixfs directory", "path", contentPath) + i.serveDirectory(w, r, resolvedPath, contentPath, dir, logger) +} diff --git a/core/corehttp/gateway_handler_unixfs_dir.go b/core/corehttp/gateway_handler_unixfs_dir.go new file mode 100644 index 00000000000..8e7e131ddf8 --- /dev/null +++ b/core/corehttp/gateway_handler_unixfs_dir.go @@ -0,0 +1,197 @@ +package corehttp + +import ( + "net/http" + "net/url" + gopath "path" + "strings" + + "github.com/dustin/go-humanize" + files "github.com/ipfs/go-ipfs-files" + "github.com/ipfs/go-ipfs/assets" + path "github.com/ipfs/go-path" + "github.com/ipfs/go-path/resolver" + ipath "github.com/ipfs/interface-go-ipfs-core/path" + "go.uber.org/zap" +) + +// serveDirectory returns the best representation of UnixFS directory +// +// It will return index.html if present, or generate directory listing otherwise. +func (i *gatewayHandler) serveDirectory(w http.ResponseWriter, r *http.Request, resolvedPath ipath.Resolved, contentPath ipath.Path, dir files.Directory, logger *zap.SugaredLogger) { + + // HostnameOption might have constructed an IPNS/IPFS path using the Host header. + // In this case, we need the original path for constructing redirects + // and links that match the requested URL. + // For example, http://example.net would become /ipns/example.net, and + // the redirects and links would end up as http://example.net/ipns/example.net + requestURI, err := url.ParseRequestURI(r.RequestURI) + if err != nil { + webError(w, "failed to parse request path", err, http.StatusInternalServerError) + return + } + originalUrlPath := requestURI.Path + + // Check if directory has index.html, if so, serveFile + idxPath := ipath.Join(resolvedPath, "index.html") + idx, err := i.api.Unixfs().Get(r.Context(), idxPath) + switch err.(type) { + case nil: + cpath := contentPath.String() + dirwithoutslash := cpath[len(cpath)-1] != '/' + goget := r.URL.Query().Get("go-get") == "1" + if dirwithoutslash && !goget { + // See comment above where originalUrlPath is declared. + suffix := "/" + if r.URL.RawQuery != "" { + // preserve query parameters + suffix = suffix + "?" + r.URL.RawQuery + } + + redirectURL := originalUrlPath + suffix + logger.Debugw("serving index.html file", "to", redirectURL, "status", http.StatusFound, "path", idxPath) + http.Redirect(w, r, redirectURL, http.StatusFound) + return + } + + f, ok := idx.(files.File) + if !ok { + internalWebError(w, files.ErrNotReader) + return + } + + logger.Debugw("serving index.html file", "path", idxPath) + // write to request + i.serveFile(w, r, idxPath, resolvedPath.Cid(), f) + return + case resolver.ErrNoLink: + logger.Debugw("no index.html; noop", "path", idxPath) + default: + internalWebError(w, err) + return + } + + // See statusResponseWriter.WriteHeader + // and https://github.com/ipfs/go-ipfs/issues/7164 + // Note: this needs to occur before listingTemplate.Execute otherwise we get + // superfluous response.WriteHeader call from prometheus/client_golang + if w.Header().Get("Location") != "" { + logger.Debugw("location moved permanently", "status", http.StatusMovedPermanently) + w.WriteHeader(http.StatusMovedPermanently) + return + } + + // A HTML directory index will be presented, be sure to set the correct + // type instead of relying on autodetection (which may fail). + w.Header().Set("Content-Type", "text/html") + + // Generated dir index requires custom Etag (it may change between go-ipfs versions) + if assets.BindataVersionHash != "" { + dirEtag := `"DirIndex-` + assets.BindataVersionHash + `_CID-` + resolvedPath.Cid().String() + `"` + w.Header().Set("Etag", dirEtag) + if r.Header.Get("If-None-Match") == dirEtag { + w.WriteHeader(http.StatusNotModified) + return + } + } + + if r.Method == http.MethodHead { + logger.Debug("return as request's HTTP method is HEAD") + return + } + + // storage for directory listing + var dirListing []directoryItem + dirit := dir.Entries() + for dirit.Next() { + size := "?" + if s, err := dirit.Node().Size(); err == nil { + // Size may not be defined/supported. Continue anyways. + size = humanize.Bytes(uint64(s)) + } + + resolved, err := i.api.ResolvePath(r.Context(), ipath.Join(resolvedPath, dirit.Name())) + if err != nil { + internalWebError(w, err) + return + } + hash := resolved.Cid().String() + + // See comment above where originalUrlPath is declared. + di := directoryItem{ + Size: size, + Name: dirit.Name(), + Path: gopath.Join(originalUrlPath, dirit.Name()), + Hash: hash, + ShortHash: shortHash(hash), + } + dirListing = append(dirListing, di) + } + if dirit.Err() != nil { + internalWebError(w, dirit.Err()) + return + } + + // construct the correct back link + // https://github.com/ipfs/go-ipfs/issues/1365 + var backLink string = originalUrlPath + + // don't go further up than /ipfs/$hash/ + pathSplit := path.SplitList(contentPath.String()) + switch { + // keep backlink + case len(pathSplit) == 3: // url: /ipfs/$hash + + // keep backlink + case len(pathSplit) == 4 && pathSplit[3] == "": // url: /ipfs/$hash/ + + // add the correct link depending on whether the path ends with a slash + default: + if strings.HasSuffix(backLink, "/") { + backLink += "./.." + } else { + backLink += "/.." + } + } + + size := "?" + if s, err := dir.Size(); err == nil { + // Size may not be defined/supported. Continue anyways. + size = humanize.Bytes(uint64(s)) + } + + hash := resolvedPath.Cid().String() + + // Gateway root URL to be used when linking to other rootIDs. + // This will be blank unless subdomain or DNSLink resolution is being used + // for this request. + var gwURL string + + // Get gateway hostname and build gateway URL. + if h, ok := r.Context().Value("gw-hostname").(string); ok { + gwURL = "//" + h + } else { + gwURL = "" + } + + dnslink := hasDNSLinkOrigin(gwURL, contentPath.String()) + + // See comment above where originalUrlPath is declared. + tplData := listingTemplateData{ + GatewayURL: gwURL, + DNSLink: dnslink, + Listing: dirListing, + Size: size, + Path: contentPath.String(), + Breadcrumbs: breadcrumbs(contentPath.String(), dnslink), + BackLink: backLink, + Hash: hash, + } + + logger.Debugw("request processed", "tplDataDNSLink", dnslink, "tplDataSize", size, "tplDataBackLink", backLink, "tplDataHash", hash) + + if err := listingTemplate.Execute(w, tplData); err != nil { + internalWebError(w, err) + return + } +} diff --git a/core/corehttp/gateway_handler_unixfs_file.go b/core/corehttp/gateway_handler_unixfs_file.go new file mode 100644 index 00000000000..19e6d6795e5 --- /dev/null +++ b/core/corehttp/gateway_handler_unixfs_file.go @@ -0,0 +1,83 @@ +package corehttp + +import ( + "fmt" + "io" + "mime" + "net/http" + gopath "path" + "strings" + + "github.com/gabriel-vasile/mimetype" + cid "github.com/ipfs/go-cid" + files "github.com/ipfs/go-ipfs-files" + ipath "github.com/ipfs/interface-go-ipfs-core/path" +) + +// serveFile returns data behind a file along with HTTP headers based on +// the file itself, its CID and the contentPath used for accessing it. +func (i *gatewayHandler) serveFile(w http.ResponseWriter, r *http.Request, contentPath ipath.Path, fileCid cid.Cid, file files.File) { + + // Set Cache-Control and read optional Last-Modified time + modtime := addCacheControlHeaders(w, r, contentPath, fileCid) + + // Set Content-Disposition + name := addContentDispositionHeader(w, r, contentPath) + + // Prepare size value for Content-Length HTTP header (set inside of http.ServeContent) + size, err := file.Size() + if err != nil { + http.Error(w, "cannot serve files with unknown sizes", http.StatusBadGateway) + return + } + + // Lazy seeker enables efficient range-requests and HTTP HEAD responses + content := &lazySeeker{ + size: size, + reader: file, + } + + // Calculate deterministic value for Content-Type HTTP header + // (we prefer to do it here, rather than using implicit sniffing in http.ServeContent) + var ctype string + if _, isSymlink := file.(*files.Symlink); isSymlink { + // We should be smarter about resolving symlinks but this is the + // "most correct" we can be without doing that. + ctype = "inode/symlink" + } else { + ctype = mime.TypeByExtension(gopath.Ext(name)) + if ctype == "" { + // uses https://github.com/gabriel-vasile/mimetype library to determine the content type. + // Fixes https://github.com/ipfs/go-ipfs/issues/7252 + mimeType, err := mimetype.DetectReader(content) + if err != nil { + http.Error(w, fmt.Sprintf("cannot detect content-type: %s", err.Error()), http.StatusInternalServerError) + return + } + + ctype = mimeType.String() + _, err = content.Seek(0, io.SeekStart) + if err != nil { + http.Error(w, "seeker can't seek", http.StatusInternalServerError) + return + } + } + // Strip the encoding from the HTML Content-Type header and let the + // browser figure it out. + // + // Fixes https://github.com/ipfs/go-ipfs/issues/2203 + if strings.HasPrefix(ctype, "text/html;") { + ctype = "text/html" + } + } + // Setting explicit Content-Type to avoid mime-type sniffing on the client + // (unifies behavior across gateways and web browsers) + w.Header().Set("Content-Type", ctype) + + // special fixup around redirects + w = &statusResponseWriter{w} + + // Done: http.ServeContent will take care of + // If-None-Match+Etag, Content-Length and range requests + http.ServeContent(w, r, name, modtime, content) +} diff --git a/core/corehttp/gateway_test.go b/core/corehttp/gateway_test.go index ae010421767..2cba931ddc4 100644 --- a/core/corehttp/gateway_test.go +++ b/core/corehttp/gateway_test.go @@ -126,12 +126,6 @@ func newTestServerAndNode(t *testing.T, ns mockNamesys) (*httptest.Server, iface t.Fatal(err) } - cfg, err := n.Repo.Config() - if err != nil { - t.Fatal(err) - } - cfg.Gateway.PathPrefixes = []string{"/good-prefix"} - // need this variable here since we need to construct handler with // listener, and server with handler. yay cycles. dh := &delegatedHandler{} @@ -242,7 +236,7 @@ func TestGatewayGet(t *testing.T) { {"127.0.0.1:8080", "/" + k.Cid().String(), http.StatusNotFound, "404 page not found\n"}, {"127.0.0.1:8080", k.String(), http.StatusOK, "fnord"}, {"127.0.0.1:8080", "/ipns/nxdomain.example.com", http.StatusNotFound, "ipfs resolve -r /ipns/nxdomain.example.com: " + namesys.ErrResolveFailed.Error() + "\n"}, - {"127.0.0.1:8080", "/ipns/%0D%0A%0D%0Ahello", http.StatusNotFound, "ipfs resolve -r /ipns/%0D%0A%0D%0Ahello: " + namesys.ErrResolveFailed.Error() + "\n"}, + {"127.0.0.1:8080", "/ipns/%0D%0A%0D%0Ahello", http.StatusNotFound, "ipfs resolve -r /ipns/\\r\\n\\r\\nhello: " + namesys.ErrResolveFailed.Error() + "\n"}, {"127.0.0.1:8080", "/ipns/example.com", http.StatusOK, "fnord"}, {"example.com", "/", http.StatusOK, "fnord"}, @@ -403,7 +397,6 @@ func TestIPNSHostnameRedirect(t *testing.T) { t.Fatal(err) } req.Host = "example.net" - req.Header.Set("X-Ipfs-Gateway-Prefix", "/good-prefix") res, err = doWithoutRedirect(req) if err != nil { @@ -417,8 +410,8 @@ func TestIPNSHostnameRedirect(t *testing.T) { hdr = res.Header["Location"] if len(hdr) < 1 { t.Errorf("location header not present") - } else if hdr[0] != "/good-prefix/foo/" { - t.Errorf("location header is %v, expected /good-prefix/foo/", hdr[0]) + } else if hdr[0] != "/foo/" { + t.Errorf("location header is %v, expected /foo/", hdr[0]) } // make sure /version isn't exposed @@ -427,7 +420,6 @@ func TestIPNSHostnameRedirect(t *testing.T) { t.Fatal(err) } req.Host = "example.net" - req.Header.Set("X-Ipfs-Gateway-Prefix", "/good-prefix") res, err = doWithoutRedirect(req) if err != nil { @@ -583,82 +575,6 @@ func TestIPNSHostnameBacklinks(t *testing.T) { if !strings.Contains(s, k3.Cid().String()) { t.Fatalf("expected hash in directory listing") } - - // make request to directory listing with prefix - req, err = http.NewRequest(http.MethodGet, ts.URL, nil) - if err != nil { - t.Fatal(err) - } - req.Host = "example.net" - req.Header.Set("X-Ipfs-Gateway-Prefix", "/good-prefix") - - res, err = doWithoutRedirect(req) - if err != nil { - t.Fatal(err) - } - - // expect correct backlinks with prefix - body, err = ioutil.ReadAll(res.Body) - if err != nil { - t.Fatalf("error reading response: %s", err) - } - s = string(body) - t.Logf("body: %s\n", string(body)) - - if !matchPathOrBreadcrumbs(s, "/ipns/example.net") { - t.Fatalf("expected a path in directory listing") - } - if !strings.Contains(s, "") { - t.Fatalf("expected backlink in directory listing") - } - if !strings.Contains(s, "") { - t.Fatalf("expected file in directory listing") - } - if !strings.Contains(s, k.Cid().String()) { - t.Fatalf("expected hash in directory listing") - } - - // make request to directory listing with illegal prefix - req, err = http.NewRequest(http.MethodGet, ts.URL, nil) - if err != nil { - t.Fatal(err) - } - req.Host = "example.net" - req.Header.Set("X-Ipfs-Gateway-Prefix", "/bad-prefix") - - // make request to directory listing with evil prefix - req, err = http.NewRequest(http.MethodGet, ts.URL, nil) - if err != nil { - t.Fatal(err) - } - req.Host = "example.net" - req.Header.Set("X-Ipfs-Gateway-Prefix", "//good-prefix/foo") - - res, err = doWithoutRedirect(req) - if err != nil { - t.Fatal(err) - } - - // expect correct backlinks without illegal prefix - body, err = ioutil.ReadAll(res.Body) - if err != nil { - t.Fatalf("error reading response: %s", err) - } - s = string(body) - t.Logf("body: %s\n", string(body)) - - if !matchPathOrBreadcrumbs(s, "/") { - t.Fatalf("expected a path in directory listing") - } - if !strings.Contains(s, "") { - t.Fatalf("expected backlink in directory listing") - } - if !strings.Contains(s, "") { - t.Fatalf("expected file in directory listing") - } - if !strings.Contains(s, k.Cid().String()) { - t.Fatalf("expected hash in directory listing") - } } func TestCacheControlImmutable(t *testing.T) { diff --git a/docs/gateway.md b/docs/gateway.md index 7e85c58ec83..fcfbed36595 100644 --- a/docs/gateway.md +++ b/docs/gateway.md @@ -65,17 +65,36 @@ images, audio, video, PDF) and trigger immediate "save as" dialog by appending > https://ipfs.io/ipfs/QmfM2r8seH2GiRaC4esTjeraXEachRt8ZsSeGaWTPLyMoG?filename=hello_world.txt&download=true -## MIME-Types +## Response Format -TODO +An explicit response format can be requested using `?format=raw|car|..` URL parameter, +or by sending `Accept: application/vnd.ipld.{format}` HTTP header with one of supported content types. -## Read-Only API +## Content-Types -For convenience, the gateway exposes a read-only API. This read-only API exposes -a read-only, "safe" subset of the normal API. +### `application/vnd.ipld.raw` -For example, you use this to download a block: +Returns a byte array for a single `raw` block. -``` -> curl https://ipfs.io/api/v0/block/get/bafkreifjjcie6lypi6ny7amxnfftagclbuxndqonfipmb64f2km2devei4 -``` +Sending such requests for `/ipfs/{cid}` allows for efficient fetch of blocks with data +encoded in custom format, without the need for deserialization and traversal on the gateway. + +This is equivalent of `ipfs block get`. + +### `application/vnd.ipld.car` + +Returns a [CAR](https://ipld.io/specs/transport/car/) stream for specific DAG and selector. + +Right now only 'full DAG' implicit selector is implemented. +Support for user-provided IPLD selectors is tracked in https://github.com/ipfs/go-ipfs/issues/8769. + +This is a rough equivalent of `ipfs dag export`. + +## Deprecated Subset of RPC API + +For legacy reasons, the gateway port exposes a small subset of RPC API under `/api/v0/`. +While this read-only API exposes a read-only, "safe" subset of the normal API, +it is deprecated and should not be used for greenfield projects. + +Where possible, leverage `/ipfs/` and `/ipns/` endpoints. +along with `application/vnd.ipld.*` Content-Types instead. diff --git a/test/sharness/lib/test-lib.sh b/test/sharness/lib/test-lib.sh index a68c5d9737b..38f12a0250c 100644 --- a/test/sharness/lib/test-lib.sh +++ b/test/sharness/lib/test-lib.sh @@ -520,3 +520,16 @@ findprovs_expect() { test_cmp findprovsOut expected ' } + +purge_blockstore() { + ipfs pin ls --quiet --type=recursive | ipfs pin rm &>/dev/null + ipfs repo gc --silent &>/dev/null + + test_expect_success "pinlist empty" ' + [[ -z "$( ipfs pin ls )" ]] + ' + test_expect_success "nothing left to gc" ' + [[ -z "$( ipfs repo gc )" ]] + ' +} + diff --git a/test/sharness/t0117-gateway-block.sh b/test/sharness/t0117-gateway-block.sh new file mode 100755 index 00000000000..c9e3a4713c8 --- /dev/null +++ b/test/sharness/t0117-gateway-block.sh @@ -0,0 +1,70 @@ +#!/usr/bin/env bash + +test_description="Test HTTP Gateway Raw Block (application/vnd.ipld.raw) Support" + +. lib/test-lib.sh + +test_init_ipfs +test_launch_ipfs_daemon_without_network + +test_expect_success "Create text fixtures" ' + mkdir -p dir && + echo "hello application/vnd.ipld.raw" > dir/ascii.txt && + ROOT_DIR_CID=$(ipfs add -Qrw --cid-version 1 dir) && + FILE_CID=$(ipfs resolve -r /ipfs/$ROOT_DIR_CID/dir/ascii.txt | cut -d "/" -f3) +' + +# GET unixfs dir root block and compare it with `ipfs block get` output + + test_expect_success "GET with format=raw param returns a raw block" ' + ipfs block get "/ipfs/$ROOT_DIR_CID/dir" > expected && + curl -sX GET "http://127.0.0.1:$GWAY_PORT/ipfs/$ROOT_DIR_CID/dir?format=raw" -o curl_ipfs_dir_block_param_output && + test_cmp expected curl_ipfs_dir_block_param_output + ' + + test_expect_success "GET for application/vnd.ipld.raw returns a raw block" ' + ipfs block get "/ipfs/$ROOT_DIR_CID/dir" > expected_block && + curl -sX GET -H "Accept: application/vnd.ipld.raw" "http://127.0.0.1:$GWAY_PORT/ipfs/$ROOT_DIR_CID/dir" -o curl_ipfs_dir_block_accept_output && + test_cmp expected_block curl_ipfs_dir_block_accept_output + ' + +# Make sure expected HTTP headers are returned with the block bytes + + test_expect_success "GET response for application/vnd.ipld.raw has expected Content-Type" ' + curl -svX GET -H "Accept: application/vnd.ipld.raw" "http://127.0.0.1:$GWAY_PORT/ipfs/$ROOT_DIR_CID/dir/ascii.txt" >/dev/null 2>curl_output && + cat curl_output && + grep "< Content-Type: application/vnd.ipld.raw" curl_output + ' + + test_expect_success "GET response for application/vnd.ipld.raw includes Content-Length" ' + BYTES=$(ipfs block get $FILE_CID | wc --bytes) + grep "< Content-Length: $BYTES" curl_output + ' + + test_expect_success "GET response for application/vnd.ipld.raw includes Content-Disposition" ' + grep "< Content-Disposition: attachment\; filename=\"${FILE_CID}.bin\"" curl_output + ' + + test_expect_success "GET response for application/vnd.ipld.raw includes nosniff hint" ' + grep "< X-Content-Type-Options: nosniff" curl_output + ' + +# Cache control HTTP headers +# (basic checks, detailed behavior is tested in t0116-gateway-cache.sh) + + test_expect_success "GET response for application/vnd.ipld.raw includes Etag" ' + grep "< Etag: \"${FILE_CID}.raw\"" curl_output + ' + + test_expect_success "GET response for application/vnd.ipld.raw includes X-Ipfs-Path and X-Ipfs-Roots" ' + grep "< X-Ipfs-Path" curl_output && + grep "< X-Ipfs-Roots" curl_output + ' + + test_expect_success "GET response for application/vnd.ipld.raw includes Cache-Control" ' + grep "< Cache-Control" curl_output + ' + +test_kill_ipfs_daemon + +test_done diff --git a/test/sharness/t0118-gateway-car.sh b/test/sharness/t0118-gateway-car.sh new file mode 100755 index 00000000000..9cdb5aec522 --- /dev/null +++ b/test/sharness/t0118-gateway-car.sh @@ -0,0 +1,116 @@ +#!/usr/bin/env bash + +test_description="Test HTTP Gateway CAR (application/vnd.ipld.car) Support" + +. lib/test-lib.sh + +test_init_ipfs +test_launch_ipfs_daemon_without_network + +# CAR stream is not deterministic, as blocks can arrive in random order, +# but if we have a small file that fits into a single block, and export its CID +# we will get a CAR that is a deterministic array of bytes. + + test_expect_success "Create a deterministic CAR for testing" ' + mkdir -p subdir && + echo "hello application/vnd.ipld.car" > subdir/ascii.txt && + ROOT_DIR_CID=$(ipfs add -Qrw --cid-version 1 subdir) && + FILE_CID=$(ipfs resolve -r /ipfs/$ROOT_DIR_CID/subdir/ascii.txt | cut -d "/" -f3) && + ipfs dag export $ROOT_DIR_CID > test-dag.car && + ipfs dag export $FILE_CID > deterministic.car && + purge_blockstore + ' + +# GET a reference DAG with dag-cbor+dag-pb+raw blocks as CAR + + # This test uses official CARv1 fixture from https://ipld.io/specs/transport/car/fixture/carv1-basic/ + test_expect_success "GET for application/vnd.ipld.car with dag-cbor root returns a CARv1 stream with full DAG" ' + ipfs dag import ../t0118-gateway-car/carv1-basic.car && + DAG_CBOR_CID=bafyreihyrpefhacm6kkp4ql6j6udakdit7g3dmkzfriqfykhjw6cad5lrm && + curl -sX GET -H "Accept: application/vnd.ipld.car" "http://127.0.0.1:$GWAY_PORT/ipfs/$DAG_CBOR_CID" -o gateway-dag-cbor.car && + purge_blockstore && + ipfs dag import gateway-dag-cbor.car && + ipfs dag stat --offline $DAG_CBOR_CID + ' + +# GET unixfs file as CAR +# (by using a single file we ensure deterministic result that can be compared byte-for-byte) + + test_expect_success "GET with format=car param returns a CARv1 stream" ' + ipfs dag import test-dag.car && + curl -sX GET "http://127.0.0.1:$GWAY_PORT/ipfs/$ROOT_DIR_CID/subdir/ascii.txt?format=car" -o gateway-param.car && + test_cmp deterministic.car gateway-param.car + ' + + test_expect_success "GET for application/vnd.ipld.car returns a CARv1 stream" ' + ipfs dag import test-dag.car && + curl -sX GET -H "Accept: application/vnd.ipld.car" "http://127.0.0.1:$GWAY_PORT/ipfs/$ROOT_DIR_CID/subdir/ascii.txt" -o gateway-header.car && + test_cmp deterministic.car gateway-header.car + ' + + # explicit version=1 + test_expect_success "GET for application/vnd.ipld.raw version=1 returns a CARv1 stream" ' + ipfs dag import test-dag.car && + curl -sX GET -H "Accept: application/vnd.ipld.car; version=1" "http://127.0.0.1:$GWAY_PORT/ipfs/$ROOT_DIR_CID/subdir/ascii.txt" -o gateway-header-v1.car && + test_cmp deterministic.car gateway-header-v1.car + ' + +# GET unixfs directory as a CAR with DAG and some selector + + # TODO: this is basic test for "full" selector, we will add support for custom ones in https://github.com/ipfs/go-ipfs/issues/8769 + test_expect_success "GET for application/vnd.ipld.car with unixfs dir returns a CARv1 stream with full DAG" ' + ipfs dag import test-dag.car && + curl -sX GET -H "Accept: application/vnd.ipld.car" "http://127.0.0.1:$GWAY_PORT/ipfs/$ROOT_DIR_CID" -o gateway-dir.car && + purge_blockstore && + ipfs dag import gateway-dir.car && + ipfs dag stat --offline $ROOT_DIR_CID + ' + +# Make sure expected HTTP headers are returned with the CAR bytes + + test_expect_success "GET response for application/vnd.ipld.car has expected Content-Type" ' + ipfs dag import test-dag.car && + curl -svX GET -H "Accept: application/vnd.ipld.car" "http://127.0.0.1:$GWAY_PORT/ipfs/$ROOT_DIR_CID/subdir/ascii.txt" >/dev/null 2>curl_output && + cat curl_output && + grep "< Content-Type: application/vnd.ipld.car; version=1" curl_output + ' + + # CAR is streamed, gateway may not have the entire thing, unable to calculate total size + test_expect_success "GET response for application/vnd.ipld.car includes no Content-Length" ' + grep -qv "< Content-Length:" curl_output + ' + + test_expect_success "GET response for application/vnd.ipld.car includes Content-Disposition" ' + grep "< Content-Disposition: attachment\; filename=\"${FILE_CID}.car\"" curl_output + ' + + test_expect_success "GET response for application/vnd.ipld.car includes nosniff hint" ' + grep "< X-Content-Type-Options: nosniff" curl_output + ' + + # CAR is streamed, gateway may not have the entire thing, unable to support range-requests + # Partial downloads and resumes should be handled using + # IPLD selectors: https://github.com/ipfs/go-ipfs/issues/8769 + test_expect_success "GET response for application/vnd.ipld.car includes Accept-Ranges header" ' + grep "< Accept-Ranges: none" curl_output + ' + +# Cache control HTTP headers + + test_expect_success "GET response for application/vnd.ipld.car includes a weak Etag" ' + grep "< Etag: W/\"${FILE_CID}.car\"" curl_output + ' + + # (basic checks, detailed behavior for some fields is tested in t0116-gateway-cache.sh) + test_expect_success "GET response for application/vnd.ipld.car includes X-Ipfs-Path and X-Ipfs-Roots" ' + grep "< X-Ipfs-Path" curl_output && + grep "< X-Ipfs-Roots" curl_output + ' + + test_expect_success "GET response for application/vnd.ipld.car includes expected Cache-Control" ' + grep "< Cache-Control: no-cache, no-transform" curl_output + ' + +test_kill_ipfs_daemon + +test_done diff --git a/test/sharness/t0118-gateway-car/README.md b/test/sharness/t0118-gateway-car/README.md new file mode 100644 index 00000000000..2efccc18544 --- /dev/null +++ b/test/sharness/t0118-gateway-car/README.md @@ -0,0 +1,10 @@ +# Dataset description/sources + +- carv1-basic.car + - raw CARv1 + - Source: https://ipld.io/specs/transport/car/fixture/carv1-basic/carv1-basic.car + +- carv1-basic.json + - description of the contents and layout of the raw CAR, encoded in DAG-JSON + - Source: https://ipld.io/specs/transport/car/fixture/carv1-basic/carv1-basic.json + diff --git a/test/sharness/t0118-gateway-car/carv1-basic.car b/test/sharness/t0118-gateway-car/carv1-basic.car new file mode 100644 index 0000000000000000000000000000000000000000..48c67a3d8dc77ccff652289efb2b41edd4867d44 GIT binary patch literal 715 zcmYdZlv@T^XBM16^mDnYKs~9PRn;i&guKF^#9|+JO5wK+*E)0UP@kKZfZ(W zPG&(fBVpA-dR!`up+XAVeqSs7*{8Kv>B?Kpzb6a>{@wA2tebRKs!GK|)@4yipb$$^ zYGRQDi;zB-l8{2>%BFiZGufxw`Wo51ljYy|w%_%~d!}|Co}CXSx$O<+5@IV(P0r6t zk(kP;L5%6iK+phmEkSd2A+Bva6D`izRIm8 zgfZBugp5uCf Date: Fri, 18 Mar 2022 00:28:29 +0100 Subject: [PATCH 321/414] chore: update deps The commits has been moved from the PR to master to avoid the deps breaking when github is gonna GC the PR commits. --- go.mod | 12 ++++++------ go.sum | 29 ++++++++++++----------------- 2 files changed, 18 insertions(+), 23 deletions(-) diff --git a/go.mod b/go.mod index f87cb2edbc8..11906ab8e8a 100644 --- a/go.mod +++ b/go.mod @@ -13,9 +13,9 @@ require ( github.com/gabriel-vasile/mimetype v1.4.0 github.com/go-bindata/go-bindata/v3 v3.1.3 github.com/hashicorp/go-multierror v1.1.1 - github.com/ipfs/go-bitswap v0.5.2-0.20220302142610-595ae6937936 + github.com/ipfs/go-bitswap v0.5.2-0.20220317230308-3dda118592e6 github.com/ipfs/go-block-format v0.0.3 - github.com/ipfs/go-blockservice v0.2.2-0.20220302144055-931fbecb724e + github.com/ipfs/go-blockservice v0.2.2-0.20220317230748-bad627fc7323 github.com/ipfs/go-cid v0.1.0 github.com/ipfs/go-cidutil v0.0.2 github.com/ipfs/go-datastore v0.5.1 @@ -25,15 +25,15 @@ require ( github.com/ipfs/go-ds-leveldb v0.5.0 github.com/ipfs/go-ds-measure v0.2.0 github.com/ipfs/go-fetcher v1.6.1 - github.com/ipfs/go-filestore v1.1.1-0.20220302151633-1dfe2386cda8 + github.com/ipfs/go-filestore v1.1.1-0.20220317232111-017276727f6d github.com/ipfs/go-fs-lock v0.0.7 github.com/ipfs/go-graphsync v0.11.0 - github.com/ipfs/go-ipfs-blockstore v1.1.3-0.20220302142350-af197de1c3da + github.com/ipfs/go-ipfs-blockstore v1.1.3-0.20220317225625-b3ee1d940911 github.com/ipfs/go-ipfs-chunker v0.0.5 github.com/ipfs/go-ipfs-cmds v0.6.0 github.com/ipfs/go-ipfs-config v0.19.0 github.com/ipfs/go-ipfs-exchange-interface v0.1.0 - github.com/ipfs/go-ipfs-exchange-offline v0.1.2-0.20220302144615-a919970e8153 + github.com/ipfs/go-ipfs-exchange-offline v0.1.2-0.20220317230823-84971a95e6ed github.com/ipfs/go-ipfs-files v0.0.9 github.com/ipfs/go-ipfs-keystore v0.0.2 github.com/ipfs/go-ipfs-pinner v0.2.1 @@ -47,7 +47,7 @@ require ( github.com/ipfs/go-ipld-legacy v0.1.0 github.com/ipfs/go-ipns v0.1.2 github.com/ipfs/go-log v1.0.5 - github.com/ipfs/go-merkledag v0.5.2-0.20220302145706-4c7f7bfbe598 + github.com/ipfs/go-merkledag v0.5.2-0.20220317231502-af90f1ade665 github.com/ipfs/go-metrics-interface v0.0.1 github.com/ipfs/go-metrics-prometheus v0.0.2 github.com/ipfs/go-mfs v0.2.1 diff --git a/go.sum b/go.sum index d5a4e09a87c..a9ee43d7e26 100644 --- a/go.sum +++ b/go.sum @@ -398,8 +398,9 @@ github.com/ipfs/go-bitswap v0.1.2/go.mod h1:qxSWS4NXGs7jQ6zQvoPY3+NmOfHHG47mhkiL github.com/ipfs/go-bitswap v0.1.8/go.mod h1:TOWoxllhccevbWFUR2N7B1MTSVVge1s6XSMiCSA4MzM= github.com/ipfs/go-bitswap v0.3.4/go.mod h1:4T7fvNv/LmOys+21tnLzGKncMeeXUYUd1nUiJ2teMvI= github.com/ipfs/go-bitswap v0.5.1/go.mod h1:P+ckC87ri1xFLvk74NlXdP0Kj9RmWAh4+H78sC6Qopo= -github.com/ipfs/go-bitswap v0.5.2-0.20220302142610-595ae6937936 h1:1Ps0PF7jFKqO8/QwHaFvwCpQ0AITuYSbOI50gts3OiM= github.com/ipfs/go-bitswap v0.5.2-0.20220302142610-595ae6937936/go.mod h1:Ro9XYuNUQxtx/YIZm+OA5mEnADStr5fyowhSUIgZtaU= +github.com/ipfs/go-bitswap v0.5.2-0.20220317230308-3dda118592e6 h1:E5AEw5yKZwsc3Jn+dPKDdOaelCYLFiTTa6i/kr9bW+Q= +github.com/ipfs/go-bitswap v0.5.2-0.20220317230308-3dda118592e6/go.mod h1:Cg0LcvYRaLo9+sfluB+0MR3rhpjJ7+92BtbDm8wMd00= github.com/ipfs/go-block-format v0.0.1/go.mod h1:DK/YYcsSUIVAFNwo/KZCdIIbpN0ROH/baNLgayt4pFc= github.com/ipfs/go-block-format v0.0.2/go.mod h1:AWR46JfpcObNfg3ok2JHDUfdiHRgWhJgCQF+KIgOPJY= github.com/ipfs/go-block-format v0.0.3 h1:r8t66QstRp/pd/or4dpnbVfXT5Gt7lOqRvC+/dDTpMc= @@ -407,10 +408,10 @@ github.com/ipfs/go-block-format v0.0.3/go.mod h1:4LmD4ZUw0mhO+JSKdpWwrzATiEfM7WW github.com/ipfs/go-blockservice v0.0.7/go.mod h1:EOfb9k/Y878ZTRY/CH0x5+ATtaipfbRhbvNSdgc/7So= github.com/ipfs/go-blockservice v0.1.0/go.mod h1:hzmMScl1kXHg3M2BjTymbVPjv627N7sYcvYaKbop39M= github.com/ipfs/go-blockservice v0.1.4/go.mod h1:OTZhFpkgY48kNzbgyvcexW9cHrpjBYIjSR0KoDOFOLU= -github.com/ipfs/go-blockservice v0.1.7/go.mod h1:GmS+BAt4hrwBKkzE11AFDQUrnvqjwFatGS2MY7wOjEM= github.com/ipfs/go-blockservice v0.2.1/go.mod h1:k6SiwmgyYgs4M/qt+ww6amPeUH9EISLRBnvUurKJhi8= -github.com/ipfs/go-blockservice v0.2.2-0.20220302144055-931fbecb724e h1:Nqyg2HAa7lS19g6N7UTpbiJQFHKSO7yp+DvcqY4iBFk= github.com/ipfs/go-blockservice v0.2.2-0.20220302144055-931fbecb724e/go.mod h1:0rezJNcrjTA32XEEXiV/DQAztHZrVduLb7GiktRq6lg= +github.com/ipfs/go-blockservice v0.2.2-0.20220317230748-bad627fc7323 h1:2qH0bpmKZvLVOrvo+l3LXvCLfSSG+3AkmAM+QZWfIiM= +github.com/ipfs/go-blockservice v0.2.2-0.20220317230748-bad627fc7323/go.mod h1:ELeNHgBnD/CR2ucENULArVCliHVnr/KF3y1dvfYg0VE= github.com/ipfs/go-cid v0.0.1/go.mod h1:GHWU/WuQdMPmIosc4Yn1bcCT7dSeX4lBafM7iqUPQvM= github.com/ipfs/go-cid v0.0.2/go.mod h1:GHWU/WuQdMPmIosc4Yn1bcCT7dSeX4lBafM7iqUPQvM= github.com/ipfs/go-cid v0.0.3/go.mod h1:GHWU/WuQdMPmIosc4Yn1bcCT7dSeX4lBafM7iqUPQvM= @@ -457,8 +458,8 @@ github.com/ipfs/go-ds-measure v0.2.0/go.mod h1:SEUD/rE2PwRa4IQEC5FuNAmjJCyYObZr9 github.com/ipfs/go-fetcher v1.5.0/go.mod h1:5pDZ0393oRF/fHiLmtFZtpMNBQfHOYNPtryWedVuSWE= github.com/ipfs/go-fetcher v1.6.1 h1:UFuRVYX5AIllTiRhi5uK/iZkfhSpBCGX7L70nSZEmK8= github.com/ipfs/go-fetcher v1.6.1/go.mod h1:27d/xMV8bodjVs9pugh/RCjjK2OZ68UgAMspMdingNo= -github.com/ipfs/go-filestore v1.1.1-0.20220302151633-1dfe2386cda8 h1:e92gjZ0hO8CCcdi7UN18ghULbd/ZoP524Qm9iZltaF0= -github.com/ipfs/go-filestore v1.1.1-0.20220302151633-1dfe2386cda8/go.mod h1:EQKwAmJqrW20KGt+xU2DVK2RBFgcwYTF9eNM/M0EfKs= +github.com/ipfs/go-filestore v1.1.1-0.20220317232111-017276727f6d h1:qJ2We4rlcx4s5oRFcBtN25IANk7xLrq9EGEcJ0N4tu8= +github.com/ipfs/go-filestore v1.1.1-0.20220317232111-017276727f6d/go.mod h1:fwD+/KDv/kUYcL2siCoe8zZyHsfITPJNDP706GQhOvE= github.com/ipfs/go-fs-lock v0.0.7 h1:6BR3dajORFrFTkb5EpCUFIAypsoxpGpDSVUdFwzgL9U= github.com/ipfs/go-fs-lock v0.0.7/go.mod h1:Js8ka+FNYmgQRLrRXzU3CB/+Csr1BwrRilEcvYrHhhc= github.com/ipfs/go-graphsync v0.11.0 h1:PiiD5CnoC3xEHMW8d6uBGqGcoTwiMB5d9CORIEyF6iA= @@ -466,10 +467,10 @@ github.com/ipfs/go-graphsync v0.11.0/go.mod h1:wC+c8vGVjAHthsVIl8LKr37cUra2GOaMY github.com/ipfs/go-ipfs-blockstore v0.0.1/go.mod h1:d3WClOmRQKFnJ0Jz/jj/zmksX0ma1gROTlovZKBmN08= github.com/ipfs/go-ipfs-blockstore v0.1.0/go.mod h1:5aD0AvHPi7mZc6Ci1WCAhiBQu2IsfTduLl+422H6Rqw= github.com/ipfs/go-ipfs-blockstore v0.1.4/go.mod h1:Jxm3XMVjh6R17WvxFEiyKBLUGr86HgIYJW/D/MwqeYQ= -github.com/ipfs/go-ipfs-blockstore v0.1.6/go.mod h1:Jxm3XMVjh6R17WvxFEiyKBLUGr86HgIYJW/D/MwqeYQ= github.com/ipfs/go-ipfs-blockstore v0.2.1/go.mod h1:jGesd8EtCM3/zPgx+qr0/feTXGUeRai6adgwC+Q+JvE= -github.com/ipfs/go-ipfs-blockstore v1.1.3-0.20220302142350-af197de1c3da h1:/TU6rnYvsuKOwqpWxQXtO/K1Uj7IYY2GFE0WUr4Gh2Y= github.com/ipfs/go-ipfs-blockstore v1.1.3-0.20220302142350-af197de1c3da/go.mod h1:dFOiy6XAxbK5x1Jvx7OAO1rQsrcyHxaXdTLWN085QoE= +github.com/ipfs/go-ipfs-blockstore v1.1.3-0.20220317225625-b3ee1d940911 h1:iCeIFPgo+JsXU40unuMtk8AHfv9UNLRnWXPhVBquxtc= +github.com/ipfs/go-ipfs-blockstore v1.1.3-0.20220317225625-b3ee1d940911/go.mod h1:dFOiy6XAxbK5x1Jvx7OAO1rQsrcyHxaXdTLWN085QoE= github.com/ipfs/go-ipfs-blocksutil v0.0.1 h1:Eh/H4pc1hsvhzsQoMEP3Bke/aW5P5rVM1IWFJMcGIPQ= github.com/ipfs/go-ipfs-blocksutil v0.0.1/go.mod h1:Yq4M86uIOmxmGPUHv/uI7uKqZNtLb449gwKqXjIsnRk= github.com/ipfs/go-ipfs-chunker v0.0.1/go.mod h1:tWewYK0we3+rMbOh7pPFGDyypCtvGcBFymgY4rSDLAw= @@ -491,8 +492,9 @@ github.com/ipfs/go-ipfs-exchange-interface v0.1.0 h1:TiMekCrOGQuWYtZO3mf4YJXDIdN github.com/ipfs/go-ipfs-exchange-interface v0.1.0/go.mod h1:ych7WPlyHqFvCi/uQI48zLZuAWVP5iTQPXEfVaw5WEI= github.com/ipfs/go-ipfs-exchange-offline v0.0.1/go.mod h1:WhHSFCVYX36H/anEKQboAzpUws3x7UeEGkzQc3iNkM0= github.com/ipfs/go-ipfs-exchange-offline v0.1.1/go.mod h1:vTiBRIbzSwDD0OWm+i3xeT0mO7jG2cbJYatp3HPk5XY= -github.com/ipfs/go-ipfs-exchange-offline v0.1.2-0.20220302144615-a919970e8153 h1:GtLORXk45GpVMfhPz+IyZ9YNAe36BQ+rKZvem5Bo49Y= github.com/ipfs/go-ipfs-exchange-offline v0.1.2-0.20220302144615-a919970e8153/go.mod h1:fjwwh1LDdR2LrZ0qYeDbWx4pgdTq+Tw48YaLBjCS2qk= +github.com/ipfs/go-ipfs-exchange-offline v0.1.2-0.20220317230823-84971a95e6ed h1:vDCbp3wMXlK58JlyM+y04+Vu0h0Zy0ED8GbrrmxGxxs= +github.com/ipfs/go-ipfs-exchange-offline v0.1.2-0.20220317230823-84971a95e6ed/go.mod h1:fjwwh1LDdR2LrZ0qYeDbWx4pgdTq+Tw48YaLBjCS2qk= github.com/ipfs/go-ipfs-files v0.0.3/go.mod h1:INEFm0LL2LWXBhNJ2PMIIb2w45hpXgPjNoE7yA8Y1d4= github.com/ipfs/go-ipfs-files v0.0.8/go.mod h1:wiN/jSG8FKyk7N0WyctKSvq3ljIa2NNTiZB55kpTdOs= github.com/ipfs/go-ipfs-files v0.0.9 h1:OFyOfmuVDu9c5YtjSDORmwXzE6fmZikzZpzsnNkgFEg= @@ -547,10 +549,10 @@ github.com/ipfs/go-log/v2 v2.3.0/go.mod h1:QqGoj30OTpnKaG/LKTGTxoP2mmQtjVMEnK72g github.com/ipfs/go-merkledag v0.0.6/go.mod h1:QYPdnlvkOg7GnQRofu9XZimC5ZW5Wi3bKys/4GQQfto= github.com/ipfs/go-merkledag v0.2.3/go.mod h1:SQiXrtSts3KGNmgOzMICy5c0POOpUNQLvB3ClKnBAlk= github.com/ipfs/go-merkledag v0.3.2/go.mod h1:fvkZNNZixVW6cKSZ/JfLlON5OlgTXNdRLz0p6QG/I2M= -github.com/ipfs/go-merkledag v0.4.0/go.mod h1:XshXBkhyeS63YNGisLL1uDSfuTyrQIxVUOg3ojR5MOE= github.com/ipfs/go-merkledag v0.5.1/go.mod h1:cLMZXx8J08idkp5+id62iVftUQV+HlYJ3PIhDfZsjA4= -github.com/ipfs/go-merkledag v0.5.2-0.20220302145706-4c7f7bfbe598 h1:LBBmuAf+riiqOFU/YbErKaHF2kZ5ajc1cjy2puuNyLs= github.com/ipfs/go-merkledag v0.5.2-0.20220302145706-4c7f7bfbe598/go.mod h1:nYh/2ZlUEAHL8glS7y93pPA3Ut7JHkY5fYThsrp8+RY= +github.com/ipfs/go-merkledag v0.5.2-0.20220317231502-af90f1ade665 h1:Ic/2SjkbEW5lpMnGYx2MxUlaH0TPTfCFR0MpWiLlB14= +github.com/ipfs/go-merkledag v0.5.2-0.20220317231502-af90f1ade665/go.mod h1:s34sPVcVsUVKF3JfSit2zhS+Qu92YndK3EHy/cmAih8= github.com/ipfs/go-metrics-interface v0.0.1 h1:j+cpbjYvu4R8zbleSs36gvB7jR+wsL2fGD6n0jO4kdg= github.com/ipfs/go-metrics-interface v0.0.1/go.mod h1:6s6euYU4zowdslK0GKHmqaIZ3j/b/tL7HTWtJ4VPgWY= github.com/ipfs/go-metrics-prometheus v0.0.2 h1:9i2iljLg12S78OhC6UAiXi176xvQGiZaGVF1CUVdE+s= @@ -582,10 +584,6 @@ github.com/ipfs/go-unixfsnode v1.1.3/go.mod h1:ZZxUM5wXBC+G0Co9FjrYTOm+UlhZTjxLf github.com/ipfs/go-verifcid v0.0.1 h1:m2HI7zIuR5TFyQ1b79Da5N9dnnCP1vcu2QqawmWlK2E= github.com/ipfs/go-verifcid v0.0.1/go.mod h1:5Hrva5KBeIog4A+UpqlaIU+DEstipcJYQQZc0g37pY0= github.com/ipfs/interface-go-ipfs-core v0.4.0/go.mod h1:UJBcU6iNennuI05amq3FQ7g0JHUkibHFAfhfUIy927o= -github.com/ipfs/interface-go-ipfs-core v0.5.2 h1:m1/5U+WpOK2ZE7Qzs5iIu80QM1ZA3aWYi2Ilwpi+tdg= -github.com/ipfs/interface-go-ipfs-core v0.5.2/go.mod h1:lNBJrdXHtWS46evMPBdWtDQMDsrKcGbxCOGoKLkztOE= -github.com/ipfs/interface-go-ipfs-core v0.5.3-0.20220302154624-b7f863f05698 h1:PidDOk6cfYYKsO+1LVRpKQUccKJMxB/7It75TATpruA= -github.com/ipfs/interface-go-ipfs-core v0.5.3-0.20220302154624-b7f863f05698/go.mod h1:1wpi0hALzziD775jYmRiehbakCmxZA3XTlTlF3D2z2c= github.com/ipfs/interface-go-ipfs-core v0.5.3-0.20220302172844-ebde7297b2a0 h1:Y+PmGrp9gF9UTIQHMc6PGEMvV6Ylk5zAQJYyIg8z5Mk= github.com/ipfs/interface-go-ipfs-core v0.5.3-0.20220302172844-ebde7297b2a0/go.mod h1:1wpi0hALzziD775jYmRiehbakCmxZA3XTlTlF3D2z2c= github.com/ipfs/tar-utils v0.0.2 h1:UNgHB4x/PPzbMkmJi+7EqC9LNMPDztOVSnx1HAqSNg4= @@ -701,7 +699,6 @@ github.com/libp2p/go-libp2p v0.7.4/go.mod h1:oXsBlTLF1q7pxr+9w6lqzS1ILpyHsaBPniV github.com/libp2p/go-libp2p v0.8.1/go.mod h1:QRNH9pwdbEBpx5DTJYg+qxcVaDMAz3Ee/qDKwXujH5o= github.com/libp2p/go-libp2p v0.12.0/go.mod h1:FpHZrfC1q7nA8jitvdjKBDF31hguaC676g/nT9PgQM0= github.com/libp2p/go-libp2p v0.13.0/go.mod h1:pM0beYdACRfHO1WcJlp65WXyG2A6NqYM+t2DTVAJxMo= -github.com/libp2p/go-libp2p v0.14.0/go.mod h1:dsQrWLAoIn+GkHPN/U+yypizkHiB9tnv79Os+kSgQ4Q= github.com/libp2p/go-libp2p v0.14.3/go.mod h1:d12V4PdKbpL0T1/gsUNN8DfgMuRPDX8bS2QxCZlwRH0= github.com/libp2p/go-libp2p v0.14.4/go.mod h1:EIRU0Of4J5S8rkockZM7eJp2S0UrCyi55m2kJVru3rM= github.com/libp2p/go-libp2p v0.16.0 h1:aTxzQPllnW+nyC9mY8xaS20BbcrSYMt1HCkjZRHvdGY= @@ -909,7 +906,6 @@ github.com/libp2p/go-libp2p-yamux v0.2.8/go.mod h1:/t6tDqeuZf0INZMTgd0WxIRbtK2Ez github.com/libp2p/go-libp2p-yamux v0.4.0/go.mod h1:+DWDjtFMzoAwYLVkNZftoucn7PelNoy5nm3tZ3/Zw30= github.com/libp2p/go-libp2p-yamux v0.5.0/go.mod h1:AyR8k5EzyM2QN9Bbdg6X1SkVVuqLwTGf0L4DFq9g6po= github.com/libp2p/go-libp2p-yamux v0.5.1/go.mod h1:dowuvDu8CRWmr0iqySMiSxK+W0iL5cMVO9S94Y6gkv4= -github.com/libp2p/go-libp2p-yamux v0.5.3/go.mod h1:Vy3TMonBAfTMXHWopsMc8iX/XGRYrRlpUaMzaeuHV/s= github.com/libp2p/go-libp2p-yamux v0.5.4/go.mod h1:tfrXbyaTqqSU654GTvK3ocnSZL3BuHoeTSqhcel1wsE= github.com/libp2p/go-libp2p-yamux v0.6.0 h1:TKayW983n92JhCGdCo7ej7eEb+DQ0VYfKNOxlN/1kNQ= github.com/libp2p/go-libp2p-yamux v0.6.0/go.mod h1:MRhd6mAYnFRnSISp4M8i0ClV/j+mWHo2mYLifWGw33k= @@ -1001,7 +997,6 @@ github.com/libp2p/go-yamux v1.4.0/go.mod h1:fr7aVgmdNGJK+N1g+b6DW6VxzbRCjCOejR/h github.com/libp2p/go-yamux v1.4.1 h1:P1Fe9vF4th5JOxxgQvfbOHkrGqIZniTLf+ddhZp8YTI= github.com/libp2p/go-yamux v1.4.1/go.mod h1:fr7aVgmdNGJK+N1g+b6DW6VxzbRCjCOejR/hkmpooHE= github.com/libp2p/go-yamux/v2 v2.0.0/go.mod h1:NVWira5+sVUIU6tu1JWvaRn1dRnG+cawOJiflsAM+7U= -github.com/libp2p/go-yamux/v2 v2.1.1/go.mod h1:3So6P6TV6r75R9jiBpiIKgU/66lOarCZjqROGxzPpPQ= github.com/libp2p/go-yamux/v2 v2.2.0/go.mod h1:3So6P6TV6r75R9jiBpiIKgU/66lOarCZjqROGxzPpPQ= github.com/libp2p/go-yamux/v2 v2.3.0 h1:luRV68GS1vqqr6EFUjtu1kr51d+IbW0gSowu8emYWAI= github.com/libp2p/go-yamux/v2 v2.3.0/go.mod h1:iTU+lOIn/2h0AgKcL49clNTwfEw+WSfDYrXe05EyKIs= From 6c6a55056db47c9982d9d75e86272aba33b453bb Mon Sep 17 00:00:00 2001 From: Dimitris Apostolou Date: Sun, 13 Mar 2022 10:44:38 +0200 Subject: [PATCH 322/414] Fix typos --- config/addresses.go | 2 +- config/gateway.go | 2 +- config/swarm.go | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/config/addresses.go b/config/addresses.go index 709b28d5847..f16563d6ad6 100644 --- a/config/addresses.go +++ b/config/addresses.go @@ -4,7 +4,7 @@ package config type Addresses struct { Swarm []string // addresses for the swarm to listen on Announce []string // swarm addresses to announce to the network, if len > 0 replaces auto detected addresses - AppendAnnounce []string // similar to Announce but doesn't overwride auto detected addresses, they are just appended + AppendAnnounce []string // similar to Announce but doesn't overwrite auto detected addresses, they are just appended NoAnnounce []string // swarm addresses not to announce to the network API Strings // address for the local API (RPC) Gateway Strings // address to listen on for IPFS HTTP object gateway diff --git a/config/gateway.go b/config/gateway.go index 644467891c9..e85cda98688 100644 --- a/config/gateway.go +++ b/config/gateway.go @@ -62,7 +62,7 @@ type Gateway struct { // NoDNSLink configures the gateway to _not_ perform DNS TXT record // lookups in response to requests with values in `Host` HTTP header. - // This flag can be overriden per FQDN in PublicGateways. + // This flag can be overridden per FQDN in PublicGateways. NoDNSLink bool // PublicGateways configures behavior of known public gateways. diff --git a/config/swarm.go b/config/swarm.go index d03406126e0..ba7b2255fd5 100644 --- a/config/swarm.go +++ b/config/swarm.go @@ -29,7 +29,7 @@ type SwarmConfig struct { // Node will find and use advertised public relays when it determines that // it's not reachable from the public internet. // - // Deprecated: This flag is deprecated and is overriden by + // Deprecated: This flag is deprecated and is overridden by // `Swarm.RelayClient.Enabled` if specified. EnableAutoRelay bool `json:",omitempty"` From 943187d001fee54819abbbe0fdfe1709e62d277e Mon Sep 17 00:00:00 2001 From: Hector Sanjuan Date: Sat, 19 Mar 2022 00:14:25 +0100 Subject: [PATCH 323/414] ErrNotFound changes: bubble tagged libraries. Additionally fixes tests for new error message which went from `ipld: not found` to ` not found` --- go.mod | 16 ++++----- go.sum | 37 +++++++++----------- test/sharness/t0050-block.sh | 4 +-- test/sharness/t0054-dag-car-import-export.sh | 2 +- test/sharness/t0080-repo.sh | 2 +- 5 files changed, 28 insertions(+), 33 deletions(-) diff --git a/go.mod b/go.mod index b7440836484..9e290f9a12f 100644 --- a/go.mod +++ b/go.mod @@ -14,9 +14,9 @@ require ( github.com/gabriel-vasile/mimetype v1.4.0 github.com/go-bindata/go-bindata/v3 v3.1.3 github.com/hashicorp/go-multierror v1.1.1 - github.com/ipfs/go-bitswap v0.5.2-0.20220317230308-3dda118592e6 + github.com/ipfs/go-bitswap v0.6.0 github.com/ipfs/go-block-format v0.0.3 - github.com/ipfs/go-blockservice v0.2.2-0.20220317230748-bad627fc7323 + github.com/ipfs/go-blockservice v0.3.0 github.com/ipfs/go-cid v0.1.0 github.com/ipfs/go-cidutil v0.0.2 github.com/ipfs/go-datastore v0.5.1 @@ -26,14 +26,14 @@ require ( github.com/ipfs/go-ds-leveldb v0.5.0 github.com/ipfs/go-ds-measure v0.2.0 github.com/ipfs/go-fetcher v1.6.1 - github.com/ipfs/go-filestore v1.1.1-0.20220317232111-017276727f6d + github.com/ipfs/go-filestore v1.2.0 github.com/ipfs/go-fs-lock v0.0.7 github.com/ipfs/go-graphsync v0.11.0 - github.com/ipfs/go-ipfs-blockstore v1.1.3-0.20220317225625-b3ee1d940911 + github.com/ipfs/go-ipfs-blockstore v1.2.0 github.com/ipfs/go-ipfs-chunker v0.0.5 github.com/ipfs/go-ipfs-cmds v0.6.0 github.com/ipfs/go-ipfs-exchange-interface v0.1.0 - github.com/ipfs/go-ipfs-exchange-offline v0.1.2-0.20220317230823-84971a95e6ed + github.com/ipfs/go-ipfs-exchange-offline v0.2.0 github.com/ipfs/go-ipfs-files v0.0.9 github.com/ipfs/go-ipfs-keystore v0.0.2 github.com/ipfs/go-ipfs-pinner v0.2.1 @@ -42,12 +42,12 @@ require ( github.com/ipfs/go-ipfs-routing v0.2.1 github.com/ipfs/go-ipfs-util v0.0.2 github.com/ipfs/go-ipld-cbor v0.0.5 - github.com/ipfs/go-ipld-format v0.2.1-0.20220302134852-d02e0e18fc65 + github.com/ipfs/go-ipld-format v0.3.0 github.com/ipfs/go-ipld-git v0.1.1 github.com/ipfs/go-ipld-legacy v0.1.0 github.com/ipfs/go-ipns v0.1.2 github.com/ipfs/go-log v1.0.5 - github.com/ipfs/go-merkledag v0.5.2-0.20220317231502-af90f1ade665 + github.com/ipfs/go-merkledag v0.6.0 github.com/ipfs/go-metrics-interface v0.0.1 github.com/ipfs/go-metrics-prometheus v0.0.2 github.com/ipfs/go-mfs v0.2.1 @@ -57,7 +57,7 @@ require ( github.com/ipfs/go-unixfs v0.3.1 github.com/ipfs/go-unixfsnode v1.1.3 github.com/ipfs/go-verifcid v0.0.1 - github.com/ipfs/interface-go-ipfs-core v0.5.3-0.20220302172844-ebde7297b2a0 + github.com/ipfs/interface-go-ipfs-core v0.6.0 github.com/ipfs/tar-utils v0.0.2 github.com/ipld/go-car v0.3.2 github.com/ipld/go-codec-dagpb v1.3.0 diff --git a/go.sum b/go.sum index 8496e1f373b..71490b133d1 100644 --- a/go.sum +++ b/go.sum @@ -398,9 +398,8 @@ github.com/ipfs/go-bitswap v0.1.2/go.mod h1:qxSWS4NXGs7jQ6zQvoPY3+NmOfHHG47mhkiL github.com/ipfs/go-bitswap v0.1.8/go.mod h1:TOWoxllhccevbWFUR2N7B1MTSVVge1s6XSMiCSA4MzM= github.com/ipfs/go-bitswap v0.3.4/go.mod h1:4T7fvNv/LmOys+21tnLzGKncMeeXUYUd1nUiJ2teMvI= github.com/ipfs/go-bitswap v0.5.1/go.mod h1:P+ckC87ri1xFLvk74NlXdP0Kj9RmWAh4+H78sC6Qopo= -github.com/ipfs/go-bitswap v0.5.2-0.20220302142610-595ae6937936/go.mod h1:Ro9XYuNUQxtx/YIZm+OA5mEnADStr5fyowhSUIgZtaU= -github.com/ipfs/go-bitswap v0.5.2-0.20220317230308-3dda118592e6 h1:E5AEw5yKZwsc3Jn+dPKDdOaelCYLFiTTa6i/kr9bW+Q= -github.com/ipfs/go-bitswap v0.5.2-0.20220317230308-3dda118592e6/go.mod h1:Cg0LcvYRaLo9+sfluB+0MR3rhpjJ7+92BtbDm8wMd00= +github.com/ipfs/go-bitswap v0.6.0 h1:f2rc6GZtoSFhEIzQmddgGiel9xntj02Dg0ZNf2hSC+w= +github.com/ipfs/go-bitswap v0.6.0/go.mod h1:Hj3ZXdOC5wBJvENtdqsixmzzRukqd8EHLxZLZc3mzRA= github.com/ipfs/go-block-format v0.0.1/go.mod h1:DK/YYcsSUIVAFNwo/KZCdIIbpN0ROH/baNLgayt4pFc= github.com/ipfs/go-block-format v0.0.2/go.mod h1:AWR46JfpcObNfg3ok2JHDUfdiHRgWhJgCQF+KIgOPJY= github.com/ipfs/go-block-format v0.0.3 h1:r8t66QstRp/pd/or4dpnbVfXT5Gt7lOqRvC+/dDTpMc= @@ -409,9 +408,8 @@ github.com/ipfs/go-blockservice v0.0.7/go.mod h1:EOfb9k/Y878ZTRY/CH0x5+ATtaipfbR github.com/ipfs/go-blockservice v0.1.0/go.mod h1:hzmMScl1kXHg3M2BjTymbVPjv627N7sYcvYaKbop39M= github.com/ipfs/go-blockservice v0.1.4/go.mod h1:OTZhFpkgY48kNzbgyvcexW9cHrpjBYIjSR0KoDOFOLU= github.com/ipfs/go-blockservice v0.2.1/go.mod h1:k6SiwmgyYgs4M/qt+ww6amPeUH9EISLRBnvUurKJhi8= -github.com/ipfs/go-blockservice v0.2.2-0.20220302144055-931fbecb724e/go.mod h1:0rezJNcrjTA32XEEXiV/DQAztHZrVduLb7GiktRq6lg= -github.com/ipfs/go-blockservice v0.2.2-0.20220317230748-bad627fc7323 h1:2qH0bpmKZvLVOrvo+l3LXvCLfSSG+3AkmAM+QZWfIiM= -github.com/ipfs/go-blockservice v0.2.2-0.20220317230748-bad627fc7323/go.mod h1:ELeNHgBnD/CR2ucENULArVCliHVnr/KF3y1dvfYg0VE= +github.com/ipfs/go-blockservice v0.3.0 h1:cDgcZ+0P0Ih3sl8+qjFr2sVaMdysg/YZpLj5WJ8kiiw= +github.com/ipfs/go-blockservice v0.3.0/go.mod h1:P5ppi8IHDC7O+pA0AlGTF09jruB2h+oP3wVVaZl8sfk= github.com/ipfs/go-cid v0.0.1/go.mod h1:GHWU/WuQdMPmIosc4Yn1bcCT7dSeX4lBafM7iqUPQvM= github.com/ipfs/go-cid v0.0.2/go.mod h1:GHWU/WuQdMPmIosc4Yn1bcCT7dSeX4lBafM7iqUPQvM= github.com/ipfs/go-cid v0.0.3/go.mod h1:GHWU/WuQdMPmIosc4Yn1bcCT7dSeX4lBafM7iqUPQvM= @@ -458,8 +456,8 @@ github.com/ipfs/go-ds-measure v0.2.0/go.mod h1:SEUD/rE2PwRa4IQEC5FuNAmjJCyYObZr9 github.com/ipfs/go-fetcher v1.5.0/go.mod h1:5pDZ0393oRF/fHiLmtFZtpMNBQfHOYNPtryWedVuSWE= github.com/ipfs/go-fetcher v1.6.1 h1:UFuRVYX5AIllTiRhi5uK/iZkfhSpBCGX7L70nSZEmK8= github.com/ipfs/go-fetcher v1.6.1/go.mod h1:27d/xMV8bodjVs9pugh/RCjjK2OZ68UgAMspMdingNo= -github.com/ipfs/go-filestore v1.1.1-0.20220317232111-017276727f6d h1:qJ2We4rlcx4s5oRFcBtN25IANk7xLrq9EGEcJ0N4tu8= -github.com/ipfs/go-filestore v1.1.1-0.20220317232111-017276727f6d/go.mod h1:fwD+/KDv/kUYcL2siCoe8zZyHsfITPJNDP706GQhOvE= +github.com/ipfs/go-filestore v1.2.0 h1:O2wg7wdibwxkEDcl7xkuQsPvJFRBVgVSsOJ/GP6z3yU= +github.com/ipfs/go-filestore v1.2.0/go.mod h1:HLJrCxRXquTeEEpde4lTLMaE/MYJZD7WHLkp9z6+FF8= github.com/ipfs/go-fs-lock v0.0.7 h1:6BR3dajORFrFTkb5EpCUFIAypsoxpGpDSVUdFwzgL9U= github.com/ipfs/go-fs-lock v0.0.7/go.mod h1:Js8ka+FNYmgQRLrRXzU3CB/+Csr1BwrRilEcvYrHhhc= github.com/ipfs/go-graphsync v0.11.0 h1:PiiD5CnoC3xEHMW8d6uBGqGcoTwiMB5d9CORIEyF6iA= @@ -468,9 +466,8 @@ github.com/ipfs/go-ipfs-blockstore v0.0.1/go.mod h1:d3WClOmRQKFnJ0Jz/jj/zmksX0ma github.com/ipfs/go-ipfs-blockstore v0.1.0/go.mod h1:5aD0AvHPi7mZc6Ci1WCAhiBQu2IsfTduLl+422H6Rqw= github.com/ipfs/go-ipfs-blockstore v0.1.4/go.mod h1:Jxm3XMVjh6R17WvxFEiyKBLUGr86HgIYJW/D/MwqeYQ= github.com/ipfs/go-ipfs-blockstore v0.2.1/go.mod h1:jGesd8EtCM3/zPgx+qr0/feTXGUeRai6adgwC+Q+JvE= -github.com/ipfs/go-ipfs-blockstore v1.1.3-0.20220302142350-af197de1c3da/go.mod h1:dFOiy6XAxbK5x1Jvx7OAO1rQsrcyHxaXdTLWN085QoE= -github.com/ipfs/go-ipfs-blockstore v1.1.3-0.20220317225625-b3ee1d940911 h1:iCeIFPgo+JsXU40unuMtk8AHfv9UNLRnWXPhVBquxtc= -github.com/ipfs/go-ipfs-blockstore v1.1.3-0.20220317225625-b3ee1d940911/go.mod h1:dFOiy6XAxbK5x1Jvx7OAO1rQsrcyHxaXdTLWN085QoE= +github.com/ipfs/go-ipfs-blockstore v1.2.0 h1:n3WTeJ4LdICWs/0VSfjHrlqpPpl6MZ+ySd3j8qz0ykw= +github.com/ipfs/go-ipfs-blockstore v1.2.0/go.mod h1:eh8eTFLiINYNSNawfZOC7HOxNTxpB1PFuA5E1m/7exE= github.com/ipfs/go-ipfs-blocksutil v0.0.1 h1:Eh/H4pc1hsvhzsQoMEP3Bke/aW5P5rVM1IWFJMcGIPQ= github.com/ipfs/go-ipfs-blocksutil v0.0.1/go.mod h1:Yq4M86uIOmxmGPUHv/uI7uKqZNtLb449gwKqXjIsnRk= github.com/ipfs/go-ipfs-chunker v0.0.1/go.mod h1:tWewYK0we3+rMbOh7pPFGDyypCtvGcBFymgY4rSDLAw= @@ -490,9 +487,8 @@ github.com/ipfs/go-ipfs-exchange-interface v0.1.0 h1:TiMekCrOGQuWYtZO3mf4YJXDIdN github.com/ipfs/go-ipfs-exchange-interface v0.1.0/go.mod h1:ych7WPlyHqFvCi/uQI48zLZuAWVP5iTQPXEfVaw5WEI= github.com/ipfs/go-ipfs-exchange-offline v0.0.1/go.mod h1:WhHSFCVYX36H/anEKQboAzpUws3x7UeEGkzQc3iNkM0= github.com/ipfs/go-ipfs-exchange-offline v0.1.1/go.mod h1:vTiBRIbzSwDD0OWm+i3xeT0mO7jG2cbJYatp3HPk5XY= -github.com/ipfs/go-ipfs-exchange-offline v0.1.2-0.20220302144615-a919970e8153/go.mod h1:fjwwh1LDdR2LrZ0qYeDbWx4pgdTq+Tw48YaLBjCS2qk= -github.com/ipfs/go-ipfs-exchange-offline v0.1.2-0.20220317230823-84971a95e6ed h1:vDCbp3wMXlK58JlyM+y04+Vu0h0Zy0ED8GbrrmxGxxs= -github.com/ipfs/go-ipfs-exchange-offline v0.1.2-0.20220317230823-84971a95e6ed/go.mod h1:fjwwh1LDdR2LrZ0qYeDbWx4pgdTq+Tw48YaLBjCS2qk= +github.com/ipfs/go-ipfs-exchange-offline v0.2.0 h1:2PF4o4A7W656rC0RxuhUace997FTcDTcIQ6NoEtyjAI= +github.com/ipfs/go-ipfs-exchange-offline v0.2.0/go.mod h1:HjwBeW0dvZvfOMwDP0TSKXIHf2s+ksdP4E3MLDRtLKY= github.com/ipfs/go-ipfs-files v0.0.3/go.mod h1:INEFm0LL2LWXBhNJ2PMIIb2w45hpXgPjNoE7yA8Y1d4= github.com/ipfs/go-ipfs-files v0.0.8/go.mod h1:wiN/jSG8FKyk7N0WyctKSvq3ljIa2NNTiZB55kpTdOs= github.com/ipfs/go-ipfs-files v0.0.9 h1:OFyOfmuVDu9c5YtjSDORmwXzE6fmZikzZpzsnNkgFEg= @@ -523,8 +519,8 @@ github.com/ipfs/go-ipld-cbor v0.0.5/go.mod h1:BkCduEx3XBCO6t2Sfo5BaHzuok7hbhdMm9 github.com/ipfs/go-ipld-format v0.0.1/go.mod h1:kyJtbkDALmFHv3QR6et67i35QzO3S0dCDnkOJhcZkms= github.com/ipfs/go-ipld-format v0.0.2/go.mod h1:4B6+FM2u9OJ9zCV+kSbgFAZlOrv1Hqbf0INGQgiKf9k= github.com/ipfs/go-ipld-format v0.2.0/go.mod h1:3l3C1uKoadTPbeNfrDi+xMInYKlx2Cvg1BuydPSdzQs= -github.com/ipfs/go-ipld-format v0.2.1-0.20220302134852-d02e0e18fc65 h1:xxnD+fUS7hziDAnfrn3qsl0ql18DOjq4rwvzBTCr1iA= -github.com/ipfs/go-ipld-format v0.2.1-0.20220302134852-d02e0e18fc65/go.mod h1:co/SdBE8h99968X0hViiw1MNlh6fvxxnHpvVLnH7jSM= +github.com/ipfs/go-ipld-format v0.3.0 h1:Mwm2oRLzIuUwEPewWAWyMuuBQUsn3awfFEYVb8akMOQ= +github.com/ipfs/go-ipld-format v0.3.0/go.mod h1:co/SdBE8h99968X0hViiw1MNlh6fvxxnHpvVLnH7jSM= github.com/ipfs/go-ipld-git v0.1.1 h1:TWGnZjS0htmEmlMFEkA3ogrNCqWjIxwr16x1OsdhG+Y= github.com/ipfs/go-ipld-git v0.1.1/go.mod h1:+VyMqF5lMcJh4rwEppV0e6g4nCCHXThLYYDpKUkJubI= github.com/ipfs/go-ipld-legacy v0.1.0 h1:wxkkc4k8cnvIGIjPO0waJCe7SHEyFgl+yQdafdjGrpA= @@ -548,9 +544,8 @@ github.com/ipfs/go-merkledag v0.0.6/go.mod h1:QYPdnlvkOg7GnQRofu9XZimC5ZW5Wi3bKy github.com/ipfs/go-merkledag v0.2.3/go.mod h1:SQiXrtSts3KGNmgOzMICy5c0POOpUNQLvB3ClKnBAlk= github.com/ipfs/go-merkledag v0.3.2/go.mod h1:fvkZNNZixVW6cKSZ/JfLlON5OlgTXNdRLz0p6QG/I2M= github.com/ipfs/go-merkledag v0.5.1/go.mod h1:cLMZXx8J08idkp5+id62iVftUQV+HlYJ3PIhDfZsjA4= -github.com/ipfs/go-merkledag v0.5.2-0.20220302145706-4c7f7bfbe598/go.mod h1:nYh/2ZlUEAHL8glS7y93pPA3Ut7JHkY5fYThsrp8+RY= -github.com/ipfs/go-merkledag v0.5.2-0.20220317231502-af90f1ade665 h1:Ic/2SjkbEW5lpMnGYx2MxUlaH0TPTfCFR0MpWiLlB14= -github.com/ipfs/go-merkledag v0.5.2-0.20220317231502-af90f1ade665/go.mod h1:s34sPVcVsUVKF3JfSit2zhS+Qu92YndK3EHy/cmAih8= +github.com/ipfs/go-merkledag v0.6.0 h1:oV5WT2321tS4YQVOPgIrWHvJ0lJobRTerU+i9nmUCuA= +github.com/ipfs/go-merkledag v0.6.0/go.mod h1:9HSEwRd5sV+lbykiYP+2NC/3o6MZbKNaa4hfNcH5iH0= github.com/ipfs/go-metrics-interface v0.0.1 h1:j+cpbjYvu4R8zbleSs36gvB7jR+wsL2fGD6n0jO4kdg= github.com/ipfs/go-metrics-interface v0.0.1/go.mod h1:6s6euYU4zowdslK0GKHmqaIZ3j/b/tL7HTWtJ4VPgWY= github.com/ipfs/go-metrics-prometheus v0.0.2 h1:9i2iljLg12S78OhC6UAiXi176xvQGiZaGVF1CUVdE+s= @@ -582,8 +577,8 @@ github.com/ipfs/go-unixfsnode v1.1.3/go.mod h1:ZZxUM5wXBC+G0Co9FjrYTOm+UlhZTjxLf github.com/ipfs/go-verifcid v0.0.1 h1:m2HI7zIuR5TFyQ1b79Da5N9dnnCP1vcu2QqawmWlK2E= github.com/ipfs/go-verifcid v0.0.1/go.mod h1:5Hrva5KBeIog4A+UpqlaIU+DEstipcJYQQZc0g37pY0= github.com/ipfs/interface-go-ipfs-core v0.4.0/go.mod h1:UJBcU6iNennuI05amq3FQ7g0JHUkibHFAfhfUIy927o= -github.com/ipfs/interface-go-ipfs-core v0.5.3-0.20220302172844-ebde7297b2a0 h1:Y+PmGrp9gF9UTIQHMc6PGEMvV6Ylk5zAQJYyIg8z5Mk= -github.com/ipfs/interface-go-ipfs-core v0.5.3-0.20220302172844-ebde7297b2a0/go.mod h1:1wpi0hALzziD775jYmRiehbakCmxZA3XTlTlF3D2z2c= +github.com/ipfs/interface-go-ipfs-core v0.6.0 h1:a43QNc3CNayuMjZM+4D9SeyiSF2nKxBaG8qbCAelMNs= +github.com/ipfs/interface-go-ipfs-core v0.6.0/go.mod h1:h3NuO3wzv2KuKazt0zDF2/i8AFRqiKHusyh5DUQQdPA= github.com/ipfs/tar-utils v0.0.2 h1:UNgHB4x/PPzbMkmJi+7EqC9LNMPDztOVSnx1HAqSNg4= github.com/ipfs/tar-utils v0.0.2/go.mod h1:4qlnRWgTVljIMhSG2SqRYn66NT+3wrv/kZt9V+eqxDM= github.com/ipld/go-car v0.3.2 h1:V9wt/80FNfbMRWSD98W5br6fyjUAyVgI2lDOTZX16Lg= diff --git a/test/sharness/t0050-block.sh b/test/sharness/t0050-block.sh index 548e7a63638..4e809876b73 100755 --- a/test/sharness/t0050-block.sh +++ b/test/sharness/t0050-block.sh @@ -134,9 +134,9 @@ test_expect_success "multi-block 'ipfs block rm '" ' ' test_expect_success "multi-block 'ipfs block rm ' output looks good" ' - echo "cannot remove $RANDOMHASH: ipld: $RANDOMHASH not found" >> expect_mixed_rm && + echo "cannot remove $RANDOMHASH: $RANDOMHASH not found" >> expect_mixed_rm && echo "removed $TESTHASH" >> expect_mixed_rm && - echo "cannot remove $RANDOMHASH: ipld: $RANDOMHASH not found" >> expect_mixed_rm && + echo "cannot remove $RANDOMHASH: $RANDOMHASH not found" >> expect_mixed_rm && echo "Error: some blocks not removed" >> expect_mixed_rm test_cmp actual_mixed_rm expect_mixed_rm ' diff --git a/test/sharness/t0054-dag-car-import-export.sh b/test/sharness/t0054-dag-car-import-export.sh index a7b01be602e..d1ec0d2c52b 100755 --- a/test/sharness/t0054-dag-car-import-export.sh +++ b/test/sharness/t0054-dag-car-import-export.sh @@ -179,7 +179,7 @@ test_expect_success "basic offline export of 'getting started' dag works" ' ' -echo "Error: block was not found locally (offline): ipld: QmYwAPJXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX not found (currently offline, perhaps retry after attaching to the network)" > offline_fetch_error_expected +echo "Error: block was not found locally (offline): QmYwAPJXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX not found (currently offline, perhaps retry after attaching to the network)" > offline_fetch_error_expected test_expect_success "basic offline export of nonexistent cid" ' ! ipfs dag export QmYwAPJXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX 2> offline_fetch_error_actual >/dev/null ' diff --git a/test/sharness/t0080-repo.sh b/test/sharness/t0080-repo.sh index 0c5d3561503..521b8db43d2 100755 --- a/test/sharness/t0080-repo.sh +++ b/test/sharness/t0080-repo.sh @@ -64,7 +64,7 @@ test_expect_success "'ipfs repo gc --silent' succeeds (no output)" ' ipfs repo gc --silent >gc_out_empty && test_cmp /dev/null gc_out_empty && test_must_fail ipfs cat "$HASH2" 2>err_expected1 && - grep "Error: ipld: $HASH2 not found" err_expected1 + grep "Error: $HASH2 not found" err_expected1 ' test_kill_ipfs_daemon From beaa8fc29b472214283b9aab884ed92f03908d13 Mon Sep 17 00:00:00 2001 From: Adin Schmahmann Date: Mon, 21 Mar 2022 10:57:08 -0400 Subject: [PATCH 324/414] feat: add gateway histogram metrics (#8443) * feat(gw): response type histogram metrics - response-type agnostic firstContentBlockGetMetric which counts the latency til the first content block. - car/block/file/gen-dir-index duration histogram metrics that show how long each response type takes * docs: improve metrics descriptions * feat: more gw histogram buckets 0.05, 0.1, 0.25, 0.5, 1, 2, 5, 10, 30, 60 secs as suggested in reviews at https://github.com/ipfs/go-ipfs/pull/8443 Co-authored-by: Marcin Rataj Co-authored-by: Gus Eggert --- core/corehttp/gateway_handler.go | 107 ++++++++++++++++--- core/corehttp/gateway_handler_block.go | 6 +- core/corehttp/gateway_handler_car.go | 6 +- core/corehttp/gateway_handler_unixfs.go | 7 +- core/corehttp/gateway_handler_unixfs_dir.go | 8 +- core/corehttp/gateway_handler_unixfs_file.go | 6 +- 6 files changed, 116 insertions(+), 24 deletions(-) diff --git a/core/corehttp/gateway_handler.go b/core/corehttp/gateway_handler.go index 45356271d20..eca2efff610 100644 --- a/core/corehttp/gateway_handler.go +++ b/core/corehttp/gateway_handler.go @@ -62,7 +62,15 @@ type gatewayHandler struct { config GatewayConfig api coreiface.CoreAPI - unixfsGetMetric *prometheus.SummaryVec + // generic metrics + firstContentBlockGetMetric *prometheus.HistogramVec + unixfsGetMetric *prometheus.SummaryVec // deprecated, use firstContentBlockGetMetric + + // response type metrics + unixfsFileGetMetric *prometheus.HistogramVec + unixfsGenDirGetMetric *prometheus.HistogramVec + carStreamGetMetric *prometheus.HistogramVec + rawBlockGetMetric *prometheus.HistogramVec } // StatusResponseWriter enables us to override HTTP Status Code passed to @@ -85,29 +93,93 @@ func (sw *statusResponseWriter) WriteHeader(code int) { sw.ResponseWriter.WriteHeader(code) } -func newGatewayHandler(c GatewayConfig, api coreiface.CoreAPI) *gatewayHandler { - unixfsGetMetric := prometheus.NewSummaryVec( - // TODO: deprecate and switch to content type agnostic metrics: https://github.com/ipfs/go-ipfs/issues/8441 +func newGatewaySummaryMetric(name string, help string) *prometheus.SummaryVec { + summaryMetric := prometheus.NewSummaryVec( prometheus.SummaryOpts{ Namespace: "ipfs", Subsystem: "http", - Name: "unixfs_get_latency_seconds", - Help: "The time till the first block is received when 'getting' a file from the gateway.", + Name: name, + Help: help, + }, + []string{"gateway"}, + ) + if err := prometheus.Register(summaryMetric); err != nil { + if are, ok := err.(prometheus.AlreadyRegisteredError); ok { + summaryMetric = are.ExistingCollector.(*prometheus.SummaryVec) + } else { + log.Errorf("failed to register ipfs_http_%s: %v", name, err) + } + } + return summaryMetric +} + +func newGatewayHistogramMetric(name string, help string) *prometheus.HistogramVec { + // We can add buckets as a parameter in the future, but for now using static defaults + // suggested in https://github.com/ipfs/go-ipfs/issues/8441 + defaultBuckets := []float64{0.05, 0.1, 0.25, 0.5, 1, 2, 5, 10, 30, 60} + histogramMetric := prometheus.NewHistogramVec( + prometheus.HistogramOpts{ + Namespace: "ipfs", + Subsystem: "http", + Name: name, + Help: help, + Buckets: defaultBuckets, }, []string{"gateway"}, ) - if err := prometheus.Register(unixfsGetMetric); err != nil { + if err := prometheus.Register(histogramMetric); err != nil { if are, ok := err.(prometheus.AlreadyRegisteredError); ok { - unixfsGetMetric = are.ExistingCollector.(*prometheus.SummaryVec) + histogramMetric = are.ExistingCollector.(*prometheus.HistogramVec) } else { - log.Errorf("failed to register unixfsGetMetric: %v", err) + log.Errorf("failed to register ipfs_http_%s: %v", name, err) } } + return histogramMetric +} +func newGatewayHandler(c GatewayConfig, api coreiface.CoreAPI) *gatewayHandler { i := &gatewayHandler{ - config: c, - api: api, - unixfsGetMetric: unixfsGetMetric, + config: c, + api: api, + // Improved Metrics + // ---------------------------- + // Time till the first content block (bar in /ipfs/cid/foo/bar) + // (format-agnostic, across all response types) + firstContentBlockGetMetric: newGatewayHistogramMetric( + "gw_first_content_block_get_latency_seconds", + "The time till the first content block is received on GET from the gateway.", + ), + + // Response-type specific metrics + // ---------------------------- + // UnixFS: time it takes to return a file + unixfsFileGetMetric: newGatewayHistogramMetric( + "gw_unixfs_file_get_duration_seconds", + "The time to serve an entire UnixFS file from the gateway.", + ), + // UnixFS: time it takes to generate static HTML with directory listing + unixfsGenDirGetMetric: newGatewayHistogramMetric( + "gw_unixfs_gen_dir_listing_get_duration_seconds", + "The time to serve a generated UnixFS HTML directory listing from the gateway.", + ), + // CAR: time it takes to return requested CAR stream + carStreamGetMetric: newGatewayHistogramMetric( + "gw_car_stream_get_duration_seconds", + "The time to GET an entire CAR stream from the gateway.", + ), + // Block: time it takes to return requested Block + rawBlockGetMetric: newGatewayHistogramMetric( + "gw_raw_block_get_duration_seconds", + "The time to GET an entire raw Block from the gateway.", + ), + + // Legacy Metrics + // ---------------------------- + unixfsGetMetric: newGatewaySummaryMetric( // TODO: remove? + // (deprecated, use firstContentBlockGetMetric instead) + "unixfs_get_latency_seconds", + "The time to receive the first UnixFS node on a GET from the gateway.", + ), } return i } @@ -291,7 +363,10 @@ func (i *gatewayHandler) getOrHeadHandler(w http.ResponseWriter, r *http.Request webError(w, "ipfs block get "+resolvedPath.Cid().String(), err, http.StatusInternalServerError) return } - i.unixfsGetMetric.WithLabelValues(contentPath.Namespace()).Observe(time.Since(begin).Seconds()) + ns := contentPath.Namespace() + timeToGetFirstContentBlock := time.Since(begin).Seconds() + i.unixfsGetMetric.WithLabelValues(ns).Observe(timeToGetFirstContentBlock) // deprecated, use firstContentBlockGetMetric instead + i.firstContentBlockGetMetric.WithLabelValues(ns).Observe(timeToGetFirstContentBlock) // HTTP Headers i.addUserHeaders(w) // ok, _now_ write user's headers. @@ -308,15 +383,15 @@ func (i *gatewayHandler) getOrHeadHandler(w http.ResponseWriter, r *http.Request switch responseFormat { case "": // The implicit response format is UnixFS logger.Debugw("serving unixfs", "path", contentPath) - i.serveUnixFs(w, r, resolvedPath, contentPath, logger) + i.serveUnixFs(w, r, resolvedPath, contentPath, begin, logger) return case "application/vnd.ipld.raw": logger.Debugw("serving raw block", "path", contentPath) - i.serveRawBlock(w, r, resolvedPath.Cid(), contentPath) + i.serveRawBlock(w, r, resolvedPath.Cid(), contentPath, begin) return case "application/vnd.ipld.car", "application/vnd.ipld.car; version=1": logger.Debugw("serving car stream", "path", contentPath) - i.serveCar(w, r, resolvedPath.Cid(), contentPath) + i.serveCar(w, r, resolvedPath.Cid(), contentPath, begin) return default: // catch-all for unsuported application/vnd.* err := fmt.Errorf("unsupported format %q", responseFormat) diff --git a/core/corehttp/gateway_handler_block.go b/core/corehttp/gateway_handler_block.go index 3b93851d214..13d7ebefd9f 100644 --- a/core/corehttp/gateway_handler_block.go +++ b/core/corehttp/gateway_handler_block.go @@ -4,13 +4,14 @@ import ( "bytes" "io/ioutil" "net/http" + "time" cid "github.com/ipfs/go-cid" ipath "github.com/ipfs/interface-go-ipfs-core/path" ) // serveRawBlock returns bytes behind a raw block -func (i *gatewayHandler) serveRawBlock(w http.ResponseWriter, r *http.Request, blockCid cid.Cid, contentPath ipath.Path) { +func (i *gatewayHandler) serveRawBlock(w http.ResponseWriter, r *http.Request, blockCid cid.Cid, contentPath ipath.Path, begin time.Time) { blockReader, err := i.api.Block().Get(r.Context(), contentPath) if err != nil { webError(w, "ipfs block get "+blockCid.String(), err, http.StatusInternalServerError) @@ -35,4 +36,7 @@ func (i *gatewayHandler) serveRawBlock(w http.ResponseWriter, r *http.Request, b // Done: http.ServeContent will take care of // If-None-Match+Etag, Content-Length and range requests http.ServeContent(w, r, name, modtime, content) + + // Update metrics + i.rawBlockGetMetric.WithLabelValues(contentPath.Namespace()).Observe(time.Since(begin).Seconds()) } diff --git a/core/corehttp/gateway_handler_car.go b/core/corehttp/gateway_handler_car.go index 43ce99eef53..5f0f2117fc7 100644 --- a/core/corehttp/gateway_handler_car.go +++ b/core/corehttp/gateway_handler_car.go @@ -3,6 +3,7 @@ package corehttp import ( "context" "net/http" + "time" blocks "github.com/ipfs/go-block-format" cid "github.com/ipfs/go-cid" @@ -13,7 +14,7 @@ import ( ) // serveCar returns a CAR stream for specific DAG+selector -func (i *gatewayHandler) serveCar(w http.ResponseWriter, r *http.Request, rootCid cid.Cid, contentPath ipath.Path) { +func (i *gatewayHandler) serveCar(w http.ResponseWriter, r *http.Request, rootCid cid.Cid, contentPath ipath.Path, begin time.Time) { ctx, cancel := context.WithCancel(r.Context()) defer cancel() @@ -59,6 +60,9 @@ func (i *gatewayHandler) serveCar(w http.ResponseWriter, r *http.Request, rootCi w.Header().Set("X-Stream-Error", err.Error()) return } + + // Update metrics + i.carStreamGetMetric.WithLabelValues(contentPath.Namespace()).Observe(time.Since(begin).Seconds()) } type dagStore struct { diff --git a/core/corehttp/gateway_handler_unixfs.go b/core/corehttp/gateway_handler_unixfs.go index 6f476b2afe3..ed15f41393b 100644 --- a/core/corehttp/gateway_handler_unixfs.go +++ b/core/corehttp/gateway_handler_unixfs.go @@ -4,13 +4,14 @@ import ( "fmt" "html" "net/http" + "time" files "github.com/ipfs/go-ipfs-files" ipath "github.com/ipfs/interface-go-ipfs-core/path" "go.uber.org/zap" ) -func (i *gatewayHandler) serveUnixFs(w http.ResponseWriter, r *http.Request, resolvedPath ipath.Resolved, contentPath ipath.Path, logger *zap.SugaredLogger) { +func (i *gatewayHandler) serveUnixFs(w http.ResponseWriter, r *http.Request, resolvedPath ipath.Resolved, contentPath ipath.Path, begin time.Time, logger *zap.SugaredLogger) { // Handling UnixFS dr, err := i.api.Unixfs().Get(r.Context(), resolvedPath) if err != nil { @@ -22,7 +23,7 @@ func (i *gatewayHandler) serveUnixFs(w http.ResponseWriter, r *http.Request, res // Handling Unixfs file if f, ok := dr.(files.File); ok { logger.Debugw("serving unixfs file", "path", contentPath) - i.serveFile(w, r, contentPath, resolvedPath.Cid(), f) + i.serveFile(w, r, contentPath, resolvedPath.Cid(), f, begin) return } @@ -33,5 +34,5 @@ func (i *gatewayHandler) serveUnixFs(w http.ResponseWriter, r *http.Request, res return } logger.Debugw("serving unixfs directory", "path", contentPath) - i.serveDirectory(w, r, resolvedPath, contentPath, dir, logger) + i.serveDirectory(w, r, resolvedPath, contentPath, dir, begin, logger) } diff --git a/core/corehttp/gateway_handler_unixfs_dir.go b/core/corehttp/gateway_handler_unixfs_dir.go index 8e7e131ddf8..87708159e8e 100644 --- a/core/corehttp/gateway_handler_unixfs_dir.go +++ b/core/corehttp/gateway_handler_unixfs_dir.go @@ -5,6 +5,7 @@ import ( "net/url" gopath "path" "strings" + "time" "github.com/dustin/go-humanize" files "github.com/ipfs/go-ipfs-files" @@ -18,7 +19,7 @@ import ( // serveDirectory returns the best representation of UnixFS directory // // It will return index.html if present, or generate directory listing otherwise. -func (i *gatewayHandler) serveDirectory(w http.ResponseWriter, r *http.Request, resolvedPath ipath.Resolved, contentPath ipath.Path, dir files.Directory, logger *zap.SugaredLogger) { +func (i *gatewayHandler) serveDirectory(w http.ResponseWriter, r *http.Request, resolvedPath ipath.Resolved, contentPath ipath.Path, dir files.Directory, begin time.Time, logger *zap.SugaredLogger) { // HostnameOption might have constructed an IPNS/IPFS path using the Host header. // In this case, we need the original path for constructing redirects @@ -62,7 +63,7 @@ func (i *gatewayHandler) serveDirectory(w http.ResponseWriter, r *http.Request, logger.Debugw("serving index.html file", "path", idxPath) // write to request - i.serveFile(w, r, idxPath, resolvedPath.Cid(), f) + i.serveFile(w, r, idxPath, resolvedPath.Cid(), f, begin) return case resolver.ErrNoLink: logger.Debugw("no index.html; noop", "path", idxPath) @@ -194,4 +195,7 @@ func (i *gatewayHandler) serveDirectory(w http.ResponseWriter, r *http.Request, internalWebError(w, err) return } + + // Update metrics + i.unixfsGenDirGetMetric.WithLabelValues(contentPath.Namespace()).Observe(time.Since(begin).Seconds()) } diff --git a/core/corehttp/gateway_handler_unixfs_file.go b/core/corehttp/gateway_handler_unixfs_file.go index 19e6d6795e5..9807969fee0 100644 --- a/core/corehttp/gateway_handler_unixfs_file.go +++ b/core/corehttp/gateway_handler_unixfs_file.go @@ -7,6 +7,7 @@ import ( "net/http" gopath "path" "strings" + "time" "github.com/gabriel-vasile/mimetype" cid "github.com/ipfs/go-cid" @@ -16,7 +17,7 @@ import ( // serveFile returns data behind a file along with HTTP headers based on // the file itself, its CID and the contentPath used for accessing it. -func (i *gatewayHandler) serveFile(w http.ResponseWriter, r *http.Request, contentPath ipath.Path, fileCid cid.Cid, file files.File) { +func (i *gatewayHandler) serveFile(w http.ResponseWriter, r *http.Request, contentPath ipath.Path, fileCid cid.Cid, file files.File, begin time.Time) { // Set Cache-Control and read optional Last-Modified time modtime := addCacheControlHeaders(w, r, contentPath, fileCid) @@ -80,4 +81,7 @@ func (i *gatewayHandler) serveFile(w http.ResponseWriter, r *http.Request, conte // Done: http.ServeContent will take care of // If-None-Match+Etag, Content-Length and range requests http.ServeContent(w, r, name, modtime, content) + + // Update metrics + i.unixfsFileGetMetric.WithLabelValues(contentPath.Namespace()).Observe(time.Since(begin).Seconds()) } From f62bd64fdb840809a211984ec3c6499abc62690b Mon Sep 17 00:00:00 2001 From: Lucas Molas Date: Mon, 21 Mar 2022 19:03:37 -0300 Subject: [PATCH 325/414] allow config to fail as we have no empty default --- test/sharness/t0171-peering.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/sharness/t0171-peering.sh b/test/sharness/t0171-peering.sh index 9b775cb3cbe..207b279803a 100755 --- a/test/sharness/t0171-peering.sh +++ b/test/sharness/t0171-peering.sh @@ -33,7 +33,7 @@ peer_addrs() { peer() { PEER1="$1" && PEER2="$2" && - PEER_LIST="$(ipfsi "$PEER1" config Peering.Peers)" && + PEER_LIST="$(ipfsi "$PEER1" config Peering.Peers || true)" && { [[ "$PEER_LIST" == "null" ]] || PEER_LIST_INNER="${PEER_LIST:1:-1}"; } && ADDR_INFO="$(printf '[%s{"ID": "%s", "Addrs": %s}]' \ "${PEER_LIST_INNER:+${PEER_LIST_INNER},}" \ From a61c53f87fc6b5341c8d0a0b088cb16dd59f8cc8 Mon Sep 17 00:00:00 2001 From: Marcin Rataj Date: Tue, 22 Mar 2022 20:46:32 +0100 Subject: [PATCH 326/414] feat(cmds): document deprecated RPC API commands (#8802) * feat(cmds): add deprecated and experimental status Added programmatic state annotation introduced in https://github.com/ipfs/go-ipfs-cmds/pull/225 for already deprecated / experimental commands. * chore: go-ipfs-cmds v0.7.0 Co-authored-by: Lucas Molas --- core/commands/dag/dag.go | 6 +++--- core/commands/name/ipnsps.go | 4 ++++ core/commands/object/diff.go | 1 + core/commands/object/object.go | 7 +++++++ core/commands/object/patch.go | 5 +++++ core/commands/p2p.go | 8 ++++++++ core/commands/pubsub.go | 5 +++++ core/commands/repo.go | 1 + core/commands/unixfs/ls.go | 3 ++- core/commands/unixfs/unixfs.go | 11 +++-------- core/commands/urlstore.go | 1 + go.mod | 2 +- go.sum | 4 ++-- 13 files changed, 43 insertions(+), 15 deletions(-) diff --git a/core/commands/dag/dag.go b/core/commands/dag/dag.go index 6d2e480b284..d5d7479f268 100644 --- a/core/commands/dag/dag.go +++ b/core/commands/dag/dag.go @@ -30,9 +30,9 @@ var DagCmd = &cmds.Command{ ShortDescription: ` 'ipfs dag' is used for creating and manipulating DAG objects/hierarchies. -This subcommand is currently an experimental feature, but it is intended -to deprecate and replace the existing 'ipfs object' command moving forward. - `, +This subcommand is intended to deprecate and replace +the existing 'ipfs object' command moving forward. +`, }, Subcommands: map[string]*cmds.Command{ "put": DagPutCmd, diff --git a/core/commands/name/ipnsps.go b/core/commands/name/ipnsps.go index 31791570970..949ea43d5e8 100644 --- a/core/commands/name/ipnsps.go +++ b/core/commands/name/ipnsps.go @@ -26,6 +26,7 @@ type stringList struct { // IpnsPubsubCmd is the subcommand that allows us to manage the IPNS pubsub system var IpnsPubsubCmd = &cmds.Command{ + Status: cmds.Experimental, Helptext: cmds.HelpText{ Tagline: "IPNS pubsub management", ShortDescription: ` @@ -42,6 +43,7 @@ Note: this command is experimental and subject to change as the system is refine } var ipnspsStateCmd = &cmds.Command{ + Status: cmds.Experimental, Helptext: cmds.HelpText{ Tagline: "Query the state of IPNS pubsub.", }, @@ -70,6 +72,7 @@ var ipnspsStateCmd = &cmds.Command{ } var ipnspsSubsCmd = &cmds.Command{ + Status: cmds.Experimental, Helptext: cmds.HelpText{ Tagline: "Show current name subscriptions.", }, @@ -114,6 +117,7 @@ var ipnspsSubsCmd = &cmds.Command{ } var ipnspsCancelCmd = &cmds.Command{ + Status: cmds.Experimental, Helptext: cmds.HelpText{ Tagline: "Cancel a name subscription.", }, diff --git a/core/commands/object/diff.go b/core/commands/object/diff.go index d83da7cec5d..54727cd287f 100644 --- a/core/commands/object/diff.go +++ b/core/commands/object/diff.go @@ -20,6 +20,7 @@ type Changes struct { } var ObjectDiffCmd = &cmds.Command{ + Status: cmds.Deprecated, // https://github.com/ipfs/go-ipfs/issues/7936 Helptext: cmds.HelpText{ Tagline: "Display the diff between two IPFS objects.", ShortDescription: ` diff --git a/core/commands/object/object.go b/core/commands/object/object.go index 1e145208a59..00f2f44ce3d 100644 --- a/core/commands/object/object.go +++ b/core/commands/object/object.go @@ -47,6 +47,7 @@ const ( ) var ObjectCmd = &cmds.Command{ + Status: cmds.Deprecated, // https://github.com/ipfs/go-ipfs/issues/7936 Helptext: cmds.HelpText{ Tagline: "Deprecated commands to interact with dag-pb objects. Use 'dag' or 'files' instead.", ShortDescription: ` @@ -68,6 +69,7 @@ directly. Deprecated, use more modern 'ipfs dag' and 'ipfs files' instead.`, // ObjectDataCmd object data command var ObjectDataCmd = &cmds.Command{ + Status: cmds.Deprecated, // https://github.com/ipfs/go-ipfs/issues/7936 Helptext: cmds.HelpText{ Tagline: "Deprecated way to read the raw bytes of a dag-pb object: use 'dag get' instead.", ShortDescription: ` @@ -107,6 +109,7 @@ is the raw data of the object. // ObjectLinksCmd object links command var ObjectLinksCmd = &cmds.Command{ + Status: cmds.Deprecated, // https://github.com/ipfs/go-ipfs/issues/7936 Helptext: cmds.HelpText{ Tagline: "Deprecated way to output links in the specified dag-pb object: use 'dag get' instead.", ShortDescription: ` @@ -181,6 +184,7 @@ multihash. Provided for legacy reasons. Use 'ipfs dag get' instead. // ObjectGetCmd object get command var ObjectGetCmd = &cmds.Command{ + Status: cmds.Deprecated, // https://github.com/ipfs/go-ipfs/issues/7936 Helptext: cmds.HelpText{ Tagline: "Deprecated way to get and serialize the dag-pb node. Use 'dag get' instead", ShortDescription: ` @@ -272,6 +276,7 @@ DEPRECATED and provided for legacy reasons. Use 'ipfs dag get' instead. // ObjectStatCmd object stat command var ObjectStatCmd = &cmds.Command{ + Status: cmds.Deprecated, // https://github.com/ipfs/go-ipfs/issues/7936 Helptext: cmds.HelpText{ Tagline: "Deprecated way to read stats for the dag-pb node. Use 'files stat' instead.", ShortDescription: ` @@ -371,6 +376,7 @@ DEPRECATED: Provided for legacy reasons. Modern replacements: // ObjectPutCmd object put command var ObjectPutCmd = &cmds.Command{ + Status: cmds.Deprecated, // https://github.com/ipfs/go-ipfs/issues/7936 Helptext: cmds.HelpText{ Tagline: "Deprecated way to store input as a DAG object. Use 'dag put' instead.", ShortDescription: ` @@ -450,6 +456,7 @@ DEPRECATED and provided for legacy reasons. Use 'ipfs dag put' instead. // ObjectNewCmd object new command var ObjectNewCmd = &cmds.Command{ + Status: cmds.Deprecated, // https://github.com/ipfs/go-ipfs/issues/7936 Helptext: cmds.HelpText{ Tagline: "Deprecated way to create a new dag-pb object from a template.", ShortDescription: ` diff --git a/core/commands/object/patch.go b/core/commands/object/patch.go index ab76ebb23f4..6843b226765 100644 --- a/core/commands/object/patch.go +++ b/core/commands/object/patch.go @@ -13,6 +13,7 @@ import ( ) var ObjectPatchCmd = &cmds.Command{ + Status: cmds.Deprecated, // https://github.com/ipfs/go-ipfs/issues/7936 Helptext: cmds.HelpText{ Tagline: "Deprecated way to create a new merkledag object based on an existing one. Use MFS with 'files cp|rm' instead.", ShortDescription: ` @@ -48,6 +49,7 @@ For modern use cases, use MFS with 'files' commands: 'ipfs files --help'. } var patchAppendDataCmd = &cmds.Command{ + Status: cmds.Deprecated, // https://github.com/ipfs/go-ipfs/issues/7936 Helptext: cmds.HelpText{ Tagline: "Deprecated way to append data to the data segment of a DAG node.", ShortDescription: ` @@ -102,6 +104,7 @@ DEPRECATED and provided for legacy reasons. Use 'ipfs add' or 'ipfs files' inste } var patchSetDataCmd = &cmds.Command{ + Status: cmds.Deprecated, // https://github.com/ipfs/go-ipfs/issues/7936 Helptext: cmds.HelpText{ Tagline: "Deprecated way to set the data field of dag-pb object.", ShortDescription: ` @@ -152,6 +155,7 @@ DEPRECATED and provided for legacy reasons. Use 'files cp' and 'dag put' instead } var patchRmLinkCmd = &cmds.Command{ + Status: cmds.Deprecated, // https://github.com/ipfs/go-ipfs/issues/7936 Helptext: cmds.HelpText{ Tagline: "Deprecated way to remove a link from dag-pb object.", ShortDescription: ` @@ -198,6 +202,7 @@ const ( ) var patchAddLinkCmd = &cmds.Command{ + Status: cmds.Deprecated, // https://github.com/ipfs/go-ipfs/issues/7936 Helptext: cmds.HelpText{ Tagline: "Deprecated way to add a link to a given dag-pb.", ShortDescription: ` diff --git a/core/commands/p2p.go b/core/commands/p2p.go index 77e7ca2b4f8..e9c32626bc4 100644 --- a/core/commands/p2p.go +++ b/core/commands/p2p.go @@ -59,6 +59,7 @@ var resolveTimeout = 10 * time.Second // P2PCmd is the 'ipfs p2p' command var P2PCmd = &cmds.Command{ + Status: cmds.Experimental, Helptext: cmds.HelpText{ Tagline: "Libp2p stream mounting.", ShortDescription: ` @@ -78,6 +79,7 @@ are refined`, } var p2pForwardCmd = &cmds.Command{ + Status: cmds.Experimental, Helptext: cmds.HelpText{ Tagline: "Forward connections to libp2p service.", ShortDescription: ` @@ -179,6 +181,7 @@ func parseIpfsAddr(addr string) (*peer.AddrInfo, error) { } var p2pListenCmd = &cmds.Command{ + Status: cmds.Experimental, Helptext: cmds.HelpText{ Tagline: "Create libp2p service.", ShortDescription: ` @@ -280,6 +283,7 @@ const ( ) var p2pLsCmd = &cmds.Command{ + Status: cmds.Experimental, Helptext: cmds.HelpText{ Tagline: "List active p2p listeners.", }, @@ -343,6 +347,7 @@ const ( ) var p2pCloseCmd = &cmds.Command{ + Status: cmds.Experimental, Helptext: cmds.HelpText{ Tagline: "Stop listening for new connections to forward.", }, @@ -427,6 +432,7 @@ var p2pCloseCmd = &cmds.Command{ // p2pStreamCmd is the 'ipfs p2p stream' command var p2pStreamCmd = &cmds.Command{ + Status: cmds.Experimental, Helptext: cmds.HelpText{ Tagline: "P2P stream management.", ShortDescription: "Create and manage p2p streams", @@ -439,6 +445,7 @@ var p2pStreamCmd = &cmds.Command{ } var p2pStreamLsCmd = &cmds.Command{ + Status: cmds.Experimental, Helptext: cmds.HelpText{ Tagline: "List active p2p streams.", }, @@ -488,6 +495,7 @@ var p2pStreamLsCmd = &cmds.Command{ } var p2pStreamCloseCmd = &cmds.Command{ + Status: cmds.Experimental, Helptext: cmds.HelpText{ Tagline: "Close active p2p stream.", }, diff --git a/core/commands/pubsub.go b/core/commands/pubsub.go index 47d893852af..570f850d097 100644 --- a/core/commands/pubsub.go +++ b/core/commands/pubsub.go @@ -17,6 +17,7 @@ import ( ) var PubsubCmd = &cmds.Command{ + Status: cmds.Experimental, Helptext: cmds.HelpText{ Tagline: "An experimental publish-subscribe system on ipfs.", ShortDescription: ` @@ -46,6 +47,7 @@ type pubsubMessage struct { } var PubsubSubCmd = &cmds.Command{ + Status: cmds.Experimental, Helptext: cmds.HelpText{ Tagline: "Subscribe to messages on a given topic.", ShortDescription: ` @@ -144,6 +146,7 @@ TOPIC AND DATA ENCODING } var PubsubPubCmd = &cmds.Command{ + Status: cmds.Experimental, Helptext: cmds.HelpText{ Tagline: "Publish data to a given pubsub topic.", ShortDescription: ` @@ -199,6 +202,7 @@ HTTP RPC ENCODING } var PubsubLsCmd = &cmds.Command{ + Status: cmds.Experimental, Helptext: cmds.HelpText{ Tagline: "List subscribed topics by name.", ShortDescription: ` @@ -270,6 +274,7 @@ func safeTextListEncoder(req *cmds.Request, w io.Writer, list *stringList) error } var PubsubPeersCmd = &cmds.Command{ + Status: cmds.Experimental, Helptext: cmds.HelpText{ Tagline: "List peers we are currently pubsubbing with.", ShortDescription: ` diff --git a/core/commands/repo.go b/core/commands/repo.go index c4066f50e56..367a6d901da 100644 --- a/core/commands/repo.go +++ b/core/commands/repo.go @@ -222,6 +222,7 @@ Version string The repo version. } var repoFsckCmd = &cmds.Command{ + Status: cmds.Deprecated, // https://github.com/ipfs/go-ipfs/issues/6435 Helptext: cmds.HelpText{ Tagline: "Remove repo lockfiles.", ShortDescription: ` diff --git a/core/commands/unixfs/ls.go b/core/commands/unixfs/ls.go index e5fd4e0c260..ac012b04fe4 100644 --- a/core/commands/unixfs/ls.go +++ b/core/commands/unixfs/ls.go @@ -33,8 +33,9 @@ type LsOutput struct { } var LsCmd = &cmds.Command{ + Status: cmds.Deprecated, // https://github.com/ipfs/go-ipfs/pull/7755 Helptext: cmds.HelpText{ - Tagline: "List directory contents for Unix filesystem objects. Deprecated: Use 'ipfs ls' instead.", + Tagline: "List directory contents for Unix filesystem objects. Deprecated: Use 'ipfs ls' and 'ipfs files ls' instead.", ShortDescription: ` Displays the contents of an IPFS or IPNS object(s) at the given path. diff --git a/core/commands/unixfs/unixfs.go b/core/commands/unixfs/unixfs.go index f1dfabc91e0..cb5c8ddaf32 100644 --- a/core/commands/unixfs/unixfs.go +++ b/core/commands/unixfs/unixfs.go @@ -5,17 +5,12 @@ import ( ) var UnixFSCmd = &cmds.Command{ + Status: cmds.Deprecated, // https://github.com/ipfs/go-ipfs/pull/7755 Helptext: cmds.HelpText{ Tagline: "Interact with IPFS objects representing Unix filesystems.", ShortDescription: ` -'ipfs file' provides a familiar interface to file systems represented -by IPFS objects, which hides ipfs implementation details like layout -objects (e.g. fanout and chunking). -`, - LongDescription: ` -'ipfs file' provides a familiar interface to file systems represented -by IPFS objects, which hides ipfs implementation details like layout -objects (e.g. fanout and chunking). +Old interface to file systems represented by UnixFS. +Superseded by modern alternatives: 'ipfs ls' and 'ipfs files' `, }, diff --git a/core/commands/urlstore.go b/core/commands/urlstore.go index c71229b5a6e..0b7dcbc5f50 100644 --- a/core/commands/urlstore.go +++ b/core/commands/urlstore.go @@ -23,6 +23,7 @@ var urlStoreCmd = &cmds.Command{ } var urlAdd = &cmds.Command{ + Status: cmds.Deprecated, Helptext: cmds.HelpText{ Tagline: "Add URL via urlstore.", LongDescription: ` diff --git a/go.mod b/go.mod index 9e290f9a12f..1fd95dee40d 100644 --- a/go.mod +++ b/go.mod @@ -31,7 +31,7 @@ require ( github.com/ipfs/go-graphsync v0.11.0 github.com/ipfs/go-ipfs-blockstore v1.2.0 github.com/ipfs/go-ipfs-chunker v0.0.5 - github.com/ipfs/go-ipfs-cmds v0.6.0 + github.com/ipfs/go-ipfs-cmds v0.7.0 github.com/ipfs/go-ipfs-exchange-interface v0.1.0 github.com/ipfs/go-ipfs-exchange-offline v0.2.0 github.com/ipfs/go-ipfs-files v0.0.9 diff --git a/go.sum b/go.sum index 71490b133d1..43f65b68404 100644 --- a/go.sum +++ b/go.sum @@ -473,8 +473,8 @@ github.com/ipfs/go-ipfs-blocksutil v0.0.1/go.mod h1:Yq4M86uIOmxmGPUHv/uI7uKqZNtL github.com/ipfs/go-ipfs-chunker v0.0.1/go.mod h1:tWewYK0we3+rMbOh7pPFGDyypCtvGcBFymgY4rSDLAw= github.com/ipfs/go-ipfs-chunker v0.0.5 h1:ojCf7HV/m+uS2vhUGWcogIIxiO5ubl5O57Q7NapWLY8= github.com/ipfs/go-ipfs-chunker v0.0.5/go.mod h1:jhgdF8vxRHycr00k13FM8Y0E+6BoalYeobXmUyTreP8= -github.com/ipfs/go-ipfs-cmds v0.6.0 h1:yAxdowQZzoFKjcLI08sXVNnqVj3jnABbf9smrPQmBsw= -github.com/ipfs/go-ipfs-cmds v0.6.0/go.mod h1:ZgYiWVnCk43ChwoH8hAmI1IRbuVtq3GSTHwtRB/Kqhk= +github.com/ipfs/go-ipfs-cmds v0.7.0 h1:0lEldmB7C83RxIOer38Sv1ob6wIoCAIEOaxiYgcv7wA= +github.com/ipfs/go-ipfs-cmds v0.7.0/go.mod h1:y0bflH6m4g6ary4HniYt98UqbrVnRxmRarzeMdLIUn0= github.com/ipfs/go-ipfs-delay v0.0.0-20181109222059-70721b86a9a8/go.mod h1:8SP1YXK1M1kXuc4KJZINY3TQQ03J2rwBG9QfXmbRPrw= github.com/ipfs/go-ipfs-delay v0.0.1 h1:r/UXYyRcddO6thwOnhiznIAiSvxMECGgtv35Xs1IeRQ= github.com/ipfs/go-ipfs-delay v0.0.1/go.mod h1:8SP1YXK1M1kXuc4KJZINY3TQQ03J2rwBG9QfXmbRPrw= From d02e4aa841e1271362b70c2318b15f6943cc6d1e Mon Sep 17 00:00:00 2001 From: Jorropo Date: Thu, 24 Mar 2022 16:07:08 +0100 Subject: [PATCH 327/414] CI: force running go-ipfs-http-client and go-ipfs-api tests This test is actually testing is the ipfs binary (from the path). Using the go-ipfs-http-client code. But most PR only update the binary. HOWEVER Golang does not check PATH for caching. So as far as golang knows: go-ipfs-http-client is old, it havn't changed, and it doesn't run it. That leads us to this test not running on most important PR. --- .circleci/main.yml | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/.circleci/main.yml b/.circleci/main.yml index 9838b0f4de5..7e87098cf6a 100644 --- a/.circleci/main.yml +++ b/.circleci/main.yml @@ -292,7 +292,7 @@ jobs: - v1-go-api-{{ checksum "~/ipfs/go-ipfs/go-ipfs-api/go.sum" }} - v1-go-api- - run: - command: go test -v ./... + command: go test -count=1 -v ./... working_directory: ~/ipfs/go-ipfs/go-ipfs-api - save_cache: key: v1-go-api-{{ checksum "~/ipfs/go-ipfs/go-ipfs-api/go.sum" }} @@ -318,10 +318,10 @@ jobs: - v1-http-client-{{ checksum "~/ipfs/go-ipfs/go-ipfs-http-client/go.sum" }} - v1-http-client- - run: - name: go test -v ./... + name: go test -count=1 -v ./... command: | export PATH=/tmp/circleci-workspace/bin:$PATH - go test -v ./... + go test -count=1 -v ./... working_directory: ~/ipfs/go-ipfs/go-ipfs-http-client - save_cache: key: v1-http-client-{{ checksum "~/ipfs/go-ipfs/go-ipfs-http-client/go.sum" }} From d13a09a076e97c0ab4fd71a6019c68034605e89f Mon Sep 17 00:00:00 2001 From: Omicron166 <64985125+Omicron166@users.noreply.github.com> Date: Fri, 25 Mar 2022 16:48:16 +0100 Subject: [PATCH 328/414] remove unused import (#8787) --- bin/gencmdref | 1 - 1 file changed, 1 deletion(-) diff --git a/bin/gencmdref b/bin/gencmdref index e8a9ea62e79..0b3140f64f1 100755 --- a/bin/gencmdref +++ b/bin/gencmdref @@ -3,7 +3,6 @@ import os import sys import datetime -import subprocess from subprocess import check_output From d92887086f9c9a4026f8742feada8aaf0aea3530 Mon Sep 17 00:00:00 2001 From: Lucas Molas Date: Sun, 27 Mar 2022 09:11:45 -0300 Subject: [PATCH 329/414] fix(core/commands): do not cache config (#8824) --- cmd/ipfs/main.go | 6 ------ cmd/ipfs/pinmfs.go | 4 ++-- cmd/ipfs/pinmfs_test.go | 2 +- cmd/ipfswatch/main.go | 4 ---- commands/context.go | 26 ++++---------------------- core/commands/cmdenv/env.go | 11 ----------- core/commands/mount_unix.go | 3 ++- core/mock/mock.go | 3 --- repo/fsrepo/fsrepo.go | 16 ---------------- 9 files changed, 9 insertions(+), 66 deletions(-) diff --git a/cmd/ipfs/main.go b/cmd/ipfs/main.go index 11b21c89905..f410559a356 100644 --- a/cmd/ipfs/main.go +++ b/cmd/ipfs/main.go @@ -25,7 +25,6 @@ import ( "github.com/ipfs/go-ipfs-cmds/cli" cmdhttp "github.com/ipfs/go-ipfs-cmds/http" u "github.com/ipfs/go-ipfs-util" - config "github.com/ipfs/go-ipfs/config" logging "github.com/ipfs/go-log" loggables "github.com/libp2p/go-libp2p-loggables" ma "github.com/multiformats/go-multiaddr" @@ -138,7 +137,6 @@ func mainRet() int { // this is so that we can construct the node lazily. return &oldcmds.Context{ ConfigRoot: repoPath, - LoadConfig: loadConfig, ReqLog: &oldcmds.ReqLog{}, Plugins: plugins, ConstructNode: func() (n *core.IpfsNode, err error) { @@ -306,10 +304,6 @@ func getRepoPath(req *cmds.Request) (string, error) { return repoPath, nil } -func loadConfig(path string) (*config.Config, error) { - return fsrepo.ConfigAt(path) -} - // startProfiling begins CPU profiling and returns a `stop` function to be // executed as late as possible. The stop function captures the memprofile. func startProfiling() (func(), error) { diff --git a/cmd/ipfs/pinmfs.go b/cmd/ipfs/pinmfs.go index 5eadef5a7e8..021b0530b96 100644 --- a/cmd/ipfs/pinmfs.go +++ b/cmd/ipfs/pinmfs.go @@ -36,7 +36,7 @@ const defaultRepinInterval = 5 * time.Minute type pinMFSContext interface { Context() context.Context - GetConfigNoCache() (*config.Config, error) + GetConfig() (*config.Config, error) } type pinMFSNode interface { @@ -104,7 +104,7 @@ func pinMFSOnChange(configPollInterval time.Duration, cctx pinMFSContext, node p } // reread the config, which may have changed in the meantime - cfg, err := cctx.GetConfigNoCache() + cfg, err := cctx.GetConfig() if err != nil { select { case errCh <- fmt.Errorf("pinning reading config (%v)", err): diff --git a/cmd/ipfs/pinmfs_test.go b/cmd/ipfs/pinmfs_test.go index 63c8af070ee..2c79c20432c 100644 --- a/cmd/ipfs/pinmfs_test.go +++ b/cmd/ipfs/pinmfs_test.go @@ -24,7 +24,7 @@ func (x *testPinMFSContext) Context() context.Context { return x.ctx } -func (x *testPinMFSContext) GetConfigNoCache() (*config.Config, error) { +func (x *testPinMFSContext) GetConfig() (*config.Config, error) { return x.cfg, x.err } diff --git a/cmd/ipfswatch/main.go b/cmd/ipfswatch/main.go index f810ada12c8..9ffc6f62ea1 100644 --- a/cmd/ipfswatch/main.go +++ b/cmd/ipfswatch/main.go @@ -20,7 +20,6 @@ import ( fsnotify "github.com/fsnotify/fsnotify" files "github.com/ipfs/go-ipfs-files" - config "github.com/ipfs/go-ipfs/config" process "github.com/jbenet/goprocess" homedir "github.com/mitchellh/go-homedir" ) @@ -217,9 +216,6 @@ func IsHidden(path string) bool { func cmdCtx(node *core.IpfsNode, repoPath string) commands.Context { return commands.Context{ ConfigRoot: repoPath, - LoadConfig: func(path string) (*config.Config, error) { - return node.Repo.Config() - }, ConstructNode: func() (*core.IpfsNode, error) { return node, nil }, diff --git a/commands/context.go b/commands/context.go index 984071a05cd..be768f54a12 100644 --- a/commands/context.go +++ b/commands/context.go @@ -26,30 +26,18 @@ type Context struct { Plugins *loader.PluginLoader - config *config.Config - LoadConfig func(path string) (*config.Config, error) - Gateway bool api coreiface.CoreAPI node *core.IpfsNode ConstructNode func() (*core.IpfsNode, error) } -// GetConfig returns the config of the current Command execution -// context. It may load it with the provided function. func (c *Context) GetConfig() (*config.Config, error) { - var err error - if c.config == nil { - if c.LoadConfig == nil { - return nil, errors.New("nil LoadConfig function") - } - c.config, err = c.LoadConfig(c.ConfigRoot) + node, err := c.GetNode() + if err != nil { + return nil, err } - return c.config, err -} - -func (c *Context) GetConfigNoCache() (*config.Config, error) { - return c.LoadConfig(c.ConfigRoot) + return node.Repo.Config() } // GetNode returns the node of the current Command execution @@ -61,12 +49,6 @@ func (c *Context) GetNode() (*core.IpfsNode, error) { return nil, errors.New("nil ConstructNode function") } c.node, err = c.ConstructNode() - if err == nil { - // Pre-load the config from the repo to avoid re-parsing it from disk. - if cfg, err := c.node.Repo.Config(); err != nil { - c.config = cfg - } - } } return c.node, err } diff --git a/core/commands/cmdenv/env.go b/core/commands/cmdenv/env.go index 06d401db4cf..ecce8327857 100644 --- a/core/commands/cmdenv/env.go +++ b/core/commands/cmdenv/env.go @@ -9,7 +9,6 @@ import ( "github.com/ipfs/go-ipfs/core" cmds "github.com/ipfs/go-ipfs-cmds" - config "github.com/ipfs/go-ipfs/config" logging "github.com/ipfs/go-log" coreiface "github.com/ipfs/interface-go-ipfs-core" options "github.com/ipfs/interface-go-ipfs-core/options" @@ -52,16 +51,6 @@ func GetApi(env cmds.Environment, req *cmds.Request) (coreiface.CoreAPI, error) return api, nil } -// GetConfig extracts the config from the environment. -func GetConfig(env cmds.Environment) (*config.Config, error) { - ctx, ok := env.(*commands.Context) - if !ok { - return nil, fmt.Errorf("expected env to be of type %T, got %T", ctx, env) - } - - return ctx.GetConfig() -} - // GetConfigRoot extracts the config root from the environment func GetConfigRoot(env cmds.Environment) (string, error) { ctx, ok := env.(*commands.Context) diff --git a/core/commands/mount_unix.go b/core/commands/mount_unix.go index 1c72c6bd990..bde049c3411 100644 --- a/core/commands/mount_unix.go +++ b/core/commands/mount_unix.go @@ -7,6 +7,7 @@ import ( "fmt" "io" + oldcmds "github.com/ipfs/go-ipfs/commands" cmdenv "github.com/ipfs/go-ipfs/core/commands/cmdenv" nodeMount "github.com/ipfs/go-ipfs/fuse/node" @@ -81,7 +82,7 @@ baz cmds.StringOption(mountIPNSPathOptionName, "n", "The path where IPNS should be mounted."), }, Run: func(req *cmds.Request, res cmds.ResponseEmitter, env cmds.Environment) error { - cfg, err := cmdenv.GetConfig(env) + cfg, err := env.(*oldcmds.Context).GetConfig() if err != nil { return err } diff --git a/core/mock/mock.go b/core/mock/mock.go index 65c028ac5e8..154917ab45a 100644 --- a/core/mock/mock.go +++ b/core/mock/mock.go @@ -69,9 +69,6 @@ func MockCmdsCtx() (commands.Context, error) { return commands.Context{ ConfigRoot: "/tmp/.mockipfsconfig", - LoadConfig: func(path string) (*config.Config, error) { - return &conf, nil - }, ConstructNode: func() (*core.IpfsNode, error) { return node, nil }, diff --git a/repo/fsrepo/fsrepo.go b/repo/fsrepo/fsrepo.go index 3e428ac4cff..7ec0e0ab89a 100644 --- a/repo/fsrepo/fsrepo.go +++ b/repo/fsrepo/fsrepo.go @@ -205,22 +205,6 @@ func checkInitialized(path string) error { return nil } -// ConfigAt returns an error if the FSRepo at the given path is not -// initialized. This function allows callers to read the config file even when -// another process is running and holding the lock. -func ConfigAt(repoPath string) (*config.Config, error) { - - // packageLock must be held to ensure that the Read is atomic. - packageLock.Lock() - defer packageLock.Unlock() - - configFilename, err := config.Filename(repoPath) - if err != nil { - return nil, err - } - return serialize.Load(configFilename) -} - // configIsInitialized returns true if the repo is initialized at // provided |path|. func configIsInitialized(path string) bool { From d6de97b417def4feaf1382d0ff423e22fd2ff08b Mon Sep 17 00:00:00 2001 From: Marcin Rataj Date: Mon, 28 Mar 2022 16:31:36 +0200 Subject: [PATCH 330/414] docs: gateway.md (#8825) Adds link to relevant pages at docs.ipfs.io --- docs/gateway.md | 27 +++++++++++++++++++-------- 1 file changed, 19 insertions(+), 8 deletions(-) diff --git a/docs/gateway.md b/docs/gateway.md index fcfbed36595..0abcb2c0005 100644 --- a/docs/gateway.md +++ b/docs/gateway.md @@ -2,19 +2,30 @@ An IPFS Gateway acts as a bridge between traditional web browsers and IPFS. Through the gateway, users can browse files and websites stored in IPFS as if -they were stored in a traditional web server. +they were stored in a traditional web server. -By default, go-ipfs nodes run a gateway at `http://127.0.0.1:8080/`. +[More about Gateways](https://docs.ipfs.io/concepts/ipfs-gateway/) and [addressing IPFS on the web](https://docs.ipfs.io/how-to/address-ipfs-on-web/). -We also provide a public gateway at `https://ipfs.io`. If you've ever seen a -link in the form `https://ipfs.io/ipfs/Qm...`, that's being served from *our* -gateway. +### Local gateway + +By default, go-ipfs nodes run +a [path gateway](https://docs.ipfs.io/how-to/address-ipfs-on-web/#path-gateway) at `http://127.0.0.1:8080/` +and a [subdomain gateway](https://docs.ipfs.io/how-to/address-ipfs-on-web/#subdomain-gateway) at `http://localhost:8080/` + +Additional listening addresses and gateway behaviors can be set in the [config](#configuration) file. + +### Public gateways + +Protocol Labs provides a public gateway at `https://ipfs.io` (path) and `https://dweb.link` (subdomain). +If you've ever seen a link in the form `https://ipfs.io/ipfs/Qm...`, that's being served from *our* gateway. + +There is a list of third-party public gateways provided by the IPFS community at https://ipfs.github.io/public-gateway-checker/ ## Configuration -The gateway's configuration options are (briefly) described in the +The `Gateway.*` configuration options are (briefly) described in the [config](https://github.com/ipfs/go-ipfs/blob/master/docs/config.md#gateway) -documentation. +documentation, including a list of common [gateway recipes](https://github.com/ipfs/go-ipfs/blob/master/docs/config.md#gateway-recipes). ### Debug The gateway's log level can be changed with this command: @@ -40,7 +51,7 @@ for details ## Static Websites You can use an IPFS gateway to serve static websites at a custom domain using -[DNSLink](https://dnslink.io). See [Example: IPFS +[DNSLink](https://docs.ipfs.io/concepts/glossary#dnslink). See [Example: IPFS Gateway](https://dnslink.io/#example-ipfs-gateway) for instructions. ## Filenames From 46c3689b7506c8166f8f96f42d597ad6a816257f Mon Sep 17 00:00:00 2001 From: Gus Eggert Date: Wed, 30 Mar 2022 11:07:26 -0400 Subject: [PATCH 331/414] feat: re-enable docker sharness tests (#8808) The Docker sharness tests were disabled years ago when go-ipfs moved from Travis to CircleCI. This makes the tweaks necessary to re-enable them. The Docker image has since moved to be based on BusyBox which doesn't have the requisite wget version for the existing tests to work, so this adds some functionality to the pollEndpoint program to support polling HTTP endpoints as well. --- .circleci/main.yml | 2 +- .dockerignore | 2 + test/dependencies/pollEndpoint/main.go | 72 ++++++++++++++++++++++++-- test/ipfs-test-lib.sh | 7 +-- test/sharness/t0300-docker-image.sh | 23 ++++---- test/sharness/t0301-docker-migrate.sh | 14 ++--- 6 files changed, 89 insertions(+), 31 deletions(-) diff --git a/.circleci/main.yml b/.circleci/main.yml index 7e87098cf6a..4c01be86fe3 100644 --- a/.circleci/main.yml +++ b/.circleci/main.yml @@ -154,7 +154,7 @@ jobs: working_directory: ~/ipfs/go-ipfs environment: <<: *default_environment - TEST_NO_DOCKER: 1 + TEST_NO_DOCKER: 0 TEST_NO_FUSE: 1 TEST_VERBOSE: 1 steps: diff --git a/.dockerignore b/.dockerignore index 10dd5fd886d..1e149a2bddb 100644 --- a/.dockerignore +++ b/.dockerignore @@ -5,6 +5,8 @@ Dockerfile.fast !.git/refs/ !.git/packed-refs test/sharness/lib/sharness/ +test/sharness/trash* +rb-pinning-service-api/ # The Docker client might not be running on Linux # so delete any compiled binaries diff --git a/test/dependencies/pollEndpoint/main.go b/test/dependencies/pollEndpoint/main.go index 7eadcd3f702..f3c19dbaf4a 100644 --- a/test/dependencies/pollEndpoint/main.go +++ b/test/dependencies/pollEndpoint/main.go @@ -2,7 +2,11 @@ package main import ( + "context" "flag" + "io" + "net" + "net/http" "os" "time" @@ -15,6 +19,8 @@ var ( host = flag.String("host", "/ip4/127.0.0.1/tcp/5001", "the multiaddr host to dial on") tries = flag.Int("tries", 10, "how many tries to make before failing") timeout = flag.Duration("tout", time.Second, "how long to wait between attempts") + httpURL = flag.String("http-url", "", "HTTP URL to fetch") + httpOut = flag.Bool("http-out", false, "Print the HTTP response body to stdout") verbose = flag.Bool("v", false, "verbose logging") ) @@ -37,18 +43,76 @@ func main() { start := time.Now() log.Debugf("starting at %s, tries: %d, timeout: %s, addr: %s", start, *tries, *timeout, addr) - for *tries > 0 { + connTries := *tries + for connTries > 0 { c, err := manet.Dial(addr) if err == nil { log.Debugf("ok - endpoint reachable with %d tries remaining, took %s", *tries, time.Since(start)) c.Close() - os.Exit(0) + break } log.Debug("connect failed: ", err) time.Sleep(*timeout) - *tries-- + connTries-- } - log.Error("failed.") + if err != nil { + goto Fail + } + + if *httpURL != "" { + dialer := &connDialer{addr: addr} + httpClient := http.Client{Transport: &http.Transport{ + DialContext: dialer.DialContext, + }} + reqTries := *tries + for reqTries > 0 { + try := (*tries - reqTries) + 1 + log.Debugf("trying HTTP req %d: '%s'", try, *httpURL) + if tryHTTPGet(&httpClient, *httpURL) { + log.Debugf("HTTP req %d to '%s' succeeded", try, *httpURL) + goto Success + } + log.Debugf("HTTP req %d to '%s' failed", try, *httpURL) + time.Sleep(*timeout) + reqTries-- + } + goto Fail + } + +Success: + os.Exit(0) + +Fail: + log.Error("failed") os.Exit(1) } + +func tryHTTPGet(client *http.Client, url string) bool { + resp, err := client.Get(*httpURL) + if resp != nil && resp.Body != nil { + defer resp.Body.Close() + } + if err != nil { + return false + } + if resp.StatusCode != http.StatusOK { + return false + } + if *httpOut { + _, err := io.Copy(os.Stdout, resp.Body) + if err != nil { + panic(err) + } + } + + return true +} + +type connDialer struct { + addr ma.Multiaddr +} + +func (d connDialer) DialContext(ctx context.Context, network, addr string) (net.Conn, error) { + return (&manet.Dialer{}).DialContext(ctx, d.addr) +} diff --git a/test/ipfs-test-lib.sh b/test/ipfs-test-lib.sh index 38c62d33177..960cf7caa86 100644 --- a/test/ipfs-test-lib.sh +++ b/test/ipfs-test-lib.sh @@ -62,12 +62,7 @@ docker_run() { # This takes a docker ID and a command as arguments docker_exec() { - if test "$CIRCLE" = 1 - then - sudo lxc-attach -n "$(docker inspect --format '{{.Id}}' $1)" -- /bin/bash -c "$2" - else - docker exec -t "$1" /bin/bash -c "$2" - fi + docker exec -t "$1" /bin/sh -c "$2" } # This takes a docker ID as argument diff --git a/test/sharness/t0300-docker-image.sh b/test/sharness/t0300-docker-image.sh index 3d8f573f2f5..2a25dd28406 100755 --- a/test/sharness/t0300-docker-image.sh +++ b/test/sharness/t0300-docker-image.sh @@ -29,30 +29,28 @@ TEST_TESTS_DIR=$(dirname "$TEST_SCRIPTS_DIR") APP_ROOT_DIR=$(dirname "$TEST_TESTS_DIR") test_expect_success "docker image build succeeds" ' - docker_build "$TEST_TESTS_DIR/../Dockerfile" "$APP_ROOT_DIR" >actual || + docker_build "$TEST_TESTS_DIR/../Dockerfile" "$APP_ROOT_DIR" >build-actual || test_fsh echo "TEST_TESTS_DIR: $TEST_TESTS_DIR" || test_fsh echo "APP_ROOT_DIR : $APP_ROOT_DIR" || - test_fsh cat actual + test_fsh cat build-actual ' test_expect_success "docker image build output looks good" ' - SUCCESS_LINE=$(egrep "^Successfully built" actual) && + SUCCESS_LINE=$(egrep "^Successfully built" build-actual) && IMAGE_ID=$(expr "$SUCCESS_LINE" : "^Successfully built \(.*\)") || - test_fsh cat actual + test_fsh cat build-actual ' test_expect_success "docker image runs" ' - DOC_ID=$(docker_run "$IMAGE_ID") + DOC_ID=$(docker run -d -p 127.0.0.1:5001:5001 -p 127.0.0.1:8080:8080 "$IMAGE_ID") ' -test_expect_success "docker image gateway is up" ' - docker_exec "$DOC_ID" "wget --retry-connrefused --waitretry=1 --timeout=30 -t 30 \ - -q -O - http://localhost:8080/version >/dev/null" +test_expect_success "docker container gateway is up" ' + pollEndpoint -host=/ip4/127.0.0.1/tcp/8080 -http-url http://localhost:8080/api/v0/version -v -tries 30 -tout 1s ' -test_expect_success "docker image API is up" ' - docker_exec "$DOC_ID" "wget --retry-connrefused --waitretry=1 --timeout=30 -t 30 \ - -q -O - http://localhost:5001/api/v0/version >/dev/null" +test_expect_success "docker container API is up" ' + pollEndpoint -host=/ip4/127.0.0.1/tcp/5001 -http-url http://localhost:5001/version -v -tries 30 -tout 1s ' test_expect_success "simple ipfs add/cat can be run in docker container" ' @@ -63,8 +61,7 @@ test_expect_success "simple ipfs add/cat can be run in docker container" ' ' read testcode <actual ; \ + pollEndpoint -host=/ip4/127.0.0.1/tcp/5001 -http-url http://localhost:5001/version -http-out | grep Commit | cut -d" " -f2 >actual ; \ test -s actual ; \ docker exec -i "$DOC_ID" ipfs version --enc json \ | sed 's/^.*"Commit":"\\\([^"]*\\\)".*$/\\\1/g' >expected ; \ diff --git a/test/sharness/t0301-docker-migrate.sh b/test/sharness/t0301-docker-migrate.sh index 4f47310d181..4fb9ab155e4 100755 --- a/test/sharness/t0301-docker-migrate.sh +++ b/test/sharness/t0301-docker-migrate.sh @@ -32,6 +32,10 @@ test_expect_success "docker image build succeeds" ' test_init_ipfs +test_expect_success "configure migration sources" ' + ipfs config --json Migration.DownloadSources "[\"http://127.0.0.1:17233\"]" +' + test_expect_success "make repo be version 4" ' echo 4 > "$IPFS_PATH/version" ' @@ -43,17 +47,13 @@ test_expect_success "setup http response" ' echo "v1.1.1" >> vers_resp ' -pretend_server() { - socat tcp-listen:17233,fork,bind=127.0.0.1,reuseaddr 'SYSTEM:cat vers_resp'!!STDERR & -} - test_expect_success "startup fake dists server" ' - pretend_server > dist_serv_out & + ( socat tcp-listen:17233,fork,bind=127.0.0.1,reuseaddr "SYSTEM:cat vers_resp"!!STDERR 2> dist_serv_out ) & echo $! > netcat_pid ' test_expect_success "docker image runs" ' - DOC_ID=$(docker run -d -v "$IPFS_PATH":/data/ipfs --net=host -e IPFS_DIST_PATH="http://localhost:17233" "$IMAGE_ID" --migrate) + DOC_ID=$(docker run -d -v "$IPFS_PATH":/data/ipfs --net=host "$IMAGE_ID") ' test_expect_success "docker container tries to pull migrations from netcat" ' @@ -74,7 +74,7 @@ test_expect_success "kill the net cat" ' ' test_expect_success "correct version was requested" ' - grep "/fs-repo-migrations/v1.1.1/fs-repo-migrations_v1.1.1_linux-amd64.tar.gz" dist_serv_out > /dev/null + grep "/fs-repo-6-to-7/v1.1.1/fs-repo-6-to-7_v1.1.1_linux-amd64.tar.gz" dist_serv_out > /dev/null ' test_done From 5fa556945e2a9733f39e1bfcc242cba4c31c070b Mon Sep 17 00:00:00 2001 From: Marcin Rataj Date: Fri, 1 Apr 2022 18:12:46 +0200 Subject: [PATCH 332/414] fix(gw): validate requested CAR version (#8835) * fix(gw): validate requested CAR version This adds validation of 'application/vnd.ipld.car;version=n' passed in the Accept header by HTTP clients to align Gateway behavior with the spec submitted to IANA. * test: fix comment in test/sharness/t0118-gateway-car.sh Co-authored-by: Gus Eggert Co-authored-by: Gus Eggert --- core/corehttp/gateway_handler.go | 30 ++++++++++++++++++---------- core/corehttp/gateway_handler_car.go | 12 ++++++++++- test/sharness/t0118-gateway-car.sh | 15 ++++++++++++++ 3 files changed, 46 insertions(+), 11 deletions(-) diff --git a/core/corehttp/gateway_handler.go b/core/corehttp/gateway_handler.go index eca2efff610..6d90dd0080a 100644 --- a/core/corehttp/gateway_handler.go +++ b/core/corehttp/gateway_handler.go @@ -5,6 +5,7 @@ import ( "fmt" "html/template" "io" + "mime" "net/http" "net/url" "os" @@ -348,7 +349,11 @@ func (i *gatewayHandler) getOrHeadHandler(w http.ResponseWriter, r *http.Request } // Detect when explicit Accept header or ?format parameter are present - responseFormat := customResponseFormat(r) + responseFormat, formatParams, err := customResponseFormat(r) + if err != nil { + webError(w, "error while processing the Accept header", err, http.StatusBadRequest) + return + } // Finish early if client already has matching Etag if r.Header.Get("If-None-Match") == getEtag(r, resolvedPath.Cid()) { @@ -389,9 +394,10 @@ func (i *gatewayHandler) getOrHeadHandler(w http.ResponseWriter, r *http.Request logger.Debugw("serving raw block", "path", contentPath) i.serveRawBlock(w, r, resolvedPath.Cid(), contentPath, begin) return - case "application/vnd.ipld.car", "application/vnd.ipld.car; version=1": + case "application/vnd.ipld.car": logger.Debugw("serving car stream", "path", contentPath) - i.serveCar(w, r, resolvedPath.Cid(), contentPath, begin) + carVersion := formatParams["version"] + i.serveCar(w, r, resolvedPath.Cid(), contentPath, carVersion, begin) return default: // catch-all for unsuported application/vnd.* err := fmt.Errorf("unsupported format %q", responseFormat) @@ -761,8 +767,8 @@ func getFilename(contentPath ipath.Path) string { func getEtag(r *http.Request, cid cid.Cid) string { prefix := `"` suffix := `"` - responseFormat := customResponseFormat(r) - if responseFormat != "" { + responseFormat, _, err := customResponseFormat(r) + if err == nil && responseFormat != "" { // application/vnd.ipld.foo → foo f := responseFormat[strings.LastIndex(responseFormat, ".")+1:] // Etag: "cid.foo" (gives us nice compression together with Content-Disposition in block (raw) and car responses) @@ -773,14 +779,14 @@ func getEtag(r *http.Request, cid cid.Cid) string { } // return explicit response format if specified in request as query parameter or via Accept HTTP header -func customResponseFormat(r *http.Request) string { +func customResponseFormat(r *http.Request) (mediaType string, params map[string]string, err error) { if formatParam := r.URL.Query().Get("format"); formatParam != "" { // translate query param to a content type switch formatParam { case "raw": - return "application/vnd.ipld.raw" + return "application/vnd.ipld.raw", nil, nil case "car": - return "application/vnd.ipld.car" + return "application/vnd.ipld.car", nil, nil } } // Browsers and other user agents will send Accept header with generic types like: @@ -789,10 +795,14 @@ func customResponseFormat(r *http.Request) string { for _, accept := range r.Header.Values("Accept") { // respond to the very first ipld content type if strings.HasPrefix(accept, "application/vnd.ipld") { - return accept + mediatype, params, err := mime.ParseMediaType(accept) + if err != nil { + return "", nil, err + } + return mediatype, params, nil } } - return "" + return "", nil, nil } func (i *gatewayHandler) searchUpTreeFor404(r *http.Request, contentPath ipath.Path) (ipath.Resolved, string, error) { diff --git a/core/corehttp/gateway_handler_car.go b/core/corehttp/gateway_handler_car.go index 5f0f2117fc7..c6587e564f4 100644 --- a/core/corehttp/gateway_handler_car.go +++ b/core/corehttp/gateway_handler_car.go @@ -2,6 +2,7 @@ package corehttp import ( "context" + "fmt" "net/http" "time" @@ -14,10 +15,19 @@ import ( ) // serveCar returns a CAR stream for specific DAG+selector -func (i *gatewayHandler) serveCar(w http.ResponseWriter, r *http.Request, rootCid cid.Cid, contentPath ipath.Path, begin time.Time) { +func (i *gatewayHandler) serveCar(w http.ResponseWriter, r *http.Request, rootCid cid.Cid, contentPath ipath.Path, carVersion string, begin time.Time) { ctx, cancel := context.WithCancel(r.Context()) defer cancel() + switch carVersion { + case "": // noop, client does not care about version + case "1": // noop, we support this + default: + err := fmt.Errorf("only version=1 is supported") + webError(w, "unsupported CAR version", err, http.StatusBadRequest) + return + } + // Set Content-Disposition name := rootCid.String() + ".car" setContentDispositionHeader(w, name, "attachment") diff --git a/test/sharness/t0118-gateway-car.sh b/test/sharness/t0118-gateway-car.sh index 9cdb5aec522..796c3c33947 100755 --- a/test/sharness/t0118-gateway-car.sh +++ b/test/sharness/t0118-gateway-car.sh @@ -51,10 +51,25 @@ test_launch_ipfs_daemon_without_network # explicit version=1 test_expect_success "GET for application/vnd.ipld.raw version=1 returns a CARv1 stream" ' ipfs dag import test-dag.car && + curl -sX GET -H "Accept: application/vnd.ipld.car;version=1" "http://127.0.0.1:$GWAY_PORT/ipfs/$ROOT_DIR_CID/subdir/ascii.txt" -o gateway-header-v1.car && + test_cmp deterministic.car gateway-header-v1.car + ' + + # explicit version=1 with whitepace + test_expect_success "GET for application/vnd.ipld.raw version=1 returns a CARv1 stream (with whitespace)" ' + ipfs dag import test-dag.car && curl -sX GET -H "Accept: application/vnd.ipld.car; version=1" "http://127.0.0.1:$GWAY_PORT/ipfs/$ROOT_DIR_CID/subdir/ascii.txt" -o gateway-header-v1.car && test_cmp deterministic.car gateway-header-v1.car ' + # explicit version=2 + test_expect_success "GET for application/vnd.ipld.raw version=2 returns HTTP 400 Bad Request error" ' + curl -svX GET -H "Accept: application/vnd.ipld.car;version=2" "http://127.0.0.1:$GWAY_PORT/ipfs/$ROOT_DIR_CID/subdir/ascii.txt" > curl_output 2>&1 && + cat curl_output && + grep "400 Bad Request" curl_output && + grep "unsupported CAR version" curl_output + ' + # GET unixfs directory as a CAR with DAG and some selector # TODO: this is basic test for "full" selector, we will add support for custom ones in https://github.com/ipfs/go-ipfs/issues/8769 From e36f28d58190e071b652009b4c2fa1b082f28e68 Mon Sep 17 00:00:00 2001 From: Jorropo Date: Fri, 1 Apr 2022 00:41:33 +0200 Subject: [PATCH 333/414] chore: bump go-ipld-format v0.4.0 and fix related sharness tests --- go.mod | 4 ++-- go.sum | 7 ++++--- test/sharness/t0050-block.sh | 4 ++-- test/sharness/t0054-dag-car-import-export.sh | 4 ++-- test/sharness/t0080-repo.sh | 2 +- test/sharness/t0081-repo-pinning.sh | 2 +- test/sharness/t0085-pins.sh | 4 ++-- 7 files changed, 14 insertions(+), 13 deletions(-) diff --git a/go.mod b/go.mod index 1fd95dee40d..33f254478cf 100644 --- a/go.mod +++ b/go.mod @@ -42,7 +42,7 @@ require ( github.com/ipfs/go-ipfs-routing v0.2.1 github.com/ipfs/go-ipfs-util v0.0.2 github.com/ipfs/go-ipld-cbor v0.0.5 - github.com/ipfs/go-ipld-format v0.3.0 + github.com/ipfs/go-ipld-format v0.4.0 github.com/ipfs/go-ipld-git v0.1.1 github.com/ipfs/go-ipld-legacy v0.1.0 github.com/ipfs/go-ipns v0.1.2 @@ -57,7 +57,7 @@ require ( github.com/ipfs/go-unixfs v0.3.1 github.com/ipfs/go-unixfsnode v1.1.3 github.com/ipfs/go-verifcid v0.0.1 - github.com/ipfs/interface-go-ipfs-core v0.6.0 + github.com/ipfs/interface-go-ipfs-core v0.6.2 github.com/ipfs/tar-utils v0.0.2 github.com/ipld/go-car v0.3.2 github.com/ipld/go-codec-dagpb v1.3.0 diff --git a/go.sum b/go.sum index 43f65b68404..aa6b4a17159 100644 --- a/go.sum +++ b/go.sum @@ -519,8 +519,9 @@ github.com/ipfs/go-ipld-cbor v0.0.5/go.mod h1:BkCduEx3XBCO6t2Sfo5BaHzuok7hbhdMm9 github.com/ipfs/go-ipld-format v0.0.1/go.mod h1:kyJtbkDALmFHv3QR6et67i35QzO3S0dCDnkOJhcZkms= github.com/ipfs/go-ipld-format v0.0.2/go.mod h1:4B6+FM2u9OJ9zCV+kSbgFAZlOrv1Hqbf0INGQgiKf9k= github.com/ipfs/go-ipld-format v0.2.0/go.mod h1:3l3C1uKoadTPbeNfrDi+xMInYKlx2Cvg1BuydPSdzQs= -github.com/ipfs/go-ipld-format v0.3.0 h1:Mwm2oRLzIuUwEPewWAWyMuuBQUsn3awfFEYVb8akMOQ= github.com/ipfs/go-ipld-format v0.3.0/go.mod h1:co/SdBE8h99968X0hViiw1MNlh6fvxxnHpvVLnH7jSM= +github.com/ipfs/go-ipld-format v0.4.0 h1:yqJSaJftjmjc9jEOFYlpkwOLVKv68OD27jFLlSghBlQ= +github.com/ipfs/go-ipld-format v0.4.0/go.mod h1:co/SdBE8h99968X0hViiw1MNlh6fvxxnHpvVLnH7jSM= github.com/ipfs/go-ipld-git v0.1.1 h1:TWGnZjS0htmEmlMFEkA3ogrNCqWjIxwr16x1OsdhG+Y= github.com/ipfs/go-ipld-git v0.1.1/go.mod h1:+VyMqF5lMcJh4rwEppV0e6g4nCCHXThLYYDpKUkJubI= github.com/ipfs/go-ipld-legacy v0.1.0 h1:wxkkc4k8cnvIGIjPO0waJCe7SHEyFgl+yQdafdjGrpA= @@ -577,8 +578,8 @@ github.com/ipfs/go-unixfsnode v1.1.3/go.mod h1:ZZxUM5wXBC+G0Co9FjrYTOm+UlhZTjxLf github.com/ipfs/go-verifcid v0.0.1 h1:m2HI7zIuR5TFyQ1b79Da5N9dnnCP1vcu2QqawmWlK2E= github.com/ipfs/go-verifcid v0.0.1/go.mod h1:5Hrva5KBeIog4A+UpqlaIU+DEstipcJYQQZc0g37pY0= github.com/ipfs/interface-go-ipfs-core v0.4.0/go.mod h1:UJBcU6iNennuI05amq3FQ7g0JHUkibHFAfhfUIy927o= -github.com/ipfs/interface-go-ipfs-core v0.6.0 h1:a43QNc3CNayuMjZM+4D9SeyiSF2nKxBaG8qbCAelMNs= -github.com/ipfs/interface-go-ipfs-core v0.6.0/go.mod h1:h3NuO3wzv2KuKazt0zDF2/i8AFRqiKHusyh5DUQQdPA= +github.com/ipfs/interface-go-ipfs-core v0.6.2 h1:nnkq9zhb5O8lPzkZeynEymc83RqkTRqfYH4x5JNUkT4= +github.com/ipfs/interface-go-ipfs-core v0.6.2/go.mod h1:h3NuO3wzv2KuKazt0zDF2/i8AFRqiKHusyh5DUQQdPA= github.com/ipfs/tar-utils v0.0.2 h1:UNgHB4x/PPzbMkmJi+7EqC9LNMPDztOVSnx1HAqSNg4= github.com/ipfs/tar-utils v0.0.2/go.mod h1:4qlnRWgTVljIMhSG2SqRYn66NT+3wrv/kZt9V+eqxDM= github.com/ipld/go-car v0.3.2 h1:V9wt/80FNfbMRWSD98W5br6fyjUAyVgI2lDOTZX16Lg= diff --git a/test/sharness/t0050-block.sh b/test/sharness/t0050-block.sh index 4e809876b73..2b58c7efe1a 100755 --- a/test/sharness/t0050-block.sh +++ b/test/sharness/t0050-block.sh @@ -134,9 +134,9 @@ test_expect_success "multi-block 'ipfs block rm '" ' ' test_expect_success "multi-block 'ipfs block rm ' output looks good" ' - echo "cannot remove $RANDOMHASH: $RANDOMHASH not found" >> expect_mixed_rm && + echo "cannot remove $RANDOMHASH: ipld: could not find $RANDOMHASH" >> expect_mixed_rm && echo "removed $TESTHASH" >> expect_mixed_rm && - echo "cannot remove $RANDOMHASH: $RANDOMHASH not found" >> expect_mixed_rm && + echo "cannot remove $RANDOMHASH: ipld: could not find $RANDOMHASH" >> expect_mixed_rm && echo "Error: some blocks not removed" >> expect_mixed_rm test_cmp actual_mixed_rm expect_mixed_rm ' diff --git a/test/sharness/t0054-dag-car-import-export.sh b/test/sharness/t0054-dag-car-import-export.sh index d1ec0d2c52b..d795c151d8e 100755 --- a/test/sharness/t0054-dag-car-import-export.sh +++ b/test/sharness/t0054-dag-car-import-export.sh @@ -67,7 +67,7 @@ EOE # Explainer: # naked_root_import_json_expected output is produced by dag import of combined_naked_roots_genesis_and_128.car # executed when roots are already present in the repo - thus the BlockCount=0 - # (if blocks were not present in the repo, blockstore: block not found would be returned) + # (if blocks were not present in the repo, ipld: could not find would be returned) cat >naked_root_import_json_expected < offline_fetch_error_expected +echo "Error: block was not found locally (offline): ipld: could not find QmYwAPJXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX (currently offline, perhaps retry after attaching to the network)" > offline_fetch_error_expected test_expect_success "basic offline export of nonexistent cid" ' ! ipfs dag export QmYwAPJXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX 2> offline_fetch_error_actual >/dev/null ' diff --git a/test/sharness/t0080-repo.sh b/test/sharness/t0080-repo.sh index 521b8db43d2..2cdaac474b1 100755 --- a/test/sharness/t0080-repo.sh +++ b/test/sharness/t0080-repo.sh @@ -64,7 +64,7 @@ test_expect_success "'ipfs repo gc --silent' succeeds (no output)" ' ipfs repo gc --silent >gc_out_empty && test_cmp /dev/null gc_out_empty && test_must_fail ipfs cat "$HASH2" 2>err_expected1 && - grep "Error: $HASH2 not found" err_expected1 + grep "Error: ipld: could not find $HASH2" err_expected1 ' test_kill_ipfs_daemon diff --git a/test/sharness/t0081-repo-pinning.sh b/test/sharness/t0081-repo-pinning.sh index 656698fae06..030f3fa3d06 100755 --- a/test/sharness/t0081-repo-pinning.sh +++ b/test/sharness/t0081-repo-pinning.sh @@ -238,7 +238,7 @@ test_expect_success "some are no longer there" ' test_launch_ipfs_daemon_without_network test_expect_success "recursive pin fails without objects" ' test_must_fail ipfs pin add -r "$HASH_DIR1" 2>err_expected8 && - grep "not found" err_expected8 || + grep "ipld: could not find" err_expected8 || test_fsh cat err_expected8 ' diff --git a/test/sharness/t0085-pins.sh b/test/sharness/t0085-pins.sh index 90f3b0d8acd..c83c513682b 100755 --- a/test/sharness/t0085-pins.sh +++ b/test/sharness/t0085-pins.sh @@ -115,7 +115,7 @@ test_pins_error_reporting() { test_expect_success "'ipfs pin add $PIN_ARGS' on non-existent hash should fail" ' test_must_fail ipfs pin add $PIN_ARGS $RANDOM_HASH 2> err && - grep -q "not found" err + grep -q "ipld: could not find" err ' } @@ -147,7 +147,7 @@ test_pin_dag() { test_expect_success "pin file, should fail" ' test_must_fail ipfs pin add --recursive=true $HASH 2> err && cat err && - grep -q "not found" err + grep -q "ipld: could not find" err ' } From f72110c2d8676ec770722aad44547d6169216eec Mon Sep 17 00:00:00 2001 From: Jorropo Date: Fri, 1 Apr 2022 01:18:05 +0200 Subject: [PATCH 334/414] fix: use error instead of strings as error in blockstoreutil/remove --- blocks/blockstoreutil/remove.go | 27 +++++++++++++------------ core/commands/block.go | 35 ++++++++++++++++++++++++++++----- core/coreapi/block.go | 6 ++---- 3 files changed, 46 insertions(+), 22 deletions(-) diff --git a/blocks/blockstoreutil/remove.go b/blocks/blockstoreutil/remove.go index b4e944fdfcb..992da720b73 100644 --- a/blocks/blockstoreutil/remove.go +++ b/blocks/blockstoreutil/remove.go @@ -3,6 +3,7 @@ package blockstoreutil import ( "context" + "errors" "fmt" "io" @@ -13,14 +14,14 @@ import ( ) // RemovedBlock is used to represent the result of removing a block. -// If a block was removed successfully, then the Error string will be -// empty. If a block could not be removed, then Error will contain the +// If a block was removed successfully, then the Error will be empty. +// If a block could not be removed, then Error will contain the // reason the block could not be removed. If the removal was aborted // due to a fatal error, Hash will be empty, Error will contain the // reason, and no more results will be sent. type RemovedBlock struct { - Hash string `json:",omitempty"` - Error string `json:",omitempty"` + Hash string + Error error } // RmBlocksOpts is used to wrap options for RmBlocks(). @@ -51,17 +52,17 @@ func RmBlocks(ctx context.Context, blocks bs.GCBlockstore, pins pin.Pinner, cids // remove this sometime in the future. has, err := blocks.Has(ctx, c) if err != nil { - out <- &RemovedBlock{Hash: c.String(), Error: err.Error()} + out <- &RemovedBlock{Hash: c.String(), Error: err} continue } if !has && !opts.Force { - out <- &RemovedBlock{Hash: c.String(), Error: format.ErrNotFound{Cid: c}.Error()} + out <- &RemovedBlock{Hash: c.String(), Error: format.ErrNotFound{Cid: c}} continue } err = blocks.DeleteBlock(ctx, c) if err != nil { - out <- &RemovedBlock{Hash: c.String(), Error: err.Error()} + out <- &RemovedBlock{Hash: c.String(), Error: err} } else if !opts.Quiet { out <- &RemovedBlock{Hash: c.String()} } @@ -79,7 +80,7 @@ func FilterPinned(ctx context.Context, pins pin.Pinner, out chan<- interface{}, stillOkay := make([]cid.Cid, 0, len(cids)) res, err := pins.CheckIfPinned(ctx, cids...) if err != nil { - out <- &RemovedBlock{Error: fmt.Sprintf("pin check failed: %s", err)} + out <- &RemovedBlock{Error: fmt.Errorf("pin check failed: %w", err)} return nil } for _, r := range res { @@ -88,7 +89,7 @@ func FilterPinned(ctx context.Context, pins pin.Pinner, out chan<- interface{}, } else { out <- &RemovedBlock{ Hash: r.Key.String(), - Error: r.String(), + Error: errors.New(r.String()), } } } @@ -107,11 +108,11 @@ func ProcRmOutput(next func() (interface{}, error), sout io.Writer, serr io.Writ return err } r := res.(*RemovedBlock) - if r.Hash == "" && r.Error != "" { - return fmt.Errorf("aborted: %s", r.Error) - } else if r.Error != "" { + if r.Hash == "" && r.Error != nil { + return fmt.Errorf("aborted: %w", r.Error) + } else if r.Error != nil { someFailed = true - fmt.Fprintf(serr, "cannot remove %s: %s\n", r.Hash, r.Error) + fmt.Fprintf(serr, "cannot remove %s: %v\n", r.Hash, r.Error) } else { fmt.Fprintf(sout, "removed %s\n", r.Hash) } diff --git a/core/commands/block.go b/core/commands/block.go index 4cfe1fc6ef9..945dbf64f80 100644 --- a/core/commands/block.go +++ b/core/commands/block.go @@ -8,7 +8,6 @@ import ( files "github.com/ipfs/go-ipfs-files" - util "github.com/ipfs/go-ipfs/blocks/blockstoreutil" cmdenv "github.com/ipfs/go-ipfs/core/commands/cmdenv" "github.com/ipfs/go-ipfs/core/commands/cmdutils" @@ -213,6 +212,11 @@ const ( blockQuietOptionName = "quiet" ) +type removedBlock struct { + Hash string `json:",omitempty"` + Error string `json:",omitempty"` +} + var blockRmCmd = &cmds.Command{ Helptext: cmds.HelpText{ Tagline: "Remove IPFS block(s).", @@ -246,7 +250,7 @@ It takes a list of base58 encoded multihashes to remove. err = api.Block().Rm(req.Context, rp, options.Block.Force(force)) if err != nil { - if err := res.Emit(&util.RemovedBlock{ + if err := res.Emit(&removedBlock{ Hash: rp.Cid().String(), Error: err.Error(), }); err != nil { @@ -256,7 +260,7 @@ It takes a list of base58 encoded multihashes to remove. } if !quiet { - err := res.Emit(&util.RemovedBlock{ + err := res.Emit(&removedBlock{ Hash: rp.Cid().String(), }) if err != nil { @@ -269,8 +273,29 @@ It takes a list of base58 encoded multihashes to remove. }, PostRun: cmds.PostRunMap{ cmds.CLI: func(res cmds.Response, re cmds.ResponseEmitter) error { - return util.ProcRmOutput(res.Next, os.Stdout, os.Stderr) + someFailed := false + for { + res, err := res.Next() + if err == io.EOF { + break + } else if err != nil { + return err + } + r := res.(*removedBlock) + if r.Hash == "" && r.Error != "" { + return fmt.Errorf("aborted: %s", r.Error) + } else if r.Error != "" { + someFailed = true + fmt.Fprintf(os.Stderr, "cannot remove %s: %s\n", r.Hash, r.Error) + } else { + fmt.Fprintf(os.Stdout, "removed %s\n", r.Hash) + } + } + if someFailed { + return fmt.Errorf("some blocks not removed") + } + return nil }, }, - Type: util.RemovedBlock{}, + Type: removedBlock{}, } diff --git a/core/coreapi/block.go b/core/coreapi/block.go index a1d5984d412..0b103a78a32 100644 --- a/core/coreapi/block.go +++ b/core/coreapi/block.go @@ -107,10 +107,8 @@ func (api *BlockAPI) Rm(ctx context.Context, p path.Path, opts ...caopts.BlockRm return errors.New("got unexpected output from util.RmBlocks") } - // Because errors come as strings we lose information about - // the error type. - if remBlock.Error != "" { - return errors.New(remBlock.Error) + if remBlock.Error != nil { + return remBlock.Error } return nil case <-ctx.Done(): From ac297a829e5e4bbc42b2640cf285c5413da70443 Mon Sep 17 00:00:00 2001 From: Jorropo Date: Fri, 1 Apr 2022 15:59:41 +0200 Subject: [PATCH 335/414] chore: block/blockstoreutil remove unused ProcRmOutput function --- blocks/blockstoreutil/remove.go | 28 ---------------------------- 1 file changed, 28 deletions(-) diff --git a/blocks/blockstoreutil/remove.go b/blocks/blockstoreutil/remove.go index 992da720b73..4440c2a6538 100644 --- a/blocks/blockstoreutil/remove.go +++ b/blocks/blockstoreutil/remove.go @@ -5,7 +5,6 @@ import ( "context" "errors" "fmt" - "io" cid "github.com/ipfs/go-cid" bs "github.com/ipfs/go-ipfs-blockstore" @@ -95,30 +94,3 @@ func FilterPinned(ctx context.Context, pins pin.Pinner, out chan<- interface{}, } return stillOkay } - -// ProcRmOutput takes a function which returns a result from RmBlocks or EOF if there is no input. -// It then writes to stdout/stderr according to the RemovedBlock object returned from the function. -func ProcRmOutput(next func() (interface{}, error), sout io.Writer, serr io.Writer) error { - someFailed := false - for { - res, err := next() - if err == io.EOF { - break - } else if err != nil { - return err - } - r := res.(*RemovedBlock) - if r.Hash == "" && r.Error != nil { - return fmt.Errorf("aborted: %w", r.Error) - } else if r.Error != nil { - someFailed = true - fmt.Fprintf(serr, "cannot remove %s: %v\n", r.Hash, r.Error) - } else { - fmt.Fprintf(sout, "removed %s\n", r.Hash) - } - } - if someFailed { - return fmt.Errorf("some blocks not removed") - } - return nil -} From 282ac7f1f54df2d8f1576d02bc43fd60fa59cb1f Mon Sep 17 00:00:00 2001 From: Lucas Molas Date: Sun, 3 Apr 2022 11:40:38 -0300 Subject: [PATCH 336/414] fix(cli): ipfs add with multiple files of same name (#8493) --- go.mod | 2 +- go.sum | 4 ++-- test/sharness/t0040-add-and-cat.sh | 21 +++++++++++++++++++++ 3 files changed, 24 insertions(+), 3 deletions(-) diff --git a/go.mod b/go.mod index 1fd95dee40d..f0b97ccc1c4 100644 --- a/go.mod +++ b/go.mod @@ -31,7 +31,7 @@ require ( github.com/ipfs/go-graphsync v0.11.0 github.com/ipfs/go-ipfs-blockstore v1.2.0 github.com/ipfs/go-ipfs-chunker v0.0.5 - github.com/ipfs/go-ipfs-cmds v0.7.0 + github.com/ipfs/go-ipfs-cmds v0.8.0 github.com/ipfs/go-ipfs-exchange-interface v0.1.0 github.com/ipfs/go-ipfs-exchange-offline v0.2.0 github.com/ipfs/go-ipfs-files v0.0.9 diff --git a/go.sum b/go.sum index 43f65b68404..496708baef5 100644 --- a/go.sum +++ b/go.sum @@ -473,8 +473,8 @@ github.com/ipfs/go-ipfs-blocksutil v0.0.1/go.mod h1:Yq4M86uIOmxmGPUHv/uI7uKqZNtL github.com/ipfs/go-ipfs-chunker v0.0.1/go.mod h1:tWewYK0we3+rMbOh7pPFGDyypCtvGcBFymgY4rSDLAw= github.com/ipfs/go-ipfs-chunker v0.0.5 h1:ojCf7HV/m+uS2vhUGWcogIIxiO5ubl5O57Q7NapWLY8= github.com/ipfs/go-ipfs-chunker v0.0.5/go.mod h1:jhgdF8vxRHycr00k13FM8Y0E+6BoalYeobXmUyTreP8= -github.com/ipfs/go-ipfs-cmds v0.7.0 h1:0lEldmB7C83RxIOer38Sv1ob6wIoCAIEOaxiYgcv7wA= -github.com/ipfs/go-ipfs-cmds v0.7.0/go.mod h1:y0bflH6m4g6ary4HniYt98UqbrVnRxmRarzeMdLIUn0= +github.com/ipfs/go-ipfs-cmds v0.8.0 h1:M7apkPxhGe7I3rcKuQ8xRJLIPdaEqaZhJz0uPZEE8EU= +github.com/ipfs/go-ipfs-cmds v0.8.0/go.mod h1:y0bflH6m4g6ary4HniYt98UqbrVnRxmRarzeMdLIUn0= github.com/ipfs/go-ipfs-delay v0.0.0-20181109222059-70721b86a9a8/go.mod h1:8SP1YXK1M1kXuc4KJZINY3TQQ03J2rwBG9QfXmbRPrw= github.com/ipfs/go-ipfs-delay v0.0.1 h1:r/UXYyRcddO6thwOnhiznIAiSvxMECGgtv35Xs1IeRQ= github.com/ipfs/go-ipfs-delay v0.0.1/go.mod h1:8SP1YXK1M1kXuc4KJZINY3TQQ03J2rwBG9QfXmbRPrw= diff --git a/test/sharness/t0040-add-and-cat.sh b/test/sharness/t0040-add-and-cat.sh index 635b97453a9..36a6e224050 100755 --- a/test/sharness/t0040-add-and-cat.sh +++ b/test/sharness/t0040-add-and-cat.sh @@ -345,6 +345,27 @@ test_add_cat_file() { echo "added Qmf35k66MZNW2GijohUmXQEWKZU4cCGTCwK6idfnt152wJ hello2.txt" >> expected && test_cmp expected actual ' + + test_expect_success "ipfs add with multiple files of same name succeeds" ' + mkdir -p mountdir/same-file/ && + cp mountdir/hello.txt mountdir/same-file/hello.txt && + ipfs add mountdir/hello.txt mountdir/same-file/hello.txt >actual && + rm mountdir/same-file/hello.txt && + rmdir mountdir/same-file + ' + + test_expect_success "ipfs add with multiple files of same name output looks good" ' + echo "added QmVr26fY1tKyspEJBniVhqxQeEjhF78XerGiqWAwraVLQH hello.txt" >expected && + test_cmp expected actual + ' + + test_must_fail "ipfs add with multiple files of same name but different dirs fails" ' + mkdir -p mountdir/same-file/ && + cp mountdir/hello.txt mountdir/same-file/hello.txt && + ipfs add mountdir/hello.txt mountdir/same-file/hello.txt >actual && + rm mountdir/same-file/hello.txt && + rmdir mountdir/same-file + ' } test_add_cat_5MB() { From f855bfe6ef8fe8a2633df889ce766cddc8d0effb Mon Sep 17 00:00:00 2001 From: Gus Eggert Date: Mon, 4 Apr 2022 13:24:05 -0400 Subject: [PATCH 337/414] feat: add basic gateway tracing (#8595) * add deprecation warning when tracer plugins are loaded * add response format attribute to span in gateway handler * add note about tracing's experimental status in godoc * add nil check for TTL when adding name span attrs * add basic sharness test for integration with otel collector * add nil check in UnixFSAPI.processLink * test: sharness check all json objs for swarm span * add env var docs to docs/environment-variables.md * chore: pin the otel collector version * add tracing spans per response type (#8841) * docs: tracing with jaeger-ui Co-authored-by: Marcin Rataj --- cmd/ipfs/main.go | 25 +++- core/coreapi/block.go | 14 ++ core/coreapi/dag.go | 7 + core/coreapi/dht.go | 13 ++ core/coreapi/key.go | 16 +++ core/coreapi/name.go | 24 +++- core/coreapi/object.go | 51 +++++++ core/coreapi/path.go | 10 ++ core/coreapi/pin.go | 37 +++++ core/coreapi/provider.go | 13 -- core/coreapi/pubsub.go | 20 +++ core/coreapi/swarm.go | 31 ++++- core/coreapi/unixfs.go | 37 +++++ core/corehttp/gateway.go | 5 +- core/corehttp/gateway_handler.go | 8 +- core/corehttp/gateway_handler_block.go | 11 +- core/corehttp/gateway_handler_car.go | 10 +- core/corehttp/gateway_handler_unixfs.go | 9 +- core/corehttp/gateway_handler_unixfs_dir.go | 11 +- core/corehttp/gateway_handler_unixfs_file.go | 10 +- core/coreunix/add.go | 25 +++- docs/debug-guide.md | 6 + docs/environment-variables.md | 70 ++++++++++ go.mod | 8 ++ go.sum | 44 +++++- mk/golang.mk | 2 +- plugin/loader/loader.go | 2 + test/sharness/t0310-tracing.sh | 57 ++++++++ tracing/doc.go | 66 +++++++++ tracing/tracing.go | 136 +++++++++++++++++++ 30 files changed, 725 insertions(+), 53 deletions(-) delete mode 100644 core/coreapi/provider.go create mode 100755 test/sharness/t0310-tracing.sh create mode 100644 tracing/doc.go create mode 100644 tracing/tracing.go diff --git a/cmd/ipfs/main.go b/cmd/ipfs/main.go index f410559a356..b95129db475 100644 --- a/cmd/ipfs/main.go +++ b/cmd/ipfs/main.go @@ -20,6 +20,8 @@ import ( loader "github.com/ipfs/go-ipfs/plugin/loader" repo "github.com/ipfs/go-ipfs/repo" fsrepo "github.com/ipfs/go-ipfs/repo/fsrepo" + "github.com/ipfs/go-ipfs/tracing" + "go.opentelemetry.io/otel" cmds "github.com/ipfs/go-ipfs-cmds" "github.com/ipfs/go-ipfs-cmds/cli" @@ -70,21 +72,30 @@ func main() { os.Exit(mainRet()) } -func mainRet() int { +func printErr(err error) int { + fmt.Fprintf(os.Stderr, "Error: %s\n", err.Error()) + return 1 +} + +func mainRet() (exitCode int) { rand.Seed(time.Now().UnixNano()) ctx := logging.ContextWithLoggable(context.Background(), loggables.Uuid("session")) var err error - // we'll call this local helper to output errors. - // this is so we control how to print errors in one place. - printErr := func(err error) { - fmt.Fprintf(os.Stderr, "Error: %s\n", err.Error()) + tp, err := tracing.NewTracerProvider(ctx) + if err != nil { + return printErr(err) } + defer func() { + if err := tp.Shutdown(ctx); err != nil { + exitCode = printErr(err) + } + }() + otel.SetTracerProvider(tp) stopFunc, err := profileIfEnabled() if err != nil { - printErr(err) - return 1 + return printErr(err) } defer stopFunc() // to be executed as late as possible diff --git a/core/coreapi/block.go b/core/coreapi/block.go index a1d5984d412..61a9d724c7e 100644 --- a/core/coreapi/block.go +++ b/core/coreapi/block.go @@ -13,8 +13,11 @@ import ( coreiface "github.com/ipfs/interface-go-ipfs-core" caopts "github.com/ipfs/interface-go-ipfs-core/options" path "github.com/ipfs/interface-go-ipfs-core/path" + "go.opentelemetry.io/otel/attribute" + "go.opentelemetry.io/otel/trace" util "github.com/ipfs/go-ipfs/blocks/blockstoreutil" + "github.com/ipfs/go-ipfs/tracing" ) type BlockAPI CoreAPI @@ -25,6 +28,9 @@ type BlockStat struct { } func (api *BlockAPI) Put(ctx context.Context, src io.Reader, opts ...caopts.BlockPutOption) (coreiface.BlockStat, error) { + ctx, span := tracing.Span(ctx, "CoreAPI.BlockAPI", "Put") + defer span.End() + settings, pref, err := caopts.BlockPutOptions(opts...) if err != nil { return nil, err @@ -65,6 +71,8 @@ func (api *BlockAPI) Put(ctx context.Context, src io.Reader, opts ...caopts.Bloc } func (api *BlockAPI) Get(ctx context.Context, p path.Path) (io.Reader, error) { + ctx, span := tracing.Span(ctx, "CoreAPI.BlockAPI", "Get", trace.WithAttributes(attribute.String("path", p.String()))) + defer span.End() rp, err := api.core().ResolvePath(ctx, p) if err != nil { return nil, err @@ -79,6 +87,9 @@ func (api *BlockAPI) Get(ctx context.Context, p path.Path) (io.Reader, error) { } func (api *BlockAPI) Rm(ctx context.Context, p path.Path, opts ...caopts.BlockRmOption) error { + ctx, span := tracing.Span(ctx, "CoreAPI.BlockAPI", "Rm", trace.WithAttributes(attribute.String("path", p.String()))) + defer span.End() + rp, err := api.core().ResolvePath(ctx, p) if err != nil { return err @@ -119,6 +130,9 @@ func (api *BlockAPI) Rm(ctx context.Context, p path.Path, opts ...caopts.BlockRm } func (api *BlockAPI) Stat(ctx context.Context, p path.Path) (coreiface.BlockStat, error) { + ctx, span := tracing.Span(ctx, "CoreAPI.BlockAPI", "Stat", trace.WithAttributes(attribute.String("path", p.String()))) + defer span.End() + rp, err := api.core().ResolvePath(ctx, p) if err != nil { return nil, err diff --git a/core/coreapi/dag.go b/core/coreapi/dag.go index d056e8e6e0a..696c5bab76c 100644 --- a/core/coreapi/dag.go +++ b/core/coreapi/dag.go @@ -5,8 +5,11 @@ import ( cid "github.com/ipfs/go-cid" pin "github.com/ipfs/go-ipfs-pinner" + "github.com/ipfs/go-ipfs/tracing" ipld "github.com/ipfs/go-ipld-format" dag "github.com/ipfs/go-merkledag" + "go.opentelemetry.io/otel/attribute" + "go.opentelemetry.io/otel/trace" ) type dagAPI struct { @@ -18,6 +21,8 @@ type dagAPI struct { type pinningAdder CoreAPI func (adder *pinningAdder) Add(ctx context.Context, nd ipld.Node) error { + ctx, span := tracing.Span(ctx, "CoreAPI.PinningAdder", "Add", trace.WithAttributes(attribute.String("node", nd.String()))) + defer span.End() defer adder.blockstore.PinLock(ctx).Unlock(ctx) if err := adder.dag.Add(ctx, nd); err != nil { @@ -30,6 +35,8 @@ func (adder *pinningAdder) Add(ctx context.Context, nd ipld.Node) error { } func (adder *pinningAdder) AddMany(ctx context.Context, nds []ipld.Node) error { + ctx, span := tracing.Span(ctx, "CoreAPI.PinningAdder", "AddMany", trace.WithAttributes(attribute.Int("nodes.count", len(nds)))) + defer span.End() defer adder.blockstore.PinLock(ctx).Unlock(ctx) if err := adder.dag.AddMany(ctx, nds); err != nil { diff --git a/core/coreapi/dht.go b/core/coreapi/dht.go index 3f10a0ffcf8..c196aba9bd8 100644 --- a/core/coreapi/dht.go +++ b/core/coreapi/dht.go @@ -9,17 +9,22 @@ import ( cidutil "github.com/ipfs/go-cidutil" blockstore "github.com/ipfs/go-ipfs-blockstore" offline "github.com/ipfs/go-ipfs-exchange-offline" + "github.com/ipfs/go-ipfs/tracing" dag "github.com/ipfs/go-merkledag" coreiface "github.com/ipfs/interface-go-ipfs-core" caopts "github.com/ipfs/interface-go-ipfs-core/options" path "github.com/ipfs/interface-go-ipfs-core/path" peer "github.com/libp2p/go-libp2p-core/peer" routing "github.com/libp2p/go-libp2p-core/routing" + "go.opentelemetry.io/otel/attribute" + "go.opentelemetry.io/otel/trace" ) type DhtAPI CoreAPI func (api *DhtAPI) FindPeer(ctx context.Context, p peer.ID) (peer.AddrInfo, error) { + ctx, span := tracing.Span(ctx, "CoreAPI.DhtAPI", "FindPeer", trace.WithAttributes(attribute.String("peer", p.String()))) + defer span.End() err := api.checkOnline(false) if err != nil { return peer.AddrInfo{}, err @@ -34,10 +39,14 @@ func (api *DhtAPI) FindPeer(ctx context.Context, p peer.ID) (peer.AddrInfo, erro } func (api *DhtAPI) FindProviders(ctx context.Context, p path.Path, opts ...caopts.DhtFindProvidersOption) (<-chan peer.AddrInfo, error) { + ctx, span := tracing.Span(ctx, "CoreAPI.DhtAPI", "FindProviders", trace.WithAttributes(attribute.String("path", p.String()))) + defer span.End() + settings, err := caopts.DhtFindProvidersOptions(opts...) if err != nil { return nil, err } + span.SetAttributes(attribute.Int("numproviders", settings.NumProviders)) err = api.checkOnline(false) if err != nil { @@ -59,10 +68,14 @@ func (api *DhtAPI) FindProviders(ctx context.Context, p path.Path, opts ...caopt } func (api *DhtAPI) Provide(ctx context.Context, path path.Path, opts ...caopts.DhtProvideOption) error { + ctx, span := tracing.Span(ctx, "CoreAPI.DhtAPI", "Provide", trace.WithAttributes(attribute.String("path", path.String()))) + defer span.End() + settings, err := caopts.DhtProvideOptions(opts...) if err != nil { return err } + span.SetAttributes(attribute.Bool("recursive", settings.Recursive)) err = api.checkOnline(false) if err != nil { diff --git a/core/coreapi/key.go b/core/coreapi/key.go index 9b4045ed04a..1468e6c0c5a 100644 --- a/core/coreapi/key.go +++ b/core/coreapi/key.go @@ -7,12 +7,15 @@ import ( "fmt" "sort" + "github.com/ipfs/go-ipfs/tracing" ipfspath "github.com/ipfs/go-path" coreiface "github.com/ipfs/interface-go-ipfs-core" caopts "github.com/ipfs/interface-go-ipfs-core/options" path "github.com/ipfs/interface-go-ipfs-core/path" crypto "github.com/libp2p/go-libp2p-core/crypto" peer "github.com/libp2p/go-libp2p-core/peer" + "go.opentelemetry.io/otel/attribute" + "go.opentelemetry.io/otel/trace" ) type KeyAPI CoreAPI @@ -40,6 +43,9 @@ func (k *key) ID() peer.ID { // Generate generates new key, stores it in the keystore under the specified // name and returns a base58 encoded multihash of its public key. func (api *KeyAPI) Generate(ctx context.Context, name string, opts ...caopts.KeyGenerateOption) (coreiface.Key, error) { + _, span := tracing.Span(ctx, "CoreAPI.KeyAPI", "Generate", trace.WithAttributes(attribute.String("name", name))) + defer span.End() + options, err := caopts.KeyGenerateOptions(opts...) if err != nil { return nil, err @@ -97,6 +103,9 @@ func (api *KeyAPI) Generate(ctx context.Context, name string, opts ...caopts.Key // List returns a list keys stored in keystore. func (api *KeyAPI) List(ctx context.Context) ([]coreiface.Key, error) { + _, span := tracing.Span(ctx, "CoreAPI.KeyAPI", "List") + defer span.End() + keys, err := api.repo.Keystore().List() if err != nil { return nil, err @@ -128,10 +137,14 @@ func (api *KeyAPI) List(ctx context.Context) ([]coreiface.Key, error) { // Rename renames `oldName` to `newName`. Returns the key and whether another // key was overwritten, or an error. func (api *KeyAPI) Rename(ctx context.Context, oldName string, newName string, opts ...caopts.KeyRenameOption) (coreiface.Key, bool, error) { + _, span := tracing.Span(ctx, "CoreAPI.KeyAPI", "Rename", trace.WithAttributes(attribute.String("oldname", oldName), attribute.String("newname", newName))) + defer span.End() + options, err := caopts.KeyRenameOptions(opts...) if err != nil { return nil, false, err } + span.SetAttributes(attribute.Bool("force", options.Force)) ks := api.repo.Keystore() @@ -187,6 +200,9 @@ func (api *KeyAPI) Rename(ctx context.Context, oldName string, newName string, o // Remove removes keys from keystore. Returns ipns path of the removed key. func (api *KeyAPI) Remove(ctx context.Context, name string) (coreiface.Key, error) { + _, span := tracing.Span(ctx, "CoreAPI.KeyAPI", "Remove", trace.WithAttributes(attribute.String("name", name))) + defer span.End() + ks := api.repo.Keystore() if name == "self" { diff --git a/core/coreapi/name.go b/core/coreapi/name.go index b007ccd7d5c..d2ef99bb338 100644 --- a/core/coreapi/name.go +++ b/core/coreapi/name.go @@ -6,8 +6,11 @@ import ( "strings" "time" - "github.com/ipfs/go-ipfs-keystore" + keystore "github.com/ipfs/go-ipfs-keystore" + "github.com/ipfs/go-ipfs/tracing" "github.com/ipfs/go-namesys" + "go.opentelemetry.io/otel/attribute" + "go.opentelemetry.io/otel/trace" ipath "github.com/ipfs/go-path" coreiface "github.com/ipfs/interface-go-ipfs-core" @@ -36,6 +39,9 @@ func (e *ipnsEntry) Value() path.Path { // Publish announces new IPNS name and returns the new IPNS entry. func (api *NameAPI) Publish(ctx context.Context, p path.Path, opts ...caopts.NamePublishOption) (coreiface.IpnsEntry, error) { + ctx, span := tracing.Span(ctx, "CoreAPI.NameAPI", "Publish", trace.WithAttributes(attribute.String("path", p.String()))) + defer span.End() + if err := api.checkPublishAllowed(); err != nil { return nil, err } @@ -44,6 +50,14 @@ func (api *NameAPI) Publish(ctx context.Context, p path.Path, opts ...caopts.Nam if err != nil { return nil, err } + span.SetAttributes( + attribute.Bool("allowoffline", options.AllowOffline), + attribute.String("key", options.Key), + attribute.Float64("validtime", options.ValidTime.Seconds()), + ) + if options.TTL != nil { + span.SetAttributes(attribute.Float64("ttl", options.TTL.Seconds())) + } err = api.checkOnline(options.AllowOffline) if err != nil { @@ -82,11 +96,16 @@ func (api *NameAPI) Publish(ctx context.Context, p path.Path, opts ...caopts.Nam } func (api *NameAPI) Search(ctx context.Context, name string, opts ...caopts.NameResolveOption) (<-chan coreiface.IpnsResult, error) { + ctx, span := tracing.Span(ctx, "CoreAPI.NameAPI", "Search", trace.WithAttributes(attribute.String("name", name))) + defer span.End() + options, err := caopts.NameResolveOptions(opts...) if err != nil { return nil, err } + span.SetAttributes(attribute.Bool("cache", options.Cache)) + err = api.checkOnline(true) if err != nil { return nil, err @@ -124,6 +143,9 @@ func (api *NameAPI) Search(ctx context.Context, name string, opts ...caopts.Name // Resolve attempts to resolve the newest version of the specified name and // returns its path. func (api *NameAPI) Resolve(ctx context.Context, name string, opts ...caopts.NameResolveOption) (path.Path, error) { + ctx, span := tracing.Span(ctx, "CoreAPI.NameAPI", "Resolve", trace.WithAttributes(attribute.String("name", name))) + defer span.End() + ctx, cancel := context.WithCancel(ctx) defer cancel() diff --git a/core/coreapi/object.go b/core/coreapi/object.go index 62d31daede1..8c3a2e0aa0c 100644 --- a/core/coreapi/object.go +++ b/core/coreapi/object.go @@ -13,6 +13,7 @@ import ( cid "github.com/ipfs/go-cid" pin "github.com/ipfs/go-ipfs-pinner" + "github.com/ipfs/go-ipfs/tracing" ipld "github.com/ipfs/go-ipld-format" dag "github.com/ipfs/go-merkledag" "github.com/ipfs/go-merkledag/dagutils" @@ -20,6 +21,8 @@ import ( coreiface "github.com/ipfs/interface-go-ipfs-core" caopts "github.com/ipfs/interface-go-ipfs-core/options" ipath "github.com/ipfs/interface-go-ipfs-core/path" + "go.opentelemetry.io/otel/attribute" + "go.opentelemetry.io/otel/trace" ) const inputLimit = 2 << 20 @@ -37,6 +40,9 @@ type Node struct { } func (api *ObjectAPI) New(ctx context.Context, opts ...caopts.ObjectNewOption) (ipld.Node, error) { + ctx, span := tracing.Span(ctx, "CoreAPI.ObjectAPI", "New") + defer span.End() + options, err := caopts.ObjectNewOptions(opts...) if err != nil { return nil, err @@ -60,10 +66,18 @@ func (api *ObjectAPI) New(ctx context.Context, opts ...caopts.ObjectNewOption) ( } func (api *ObjectAPI) Put(ctx context.Context, src io.Reader, opts ...caopts.ObjectPutOption) (ipath.Resolved, error) { + ctx, span := tracing.Span(ctx, "CoreAPI.ObjectAPI", "Put") + defer span.End() + options, err := caopts.ObjectPutOptions(opts...) if err != nil { return nil, err } + span.SetAttributes( + attribute.Bool("pin", options.Pin), + attribute.String("datatype", options.DataType), + attribute.String("inputenc", options.InputEnc), + ) data, err := ioutil.ReadAll(io.LimitReader(src, inputLimit+10)) if err != nil { @@ -130,10 +144,15 @@ func (api *ObjectAPI) Put(ctx context.Context, src io.Reader, opts ...caopts.Obj } func (api *ObjectAPI) Get(ctx context.Context, path ipath.Path) (ipld.Node, error) { + ctx, span := tracing.Span(ctx, "CoreAPI.ObjectAPI", "Get", trace.WithAttributes(attribute.String("path", path.String()))) + defer span.End() return api.core().ResolveNode(ctx, path) } func (api *ObjectAPI) Data(ctx context.Context, path ipath.Path) (io.Reader, error) { + ctx, span := tracing.Span(ctx, "CoreAPI.ObjectAPI", "Data", trace.WithAttributes(attribute.String("path", path.String()))) + defer span.End() + nd, err := api.core().ResolveNode(ctx, path) if err != nil { return nil, err @@ -148,6 +167,9 @@ func (api *ObjectAPI) Data(ctx context.Context, path ipath.Path) (io.Reader, err } func (api *ObjectAPI) Links(ctx context.Context, path ipath.Path) ([]*ipld.Link, error) { + ctx, span := tracing.Span(ctx, "CoreAPI.ObjectAPI", "Links", trace.WithAttributes(attribute.String("path", path.String()))) + defer span.End() + nd, err := api.core().ResolveNode(ctx, path) if err != nil { return nil, err @@ -163,6 +185,9 @@ func (api *ObjectAPI) Links(ctx context.Context, path ipath.Path) ([]*ipld.Link, } func (api *ObjectAPI) Stat(ctx context.Context, path ipath.Path) (*coreiface.ObjectStat, error) { + ctx, span := tracing.Span(ctx, "CoreAPI.ObjectAPI", "Stat", trace.WithAttributes(attribute.String("path", path.String()))) + defer span.End() + nd, err := api.core().ResolveNode(ctx, path) if err != nil { return nil, err @@ -186,10 +211,18 @@ func (api *ObjectAPI) Stat(ctx context.Context, path ipath.Path) (*coreiface.Obj } func (api *ObjectAPI) AddLink(ctx context.Context, base ipath.Path, name string, child ipath.Path, opts ...caopts.ObjectAddLinkOption) (ipath.Resolved, error) { + ctx, span := tracing.Span(ctx, "CoreAPI.ObjectAPI", "AddLink", trace.WithAttributes( + attribute.String("base", base.String()), + attribute.String("name", name), + attribute.String("child", child.String()), + )) + defer span.End() + options, err := caopts.ObjectAddLinkOptions(opts...) if err != nil { return nil, err } + span.SetAttributes(attribute.Bool("create", options.Create)) baseNd, err := api.core().ResolveNode(ctx, base) if err != nil { @@ -227,6 +260,12 @@ func (api *ObjectAPI) AddLink(ctx context.Context, base ipath.Path, name string, } func (api *ObjectAPI) RmLink(ctx context.Context, base ipath.Path, link string) (ipath.Resolved, error) { + ctx, span := tracing.Span(ctx, "CoreAPI.ObjectAPI", "RmLink", trace.WithAttributes( + attribute.String("base", base.String()), + attribute.String("link", link)), + ) + defer span.End() + baseNd, err := api.core().ResolveNode(ctx, base) if err != nil { return nil, err @@ -253,10 +292,16 @@ func (api *ObjectAPI) RmLink(ctx context.Context, base ipath.Path, link string) } func (api *ObjectAPI) AppendData(ctx context.Context, path ipath.Path, r io.Reader) (ipath.Resolved, error) { + ctx, span := tracing.Span(ctx, "CoreAPI.ObjectAPI", "AppendData", trace.WithAttributes(attribute.String("path", path.String()))) + defer span.End() + return api.patchData(ctx, path, r, true) } func (api *ObjectAPI) SetData(ctx context.Context, path ipath.Path, r io.Reader) (ipath.Resolved, error) { + ctx, span := tracing.Span(ctx, "CoreAPI.ObjectAPI", "SetData", trace.WithAttributes(attribute.String("path", path.String()))) + defer span.End() + return api.patchData(ctx, path, r, false) } @@ -290,6 +335,12 @@ func (api *ObjectAPI) patchData(ctx context.Context, path ipath.Path, r io.Reade } func (api *ObjectAPI) Diff(ctx context.Context, before ipath.Path, after ipath.Path) ([]coreiface.ObjectChange, error) { + ctx, span := tracing.Span(ctx, "CoreAPI.ObjectAPI", "Diff", trace.WithAttributes( + attribute.String("before", before.String()), + attribute.String("after", after.String()), + )) + defer span.End() + beforeNd, err := api.core().ResolveNode(ctx, before) if err != nil { return nil, err diff --git a/core/coreapi/path.go b/core/coreapi/path.go index b9bf83e0df6..5f2b4100789 100644 --- a/core/coreapi/path.go +++ b/core/coreapi/path.go @@ -5,8 +5,12 @@ import ( "fmt" gopath "path" + "github.com/ipfs/go-ipfs/tracing" "github.com/ipfs/go-namesys/resolve" + "go.opentelemetry.io/otel/attribute" + "go.opentelemetry.io/otel/trace" + "github.com/ipfs/go-cid" "github.com/ipfs/go-fetcher" ipld "github.com/ipfs/go-ipld-format" @@ -19,6 +23,9 @@ import ( // ResolveNode resolves the path `p` using Unixfs resolver, gets and returns the // resolved Node. func (api *CoreAPI) ResolveNode(ctx context.Context, p path.Path) (ipld.Node, error) { + ctx, span := tracing.Span(ctx, "CoreAPI", "ResolveNode", trace.WithAttributes(attribute.String("path", p.String()))) + defer span.End() + rp, err := api.ResolvePath(ctx, p) if err != nil { return nil, err @@ -34,6 +41,9 @@ func (api *CoreAPI) ResolveNode(ctx context.Context, p path.Path) (ipld.Node, er // ResolvePath resolves the path `p` using Unixfs resolver, returns the // resolved path. func (api *CoreAPI) ResolvePath(ctx context.Context, p path.Path) (path.Resolved, error) { + ctx, span := tracing.Span(ctx, "CoreAPI", "ResolvePath", trace.WithAttributes(attribute.String("path", p.String()))) + defer span.End() + if _, ok := p.(path.Resolved); ok { return p.(path.Resolved), nil } diff --git a/core/coreapi/pin.go b/core/coreapi/pin.go index 52ea6a6a453..51667c4b71f 100644 --- a/core/coreapi/pin.go +++ b/core/coreapi/pin.go @@ -8,15 +8,21 @@ import ( "github.com/ipfs/go-cid" offline "github.com/ipfs/go-ipfs-exchange-offline" pin "github.com/ipfs/go-ipfs-pinner" + "github.com/ipfs/go-ipfs/tracing" "github.com/ipfs/go-merkledag" coreiface "github.com/ipfs/interface-go-ipfs-core" caopts "github.com/ipfs/interface-go-ipfs-core/options" "github.com/ipfs/interface-go-ipfs-core/path" + "go.opentelemetry.io/otel/attribute" + "go.opentelemetry.io/otel/trace" ) type PinAPI CoreAPI func (api *PinAPI) Add(ctx context.Context, p path.Path, opts ...caopts.PinAddOption) error { + ctx, span := tracing.Span(ctx, "CoreAPI.PinAPI", "Add", trace.WithAttributes(attribute.String("path", p.String()))) + defer span.End() + dagNode, err := api.core().ResolveNode(ctx, p) if err != nil { return fmt.Errorf("pin: %s", err) @@ -27,6 +33,8 @@ func (api *PinAPI) Add(ctx context.Context, p path.Path, opts ...caopts.PinAddOp return err } + span.SetAttributes(attribute.Bool("recursive", settings.Recursive)) + defer api.blockstore.PinLock(ctx).Unlock(ctx) err = api.pinning.Pin(ctx, dagNode, settings.Recursive) @@ -42,11 +50,16 @@ func (api *PinAPI) Add(ctx context.Context, p path.Path, opts ...caopts.PinAddOp } func (api *PinAPI) Ls(ctx context.Context, opts ...caopts.PinLsOption) (<-chan coreiface.Pin, error) { + ctx, span := tracing.Span(ctx, "CoreAPI.PinAPI", "Ls") + defer span.End() + settings, err := caopts.PinLsOptions(opts...) if err != nil { return nil, err } + span.SetAttributes(attribute.String("type", settings.Type)) + switch settings.Type { case "all", "direct", "indirect", "recursive": default: @@ -57,6 +70,9 @@ func (api *PinAPI) Ls(ctx context.Context, opts ...caopts.PinLsOption) (<-chan c } func (api *PinAPI) IsPinned(ctx context.Context, p path.Path, opts ...caopts.PinIsPinnedOption) (string, bool, error) { + ctx, span := tracing.Span(ctx, "CoreAPI.PinAPI", "IsPinned", trace.WithAttributes(attribute.String("path", p.String()))) + defer span.End() + resolved, err := api.core().ResolvePath(ctx, p) if err != nil { return "", false, fmt.Errorf("error resolving path: %s", err) @@ -67,6 +83,8 @@ func (api *PinAPI) IsPinned(ctx context.Context, p path.Path, opts ...caopts.Pin return "", false, err } + span.SetAttributes(attribute.String("withtype", settings.WithType)) + mode, ok := pin.StringToMode(settings.WithType) if !ok { return "", false, fmt.Errorf("invalid type '%s', must be one of {direct, indirect, recursive, all}", settings.WithType) @@ -77,6 +95,9 @@ func (api *PinAPI) IsPinned(ctx context.Context, p path.Path, opts ...caopts.Pin // Rm pin rm api func (api *PinAPI) Rm(ctx context.Context, p path.Path, opts ...caopts.PinRmOption) error { + ctx, span := tracing.Span(ctx, "CoreAPI.PinAPI", "Rm", trace.WithAttributes(attribute.String("path", p.String()))) + defer span.End() + rp, err := api.core().ResolvePath(ctx, p) if err != nil { return err @@ -87,6 +108,8 @@ func (api *PinAPI) Rm(ctx context.Context, p path.Path, opts ...caopts.PinRmOpti return err } + span.SetAttributes(attribute.Bool("recursive", settings.Recursive)) + // Note: after unpin the pin sets are flushed to the blockstore, so we need // to take a lock to prevent a concurrent garbage collection defer api.blockstore.PinLock(ctx).Unlock(ctx) @@ -99,11 +122,19 @@ func (api *PinAPI) Rm(ctx context.Context, p path.Path, opts ...caopts.PinRmOpti } func (api *PinAPI) Update(ctx context.Context, from path.Path, to path.Path, opts ...caopts.PinUpdateOption) error { + ctx, span := tracing.Span(ctx, "CoreAPI.PinAPI", "Update", trace.WithAttributes( + attribute.String("from", from.String()), + attribute.String("to", to.String()), + )) + defer span.End() + settings, err := caopts.PinUpdateOptions(opts...) if err != nil { return err } + span.SetAttributes(attribute.Bool("unpin", settings.Unpin)) + fp, err := api.core().ResolvePath(ctx, from) if err != nil { return err @@ -153,6 +184,9 @@ func (n *badNode) Err() error { } func (api *PinAPI) Verify(ctx context.Context) (<-chan coreiface.PinStatus, error) { + ctx, span := tracing.Span(ctx, "CoreAPI.PinAPI", "Verify") + defer span.End() + visited := make(map[cid.Cid]*pinStatus) bs := api.blockstore DAG := merkledag.NewDAGService(bserv.New(bs, offline.Exchange(bs))) @@ -164,6 +198,9 @@ func (api *PinAPI) Verify(ctx context.Context) (<-chan coreiface.PinStatus, erro var checkPin func(root cid.Cid) *pinStatus checkPin = func(root cid.Cid) *pinStatus { + ctx, span := tracing.Span(ctx, "CoreAPI.PinAPI", "Verify.CheckPin", trace.WithAttributes(attribute.String("cid", root.String()))) + defer span.End() + if status, ok := visited[root]; ok { return status } diff --git a/core/coreapi/provider.go b/core/coreapi/provider.go deleted file mode 100644 index 8148c87892e..00000000000 --- a/core/coreapi/provider.go +++ /dev/null @@ -1,13 +0,0 @@ -package coreapi - -import ( - cid "github.com/ipfs/go-cid" -) - -// ProviderAPI brings Provider behavior to CoreAPI -type ProviderAPI CoreAPI - -// Provide the given cid using the current provider -func (api *ProviderAPI) Provide(cid cid.Cid) error { - return api.provider.Provide(cid) -} diff --git a/core/coreapi/pubsub.go b/core/coreapi/pubsub.go index a75db36296b..99658b59952 100644 --- a/core/coreapi/pubsub.go +++ b/core/coreapi/pubsub.go @@ -4,11 +4,14 @@ import ( "context" "errors" + "github.com/ipfs/go-ipfs/tracing" coreiface "github.com/ipfs/interface-go-ipfs-core" caopts "github.com/ipfs/interface-go-ipfs-core/options" peer "github.com/libp2p/go-libp2p-core/peer" routing "github.com/libp2p/go-libp2p-core/routing" pubsub "github.com/libp2p/go-libp2p-pubsub" + "go.opentelemetry.io/otel/attribute" + "go.opentelemetry.io/otel/trace" ) type PubSubAPI CoreAPI @@ -22,6 +25,9 @@ type pubSubMessage struct { } func (api *PubSubAPI) Ls(ctx context.Context) ([]string, error) { + _, span := tracing.Span(ctx, "CoreAPI.PubSubAPI", "Ls") + defer span.End() + _, err := api.checkNode() if err != nil { return nil, err @@ -31,6 +37,9 @@ func (api *PubSubAPI) Ls(ctx context.Context) ([]string, error) { } func (api *PubSubAPI) Peers(ctx context.Context, opts ...caopts.PubSubPeersOption) ([]peer.ID, error) { + _, span := tracing.Span(ctx, "CoreAPI.PubSubAPI", "Peers") + defer span.End() + _, err := api.checkNode() if err != nil { return nil, err @@ -41,10 +50,15 @@ func (api *PubSubAPI) Peers(ctx context.Context, opts ...caopts.PubSubPeersOptio return nil, err } + span.SetAttributes(attribute.String("topic", settings.Topic)) + return api.pubSub.ListPeers(settings.Topic), nil } func (api *PubSubAPI) Publish(ctx context.Context, topic string, data []byte) error { + _, span := tracing.Span(ctx, "CoreAPI.PubSubAPI", "Publish", trace.WithAttributes(attribute.String("topic", topic))) + defer span.End() + _, err := api.checkNode() if err != nil { return err @@ -55,6 +69,9 @@ func (api *PubSubAPI) Publish(ctx context.Context, topic string, data []byte) er } func (api *PubSubAPI) Subscribe(ctx context.Context, topic string, opts ...caopts.PubSubSubscribeOption) (coreiface.PubSubSubscription, error) { + _, span := tracing.Span(ctx, "CoreAPI.PubSubAPI", "Subscribe", trace.WithAttributes(attribute.String("topic", topic))) + defer span.End() + // Parse the options to avoid introducing silent failures for invalid // options. However, we don't currently have any use for them. The only // subscription option, discovery, is now a no-op as it's handled by @@ -97,6 +114,9 @@ func (sub *pubSubSubscription) Close() error { } func (sub *pubSubSubscription) Next(ctx context.Context) (coreiface.PubSubMessage, error) { + ctx, span := tracing.Span(ctx, "CoreAPI.PubSubSubscription", "Next") + defer span.End() + msg, err := sub.subscription.Next(ctx) if err != nil { return nil, err diff --git a/core/coreapi/swarm.go b/core/coreapi/swarm.go index 3c3c40ddbdc..2aea3152ca1 100644 --- a/core/coreapi/swarm.go +++ b/core/coreapi/swarm.go @@ -5,6 +5,7 @@ import ( "sort" "time" + "github.com/ipfs/go-ipfs/tracing" coreiface "github.com/ipfs/interface-go-ipfs-core" inet "github.com/libp2p/go-libp2p-core/network" peer "github.com/libp2p/go-libp2p-core/peer" @@ -12,6 +13,8 @@ import ( protocol "github.com/libp2p/go-libp2p-core/protocol" swarm "github.com/libp2p/go-libp2p-swarm" ma "github.com/multiformats/go-multiaddr" + "go.opentelemetry.io/otel/attribute" + "go.opentelemetry.io/otel/trace" ) type SwarmAPI CoreAPI @@ -30,6 +33,9 @@ const connectionManagerTag = "user-connect" const connectionManagerWeight = 100 func (api *SwarmAPI) Connect(ctx context.Context, pi peer.AddrInfo) error { + ctx, span := tracing.Span(ctx, "CoreAPI.SwarmAPI", "Connect", trace.WithAttributes(attribute.String("peerid", pi.ID.String()))) + defer span.End() + if api.peerHost == nil { return coreiface.ErrOffline } @@ -47,6 +53,9 @@ func (api *SwarmAPI) Connect(ctx context.Context, pi peer.AddrInfo) error { } func (api *SwarmAPI) Disconnect(ctx context.Context, addr ma.Multiaddr) error { + _, span := tracing.Span(ctx, "CoreAPI.SwarmAPI", "Disconnect", trace.WithAttributes(attribute.String("addr", addr.String()))) + defer span.End() + if api.peerHost == nil { return coreiface.ErrOffline } @@ -56,6 +65,8 @@ func (api *SwarmAPI) Disconnect(ctx context.Context, addr ma.Multiaddr) error { return peer.ErrInvalidAddr } + span.SetAttributes(attribute.String("peerid", id.String())) + net := api.peerHost.Network() if taddr == nil { if net.Connectedness(id) != inet.Connected { @@ -76,7 +87,10 @@ func (api *SwarmAPI) Disconnect(ctx context.Context, addr ma.Multiaddr) error { return coreiface.ErrConnNotFound } -func (api *SwarmAPI) KnownAddrs(context.Context) (map[peer.ID][]ma.Multiaddr, error) { +func (api *SwarmAPI) KnownAddrs(ctx context.Context) (map[peer.ID][]ma.Multiaddr, error) { + _, span := tracing.Span(ctx, "CoreAPI.SwarmAPI", "KnownAddrs") + defer span.End() + if api.peerHost == nil { return nil, coreiface.ErrOffline } @@ -93,7 +107,10 @@ func (api *SwarmAPI) KnownAddrs(context.Context) (map[peer.ID][]ma.Multiaddr, er return addrs, nil } -func (api *SwarmAPI) LocalAddrs(context.Context) ([]ma.Multiaddr, error) { +func (api *SwarmAPI) LocalAddrs(ctx context.Context) ([]ma.Multiaddr, error) { + _, span := tracing.Span(ctx, "CoreAPI.SwarmAPI", "LocalAddrs") + defer span.End() + if api.peerHost == nil { return nil, coreiface.ErrOffline } @@ -101,7 +118,10 @@ func (api *SwarmAPI) LocalAddrs(context.Context) ([]ma.Multiaddr, error) { return api.peerHost.Addrs(), nil } -func (api *SwarmAPI) ListenAddrs(context.Context) ([]ma.Multiaddr, error) { +func (api *SwarmAPI) ListenAddrs(ctx context.Context) ([]ma.Multiaddr, error) { + _, span := tracing.Span(ctx, "CoreAPI.SwarmAPI", "ListenAddrs") + defer span.End() + if api.peerHost == nil { return nil, coreiface.ErrOffline } @@ -109,7 +129,10 @@ func (api *SwarmAPI) ListenAddrs(context.Context) ([]ma.Multiaddr, error) { return api.peerHost.Network().InterfaceListenAddresses() } -func (api *SwarmAPI) Peers(context.Context) ([]coreiface.ConnectionInfo, error) { +func (api *SwarmAPI) Peers(ctx context.Context) ([]coreiface.ConnectionInfo, error) { + _, span := tracing.Span(ctx, "CoreAPI.SwarmAPI", "Peers") + defer span.End() + if api.peerHost == nil { return nil, coreiface.ErrOffline } diff --git a/core/coreapi/unixfs.go b/core/coreapi/unixfs.go index 55410dcb098..5d3d7e80e30 100644 --- a/core/coreapi/unixfs.go +++ b/core/coreapi/unixfs.go @@ -6,6 +6,9 @@ import ( "sync" "github.com/ipfs/go-ipfs/core" + "github.com/ipfs/go-ipfs/tracing" + "go.opentelemetry.io/otel/attribute" + "go.opentelemetry.io/otel/trace" "github.com/ipfs/go-ipfs/core/coreunix" @@ -55,11 +58,30 @@ func getOrCreateNilNode() (*core.IpfsNode, error) { // Add builds a merkledag node from a reader, adds it to the blockstore, // and returns the key representing that node. func (api *UnixfsAPI) Add(ctx context.Context, files files.Node, opts ...options.UnixfsAddOption) (path.Resolved, error) { + ctx, span := tracing.Span(ctx, "CoreAPI.UnixfsAPI", "Add") + defer span.End() + settings, prefix, err := options.UnixfsAddOptions(opts...) if err != nil { return nil, err } + span.SetAttributes( + attribute.String("chunker", settings.Chunker), + attribute.Int("cidversion", settings.CidVersion), + attribute.Bool("inline", settings.Inline), + attribute.Int("inlinelimit", settings.InlineLimit), + attribute.Bool("rawleaves", settings.RawLeaves), + attribute.Bool("rawleavesset", settings.RawLeavesSet), + attribute.Int("layout", int(settings.Layout)), + attribute.Bool("pin", settings.Pin), + attribute.Bool("onlyhash", settings.OnlyHash), + attribute.Bool("fscache", settings.FsCache), + attribute.Bool("nocopy", settings.NoCopy), + attribute.Bool("silent", settings.Silent), + attribute.Bool("progress", settings.Progress), + ) + cfg, err := api.repo.Config() if err != nil { return nil, err @@ -179,6 +201,9 @@ func (api *UnixfsAPI) Add(ctx context.Context, files files.Node, opts ...options } func (api *UnixfsAPI) Get(ctx context.Context, p path.Path) (files.Node, error) { + ctx, span := tracing.Span(ctx, "CoreAPI.UnixfsAPI", "Get", trace.WithAttributes(attribute.String("path", p.String()))) + defer span.End() + ses := api.core().getSession(ctx) nd, err := ses.ResolveNode(ctx, p) @@ -192,11 +217,16 @@ func (api *UnixfsAPI) Get(ctx context.Context, p path.Path) (files.Node, error) // Ls returns the contents of an IPFS or IPNS object(s) at path p, with the format: // ` ` func (api *UnixfsAPI) Ls(ctx context.Context, p path.Path, opts ...options.UnixfsLsOption) (<-chan coreiface.DirEntry, error) { + ctx, span := tracing.Span(ctx, "CoreAPI.UnixfsAPI", "Ls", trace.WithAttributes(attribute.String("path", p.String()))) + defer span.End() + settings, err := options.UnixfsLsOptions(opts...) if err != nil { return nil, err } + span.SetAttributes(attribute.Bool("resolvechildren", settings.ResolveChildren)) + ses := api.core().getSession(ctx) uses := (*UnixfsAPI)(ses) @@ -217,6 +247,13 @@ func (api *UnixfsAPI) Ls(ctx context.Context, p path.Path, opts ...options.Unixf } func (api *UnixfsAPI) processLink(ctx context.Context, linkres ft.LinkResult, settings *options.UnixfsLsSettings) coreiface.DirEntry { + ctx, span := tracing.Span(ctx, "CoreAPI.UnixfsAPI", "ProcessLink") + defer span.End() + if linkres.Link != nil { + span.SetAttributes(attribute.String("linkname", linkres.Link.Name), attribute.String("cid", linkres.Link.Cid.String())) + + } + if linkres.Err != nil { return coreiface.DirEntry{Err: linkres.Err} } diff --git a/core/corehttp/gateway.go b/core/corehttp/gateway.go index fb1524da529..2e794b53ffc 100644 --- a/core/corehttp/gateway.go +++ b/core/corehttp/gateway.go @@ -9,6 +9,7 @@ import ( version "github.com/ipfs/go-ipfs" core "github.com/ipfs/go-ipfs/core" coreapi "github.com/ipfs/go-ipfs/core/coreapi" + "go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp" options "github.com/ipfs/interface-go-ipfs-core/options" id "github.com/libp2p/go-libp2p/p2p/protocol/identify" @@ -87,12 +88,14 @@ func GatewayOption(writable bool, paths ...string) ServeOption { "X-Stream-Output", }, headers[ACEHeadersName]...)) - gateway := newGatewayHandler(GatewayConfig{ + var gateway http.Handler = newGatewayHandler(GatewayConfig{ Headers: headers, Writable: writable, PathPrefixes: cfg.Gateway.PathPrefixes, }, api) + gateway = otelhttp.NewHandler(gateway, "Gateway.Request") + for _, p := range paths { mux.Handle(p+"/", gateway) } diff --git a/core/corehttp/gateway_handler.go b/core/corehttp/gateway_handler.go index 6d90dd0080a..32d2eebaef8 100644 --- a/core/corehttp/gateway_handler.go +++ b/core/corehttp/gateway_handler.go @@ -26,6 +26,8 @@ import ( ipath "github.com/ipfs/interface-go-ipfs-core/path" routing "github.com/libp2p/go-libp2p-core/routing" prometheus "github.com/prometheus/client_golang/prometheus" + "go.opentelemetry.io/otel/attribute" + "go.opentelemetry.io/otel/trace" ) const ( @@ -354,6 +356,8 @@ func (i *gatewayHandler) getOrHeadHandler(w http.ResponseWriter, r *http.Request webError(w, "error while processing the Accept header", err, http.StatusBadRequest) return } + trace.SpanFromContext(r.Context()).SetAttributes(attribute.String("ResponseFormat", responseFormat)) + trace.SpanFromContext(r.Context()).SetAttributes(attribute.String("ResolvedPath", resolvedPath.String())) // Finish early if client already has matching Etag if r.Header.Get("If-None-Match") == getEtag(r, resolvedPath.Cid()) { @@ -392,12 +396,12 @@ func (i *gatewayHandler) getOrHeadHandler(w http.ResponseWriter, r *http.Request return case "application/vnd.ipld.raw": logger.Debugw("serving raw block", "path", contentPath) - i.serveRawBlock(w, r, resolvedPath.Cid(), contentPath, begin) + i.serveRawBlock(w, r, resolvedPath, contentPath, begin) return case "application/vnd.ipld.car": logger.Debugw("serving car stream", "path", contentPath) carVersion := formatParams["version"] - i.serveCar(w, r, resolvedPath.Cid(), contentPath, carVersion, begin) + i.serveCar(w, r, resolvedPath, contentPath, carVersion, begin) return default: // catch-all for unsuported application/vnd.* err := fmt.Errorf("unsupported format %q", responseFormat) diff --git a/core/corehttp/gateway_handler_block.go b/core/corehttp/gateway_handler_block.go index 13d7ebefd9f..891c418c87a 100644 --- a/core/corehttp/gateway_handler_block.go +++ b/core/corehttp/gateway_handler_block.go @@ -6,13 +6,18 @@ import ( "net/http" "time" - cid "github.com/ipfs/go-cid" + "github.com/ipfs/go-ipfs/tracing" ipath "github.com/ipfs/interface-go-ipfs-core/path" + "go.opentelemetry.io/otel/attribute" + "go.opentelemetry.io/otel/trace" ) // serveRawBlock returns bytes behind a raw block -func (i *gatewayHandler) serveRawBlock(w http.ResponseWriter, r *http.Request, blockCid cid.Cid, contentPath ipath.Path, begin time.Time) { - blockReader, err := i.api.Block().Get(r.Context(), contentPath) +func (i *gatewayHandler) serveRawBlock(w http.ResponseWriter, r *http.Request, resolvedPath ipath.Resolved, contentPath ipath.Path, begin time.Time) { + ctx, span := tracing.Span(r.Context(), "Gateway", "ServeRawBlock", trace.WithAttributes(attribute.String("path", resolvedPath.String()))) + defer span.End() + blockCid := resolvedPath.Cid() + blockReader, err := i.api.Block().Get(ctx, resolvedPath) if err != nil { webError(w, "ipfs block get "+blockCid.String(), err, http.StatusInternalServerError) return diff --git a/core/corehttp/gateway_handler_car.go b/core/corehttp/gateway_handler_car.go index c6587e564f4..d7dca46b381 100644 --- a/core/corehttp/gateway_handler_car.go +++ b/core/corehttp/gateway_handler_car.go @@ -8,15 +8,20 @@ import ( blocks "github.com/ipfs/go-block-format" cid "github.com/ipfs/go-cid" + "github.com/ipfs/go-ipfs/tracing" coreiface "github.com/ipfs/interface-go-ipfs-core" ipath "github.com/ipfs/interface-go-ipfs-core/path" gocar "github.com/ipld/go-car" selectorparse "github.com/ipld/go-ipld-prime/traversal/selector/parse" + "go.opentelemetry.io/otel/attribute" + "go.opentelemetry.io/otel/trace" ) // serveCar returns a CAR stream for specific DAG+selector -func (i *gatewayHandler) serveCar(w http.ResponseWriter, r *http.Request, rootCid cid.Cid, contentPath ipath.Path, carVersion string, begin time.Time) { - ctx, cancel := context.WithCancel(r.Context()) +func (i *gatewayHandler) serveCar(w http.ResponseWriter, r *http.Request, resolvedPath ipath.Resolved, contentPath ipath.Path, carVersion string, begin time.Time) { + ctx, span := tracing.Span(r.Context(), "Gateway", "ServeCar", trace.WithAttributes(attribute.String("path", resolvedPath.String()))) + defer span.End() + ctx, cancel := context.WithCancel(ctx) defer cancel() switch carVersion { @@ -27,6 +32,7 @@ func (i *gatewayHandler) serveCar(w http.ResponseWriter, r *http.Request, rootCi webError(w, "unsupported CAR version", err, http.StatusBadRequest) return } + rootCid := resolvedPath.Cid() // Set Content-Disposition name := rootCid.String() + ".car" diff --git a/core/corehttp/gateway_handler_unixfs.go b/core/corehttp/gateway_handler_unixfs.go index ed15f41393b..2252b3891c6 100644 --- a/core/corehttp/gateway_handler_unixfs.go +++ b/core/corehttp/gateway_handler_unixfs.go @@ -7,13 +7,18 @@ import ( "time" files "github.com/ipfs/go-ipfs-files" + "github.com/ipfs/go-ipfs/tracing" ipath "github.com/ipfs/interface-go-ipfs-core/path" + "go.opentelemetry.io/otel/attribute" + "go.opentelemetry.io/otel/trace" "go.uber.org/zap" ) func (i *gatewayHandler) serveUnixFs(w http.ResponseWriter, r *http.Request, resolvedPath ipath.Resolved, contentPath ipath.Path, begin time.Time, logger *zap.SugaredLogger) { + ctx, span := tracing.Span(r.Context(), "Gateway", "ServeUnixFs", trace.WithAttributes(attribute.String("path", resolvedPath.String()))) + defer span.End() // Handling UnixFS - dr, err := i.api.Unixfs().Get(r.Context(), resolvedPath) + dr, err := i.api.Unixfs().Get(ctx, resolvedPath) if err != nil { webError(w, "ipfs cat "+html.EscapeString(contentPath.String()), err, http.StatusNotFound) return @@ -23,7 +28,7 @@ func (i *gatewayHandler) serveUnixFs(w http.ResponseWriter, r *http.Request, res // Handling Unixfs file if f, ok := dr.(files.File); ok { logger.Debugw("serving unixfs file", "path", contentPath) - i.serveFile(w, r, contentPath, resolvedPath.Cid(), f, begin) + i.serveFile(w, r, resolvedPath, contentPath, f, begin) return } diff --git a/core/corehttp/gateway_handler_unixfs_dir.go b/core/corehttp/gateway_handler_unixfs_dir.go index 87708159e8e..e458e803076 100644 --- a/core/corehttp/gateway_handler_unixfs_dir.go +++ b/core/corehttp/gateway_handler_unixfs_dir.go @@ -10,9 +10,12 @@ import ( "github.com/dustin/go-humanize" files "github.com/ipfs/go-ipfs-files" "github.com/ipfs/go-ipfs/assets" + "github.com/ipfs/go-ipfs/tracing" path "github.com/ipfs/go-path" "github.com/ipfs/go-path/resolver" ipath "github.com/ipfs/interface-go-ipfs-core/path" + "go.opentelemetry.io/otel/attribute" + "go.opentelemetry.io/otel/trace" "go.uber.org/zap" ) @@ -20,6 +23,8 @@ import ( // // It will return index.html if present, or generate directory listing otherwise. func (i *gatewayHandler) serveDirectory(w http.ResponseWriter, r *http.Request, resolvedPath ipath.Resolved, contentPath ipath.Path, dir files.Directory, begin time.Time, logger *zap.SugaredLogger) { + ctx, span := tracing.Span(r.Context(), "Gateway", "ServeDirectory", trace.WithAttributes(attribute.String("path", resolvedPath.String()))) + defer span.End() // HostnameOption might have constructed an IPNS/IPFS path using the Host header. // In this case, we need the original path for constructing redirects @@ -35,7 +40,7 @@ func (i *gatewayHandler) serveDirectory(w http.ResponseWriter, r *http.Request, // Check if directory has index.html, if so, serveFile idxPath := ipath.Join(resolvedPath, "index.html") - idx, err := i.api.Unixfs().Get(r.Context(), idxPath) + idx, err := i.api.Unixfs().Get(ctx, idxPath) switch err.(type) { case nil: cpath := contentPath.String() @@ -63,7 +68,7 @@ func (i *gatewayHandler) serveDirectory(w http.ResponseWriter, r *http.Request, logger.Debugw("serving index.html file", "path", idxPath) // write to request - i.serveFile(w, r, idxPath, resolvedPath.Cid(), f, begin) + i.serveFile(w, r, resolvedPath, idxPath, f, begin) return case resolver.ErrNoLink: logger.Debugw("no index.html; noop", "path", idxPath) @@ -111,7 +116,7 @@ func (i *gatewayHandler) serveDirectory(w http.ResponseWriter, r *http.Request, size = humanize.Bytes(uint64(s)) } - resolved, err := i.api.ResolvePath(r.Context(), ipath.Join(resolvedPath, dirit.Name())) + resolved, err := i.api.ResolvePath(ctx, ipath.Join(resolvedPath, dirit.Name())) if err != nil { internalWebError(w, err) return diff --git a/core/corehttp/gateway_handler_unixfs_file.go b/core/corehttp/gateway_handler_unixfs_file.go index 9807969fee0..e8a3718fc16 100644 --- a/core/corehttp/gateway_handler_unixfs_file.go +++ b/core/corehttp/gateway_handler_unixfs_file.go @@ -10,17 +10,21 @@ import ( "time" "github.com/gabriel-vasile/mimetype" - cid "github.com/ipfs/go-cid" files "github.com/ipfs/go-ipfs-files" + "github.com/ipfs/go-ipfs/tracing" ipath "github.com/ipfs/interface-go-ipfs-core/path" + "go.opentelemetry.io/otel/attribute" + "go.opentelemetry.io/otel/trace" ) // serveFile returns data behind a file along with HTTP headers based on // the file itself, its CID and the contentPath used for accessing it. -func (i *gatewayHandler) serveFile(w http.ResponseWriter, r *http.Request, contentPath ipath.Path, fileCid cid.Cid, file files.File, begin time.Time) { +func (i *gatewayHandler) serveFile(w http.ResponseWriter, r *http.Request, resolvedPath ipath.Resolved, contentPath ipath.Path, file files.File, begin time.Time) { + _, span := tracing.Span(r.Context(), "Gateway", "ServeFile", trace.WithAttributes(attribute.String("path", resolvedPath.String()))) + defer span.End() // Set Cache-Control and read optional Last-Modified time - modtime := addCacheControlHeaders(w, r, contentPath, fileCid) + modtime := addCacheControlHeaders(w, r, contentPath, resolvedPath.Cid()) // Set Content-Disposition name := addContentDispositionHeader(w, r, contentPath) diff --git a/core/coreunix/add.go b/core/coreunix/add.go index 387a977784d..a0079b9eb07 100644 --- a/core/coreunix/add.go +++ b/core/coreunix/add.go @@ -14,6 +14,7 @@ import ( files "github.com/ipfs/go-ipfs-files" pin "github.com/ipfs/go-ipfs-pinner" posinfo "github.com/ipfs/go-ipfs-posinfo" + "github.com/ipfs/go-ipfs/tracing" ipld "github.com/ipfs/go-ipld-format" logging "github.com/ipfs/go-log" dag "github.com/ipfs/go-merkledag" @@ -158,20 +159,23 @@ func (adder *Adder) curRootNode() (ipld.Node, error) { // Recursively pins the root node of Adder and // writes the pin state to the backing datastore. -func (adder *Adder) PinRoot(root ipld.Node) error { +func (adder *Adder) PinRoot(ctx context.Context, root ipld.Node) error { + ctx, span := tracing.Span(ctx, "CoreUnix.Adder", "PinRoot") + defer span.End() + if !adder.Pin { return nil } rnk := root.Cid() - err := adder.dagService.Add(adder.ctx, root) + err := adder.dagService.Add(ctx, root) if err != nil { return err } if adder.tempRoot.Defined() { - err := adder.pinning.Unpin(adder.ctx, adder.tempRoot, true) + err := adder.pinning.Unpin(ctx, adder.tempRoot, true) if err != nil { return err } @@ -179,7 +183,7 @@ func (adder *Adder) PinRoot(root ipld.Node) error { } adder.pinning.PinWithMode(rnk, pin.Recursive) - return adder.pinning.Flush(adder.ctx) + return adder.pinning.Flush(ctx) } func (adder *Adder) outputDirs(path string, fsn mfs.FSNode) error { @@ -255,6 +259,9 @@ func (adder *Adder) addNode(node ipld.Node, path string) error { // AddAllAndPin adds the given request's files and pin them. func (adder *Adder) AddAllAndPin(ctx context.Context, file files.Node) (ipld.Node, error) { + ctx, span := tracing.Span(ctx, "CoreUnix.Adder", "AddAllAndPin") + defer span.End() + if adder.Pin { adder.unlocker = adder.gcLocker.PinLock(ctx) } @@ -330,10 +337,13 @@ func (adder *Adder) AddAllAndPin(ctx context.Context, file files.Node) (ipld.Nod if !adder.Pin { return nd, nil } - return nd, adder.PinRoot(nd) + return nd, adder.PinRoot(ctx, nd) } func (adder *Adder) addFileNode(ctx context.Context, path string, file files.Node, toplevel bool) error { + ctx, span := tracing.Span(ctx, "CoreUnix.Adder", "AddFileNode") + defer span.End() + defer file.Close() err := adder.maybePauseForGC(ctx) @@ -436,13 +446,16 @@ func (adder *Adder) addDir(ctx context.Context, path string, dir files.Directory } func (adder *Adder) maybePauseForGC(ctx context.Context) error { + ctx, span := tracing.Span(ctx, "CoreUnix.Adder", "MaybePauseForGC") + defer span.End() + if adder.unlocker != nil && adder.gcLocker.GCRequested(ctx) { rn, err := adder.curRootNode() if err != nil { return err } - err = adder.PinRoot(rn) + err = adder.PinRoot(ctx, rn) if err != nil { return err } diff --git a/docs/debug-guide.md b/docs/debug-guide.md index 07439c37cfe..5bb39eee564 100644 --- a/docs/debug-guide.md +++ b/docs/debug-guide.md @@ -7,6 +7,7 @@ This is a document for helping debug go-ipfs. Please add to it if you can! - [Analyzing the stack dump](#analyzing-the-stack-dump) - [Analyzing the CPU Profile](#analyzing-the-cpu-profile) - [Analyzing vars and memory statistics](#analyzing-vars-and-memory-statistics) +- [Tracing](#tracing) - [Other](#other) ### Beginning @@ -95,6 +96,11 @@ the quickest way to easily point out where the hot spots in the code are. The output is JSON formatted and includes badger store statistics, the command line run, and the output from Go's [runtime.ReadMemStats](https://golang.org/pkg/runtime/#ReadMemStats). The [MemStats](https://golang.org/pkg/runtime/#MemStats) has useful information about memory allocation and garbage collection. +### Tracing + +Experimental tracing via OpenTelemetry suite of tools is available. +See `tracing/doc.go` for more details. + ### Other If you have any questions, or want us to analyze some weird go-ipfs behaviour, diff --git a/docs/environment-variables.md b/docs/environment-variables.md index 174e283f9fc..aad022e3b9d 100644 --- a/docs/environment-variables.md +++ b/docs/environment-variables.md @@ -102,3 +102,73 @@ Deprecated: Use the `Swarm.Transports.Multiplexers` config field. Tells go-ipfs which multiplexers to use in which order. Default: "/yamux/1.0.0 /mplex/6.7.0" + +# Tracing +**NOTE** Tracing support is experimental--releases may contain tracing-related breaking changes. + +## `IPFS_TRACING` +Enables OpenTelemetry tracing. + +Default: false + +## `IPFS_TRACING_JAEGER` +Enables the Jaeger exporter for OpenTelemetry. + +For additional Jaeger exporter configuration, see: https://github.com/open-telemetry/opentelemetry-specification/blob/main/specification/sdk-environment-variables.md#jaeger-exporter + +Default: false + +### How to use Jaeger UI + +One can use the `jaegertracing/all-in-one` Docker image to run a full Jaeger +stack and configure go-ipfs to publish traces to it (here, in an ephemeral +container): + +```console +$ docker run --rm -it --name jaeger \ + -e COLLECTOR_ZIPKIN_HOST_PORT=:9411 \ + -p 5775:5775/udp \ + -p 6831:6831/udp \ + -p 6832:6832/udp \ + -p 5778:5778 \ + -p 16686:16686 \ + -p 14268:14268 \ + -p 14250:14250 \ + -p 9411:9411 \ + jaegertracing/all-in-one +``` + +Then, in other terminal, start go-ipfs with Jaeger tracing enabled: +``` +$ IPFS_TRACING=1 IPFS_TRACING_JAEGER=1 ipfs daemon +``` + +Finally, the [Jaeger UI](https://github.com/jaegertracing/jaeger-ui#readme) is available at http://localhost:16686 + + +## `IPFS_TRACING_OTLP_HTTP` +Enables the OTLP HTTP exporter for OpenTelemetry. + +For additional exporter configuration, see: https://github.com/open-telemetry/opentelemetry-specification/blob/main/specification/protocol/exporter.md + +Default: false + +## `IPFS_TRACING_OTLP_GRPC` +Enables the OTLP gRPC exporter for OpenTelemetry. + +For additional exporter configuration, see: https://github.com/open-telemetry/opentelemetry-specification/blob/main/specification/protocol/exporter.md + +Default: false + +## `IPFS_TRACING_FILE` +Enables the file exporter for OpenTelemetry, writing traces to the given file in JSON format. + +Example: "/var/log/ipfs-traces.json" + +Default: "" (disabled) + +## `IPFS_TRACING_RATIO` +The ratio of traces to export, as a floating point value in the interval [0, 1]. + +Deault: 1.0 (export all traces) + diff --git a/go.mod b/go.mod index f0b97ccc1c4..a58cc03dbba 100644 --- a/go.mod +++ b/go.mod @@ -107,6 +107,14 @@ require ( go.uber.org/dig v1.14.0 go.uber.org/fx v1.16.0 go.uber.org/zap v1.21.0 + go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.27.0 + go.opentelemetry.io/otel v1.2.0 + go.opentelemetry.io/otel/exporters/jaeger v1.2.0 + go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.2.0 + go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp v1.2.0 + go.opentelemetry.io/otel/exporters/stdout/stdouttrace v1.2.0 + go.opentelemetry.io/otel/sdk v1.2.0 + go.opentelemetry.io/otel/trace v1.2.0 golang.org/x/crypto v0.0.0-20210921155107-089bfa567519 golang.org/x/sync v0.0.0-20210220032951-036812b2e83c golang.org/x/sys v0.0.0-20211025112917-711f33c9992c diff --git a/go.sum b/go.sum index 496708baef5..ca9b74ab34e 100644 --- a/go.sum +++ b/go.sum @@ -118,6 +118,8 @@ github.com/buger/jsonparser v0.0.0-20181115193947-bf1c66bbce23/go.mod h1:bbYlZJ7 github.com/casbin/casbin/v2 v2.1.2/go.mod h1:YcPU1XXisHhLzuxH9coDNf2FbKpjGlbCg3n9yuLkIJQ= github.com/cenkalti/backoff v2.2.1+incompatible h1:tNowT99t7UNflLxfYYSlKYsBpXdEet03Pg2g16Swow4= github.com/cenkalti/backoff v2.2.1+incompatible/go.mod h1:90ReRw6GdpyfrHakVjL/QHaoyV4aDUVVkXQJJJ3NXXM= +github.com/cenkalti/backoff/v4 v4.1.1 h1:G2HAfAmvm/GcKan2oOQpBXOd2tT2G57ZnZGWa1PxPBQ= +github.com/cenkalti/backoff/v4 v4.1.1/go.mod h1:scbssz8iZGpm3xbr14ovlUdkxfGXNInqkPWOWmG2CLw= github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU= github.com/ceramicnetwork/go-dag-jose v0.1.0 h1:yJ/HVlfKpnD3LdYP03AHyTvbm3BpPiz2oZiOeReJRdU= github.com/ceramicnetwork/go-dag-jose v0.1.0/go.mod h1:qYA1nYt0X8u4XoMAVoOV3upUVKtrxy/I670Dg5F0wjI= @@ -136,7 +138,11 @@ github.com/clbanning/x2j v0.0.0-20191024224557-825249438eec/go.mod h1:jMjuTZXRI4 github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw= github.com/cncf/udpa/go v0.0.0-20191209042840-269d4d468f6f/go.mod h1:M8M6+tZqaGXZJjfX53e64911xZQV5JYwmTeXPW+k8Sc= github.com/cncf/udpa/go v0.0.0-20201120205902-5459f2c99403/go.mod h1:WmhPx2Nbnhtbo57+VJT5O0JRkEi1Wbu0z5j0R8u5Hbk= +github.com/cncf/udpa/go v0.0.0-20210930031921-04548b0d99d4/go.mod h1:6pvJx4me5XPnfI9Z40ddWsdw2W/uZgQLFXToKeRcDiI= github.com/cncf/xds/go v0.0.0-20210312221358-fbca930ec8ed/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs= +github.com/cncf/xds/go v0.0.0-20210805033703-aa0b78936158/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs= +github.com/cncf/xds/go v0.0.0-20210922020428-25de7278fc84/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs= +github.com/cncf/xds/go v0.0.0-20211011173535-cb28da3451f1/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs= github.com/cockroachdb/datadriven v0.0.0-20190809214429-80d97fb3cbaa/go.mod h1:zn76sxSg3SzpJ0PPJaLDCu+Bu0Lg3sKTORVIj19EIF8= github.com/codahale/hdrhistogram v0.0.0-20161010025455-3a0bb77429bd/go.mod h1:sE/e/2PUdi/liOCUjSTXgM1o87ZssimdTWN964YiIeI= github.com/coreos/etcd v3.3.10+incompatible/go.mod h1:uF7uidLiAD3TWHmW31ZFd/JWoc32PjwdhPthX9715RE= @@ -195,12 +201,15 @@ github.com/envoyproxy/go-control-plane v0.9.1-0.20191026205805-5f8ba28d4473/go.m github.com/envoyproxy/go-control-plane v0.9.4/go.mod h1:6rpuAdCZL397s3pYoYcLgu1mIlRU8Am5FuJP05cCM98= github.com/envoyproxy/go-control-plane v0.9.9-0.20201210154907-fd9021fe5dad/go.mod h1:cXg6YxExXjJnVBQHBLXeUAgxn2UodCpnH306RInaBQk= github.com/envoyproxy/go-control-plane v0.9.9-0.20210512163311-63b5d3c536b0/go.mod h1:hliV/p42l8fGbc6Y9bQ70uLwIvmJyVE5k4iMKlh8wCQ= +github.com/envoyproxy/go-control-plane v0.9.10-0.20210907150352-cf90f659a021/go.mod h1:AFq3mo9L8Lqqiid3OhADV3RfLJnjiw63cSpi+fDTRC0= github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c= github.com/facebookgo/atomicfile v0.0.0-20151019160806-2de1f203e7d5 h1:BBso6MBKW8ncyZLv37o+KNyy0HrrHgfnOaGQC2qvN+A= github.com/facebookgo/atomicfile v0.0.0-20151019160806-2de1f203e7d5/go.mod h1:JpoxHjuQauoxiFMl1ie8Xc/7TfLuMZ5eOCONd1sUBHg= github.com/fatih/color v1.7.0/go.mod h1:Zm6kSWBoL9eyXnKyktHP6abPY2pDugNf5KwzbycvMj4= github.com/fatih/color v1.9.0 h1:8xPHl4/q1VyqGIPif1F+1V3Y3lSmrq01EabUW3CoW5s= github.com/fatih/color v1.9.0/go.mod h1:eQcE1qtQxscV5RaZvpXrrb8Drkc3/DdQ+uUYCNjL+zU= +github.com/felixge/httpsnoop v1.0.2 h1:+nS9g82KMXccJ/wp0zyRW9ZBHFETmMGtkk+2CTTrW4o= +github.com/felixge/httpsnoop v1.0.2/go.mod h1:m8KPJKqk1gH5J9DgRY2ASl2lWCfGKXixSwevea8zH2U= github.com/flynn/go-shlex v0.0.0-20150515145356-3f9db97f8568/go.mod h1:xEzjJPgXI435gkrCt3MPfRiAkVrwSbHsst4LCFVfpJc= github.com/flynn/noise v0.0.0-20180327030543-2492fe189ae6/go.mod h1:1i71OnUq3iUe1ma7Lr6yG6/rjvM3emb6yoL7xLFzcVQ= github.com/flynn/noise v1.0.0 h1:DlTHqmzmvcEiKj+4RYo/imoswx/4r6iBlCMfVtrMXpQ= @@ -345,6 +354,7 @@ github.com/grpc-ecosystem/go-grpc-middleware v1.0.1-0.20190118093823-f849b5445de github.com/grpc-ecosystem/go-grpc-prometheus v1.2.0/go.mod h1:8NvIoxWQoOIhqOTXgfV/d3M/q6VIi02HzZEHgUlZvzk= github.com/grpc-ecosystem/grpc-gateway v1.5.0/go.mod h1:RSKVYQBd5MCa4OVpNdGskqpgL2+G+NZTnrVHpWWfpdw= github.com/grpc-ecosystem/grpc-gateway v1.9.5/go.mod h1:vNeuVxBJEsws4ogUvrchl83t/GYV9WGTSLVdBhOQFDY= +github.com/grpc-ecosystem/grpc-gateway v1.16.0 h1:gmcG1KaJ57LophUzW0Hy8NmPhnMZb4M0+kPpLofRdBo= github.com/grpc-ecosystem/grpc-gateway v1.16.0/go.mod h1:BDjrQk3hbvj6Nolgz8mAMFbcEtjT1g+wF4CSlocrBnw= github.com/gxed/hashland/keccakpg v0.0.1/go.mod h1:kRzw3HkwxFU1mpmPP8v1WyQzwdGfmKFJ6tItnhQ67kU= github.com/gxed/hashland/murmur3 v0.0.1/go.mod h1:KjXop02n4/ckmZSnY2+HKcLud/tcmvhST0bie/0lS48= @@ -1326,6 +1336,7 @@ github.com/streadway/amqp v0.0.0-20190404075320-75d898a42a94/go.mod h1:AZpEONHx3 github.com/streadway/amqp v0.0.0-20190827072141-edfb9018d271/go.mod h1:AZpEONHx3DKn8O/DFsRAY58/XVQiIPMTMB1SddzLXVw= github.com/streadway/handy v0.0.0-20190108123426-d5acb3125c2a/go.mod h1:qNTQ5P5JnDBl6z3cMAg/SywNDC5ABu5ApDIw6lUbRmI= github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= +github.com/stretchr/objx v0.1.1 h1:2vfRuCMp5sSVIDSqO8oNnWJq7mPa6KVP3iPIwFBuy8A= github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs= github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= @@ -1400,15 +1411,35 @@ go.opencensus.io v0.22.3/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw= go.opencensus.io v0.22.4/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw= go.opencensus.io v0.23.0 h1:gqCw0LfLxScz8irSi8exQc7fyQ0fKQU/qnC/X8+V/1M= go.opencensus.io v0.23.0/go.mod h1:XItmlyltB5F7CS4xOC1DcqMoFqwtC6OG2xF7mCv7P7E= -go.opentelemetry.io/otel v0.20.0 h1:eaP0Fqu7SXHwvjiqDq83zImeehOHX8doTvU9AwXON8g= +go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.27.0 h1:0BgiNWjN7rUWO9HdjF4L12r8OW86QkVQcYmCjnayJLo= +go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.27.0/go.mod h1:bdvm3YpMxWAgEfQhtTBaVR8ceXPRuRBSQrvOBnIlHxc= go.opentelemetry.io/otel v0.20.0/go.mod h1:Y3ugLH2oa81t5QO+Lty+zXf8zC9L26ax4Nzoxm/dooo= -go.opentelemetry.io/otel/metric v0.20.0 h1:4kzhXFP+btKm4jwxpjIqjs41A7MakRFUS86bqLHTIw8= +go.opentelemetry.io/otel v1.2.0 h1:YOQDvxO1FayUcT9MIhJhgMyNO1WqoduiyvQHzGN0kUQ= +go.opentelemetry.io/otel v1.2.0/go.mod h1:aT17Fk0Z1Nor9e0uisf98LrntPGMnk4frBO9+dkf69I= +go.opentelemetry.io/otel/exporters/jaeger v1.2.0 h1:C/5Egj3MJBXRJi22cSl07suqPqtZLnLFmH//OxETUEc= +go.opentelemetry.io/otel/exporters/jaeger v1.2.0/go.mod h1:KJLFbEMKTNPIfOxcg/WikIozEoKcPgJRz3Ce1vLlM8E= +go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.2.0 h1:xzbcGykysUh776gzD1LUPsNNHKWN0kQWDnJhn1ddUuk= +go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.2.0/go.mod h1:14T5gr+Y6s2AgHPqBMgnGwp04csUjQmYXFWPeiBoq5s= +go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.2.0 h1:VsgsSCDwOSuO8eMVh63Cd4nACMqgjpmAeJSIvVNneD0= +go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.2.0/go.mod h1:9mLBBnPRf3sf+ASVH2p9xREXVBvwib02FxcKnavtExg= +go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp v1.2.0 h1:j/jXNzS6Dy0DFgO/oyCvin4H7vTQBg2Vdi6idIzWhCI= +go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp v1.2.0/go.mod h1:k5GnE4m4Jyy2DNh6UAzG6Nml51nuqQyszV7O1ksQAnE= +go.opentelemetry.io/otel/exporters/stdout/stdouttrace v1.2.0 h1:OiYdrCq1Ctwnovp6EofSPwlp5aGy4LgKNbkg7PtEUw8= +go.opentelemetry.io/otel/exporters/stdout/stdouttrace v1.2.0/go.mod h1:DUFCmFkXr0VtAHl5Zq2JRx24G6ze5CAq8YfdD36RdX8= +go.opentelemetry.io/otel/internal/metric v0.25.0 h1:w/7RXe16WdPylaIXDgcYM6t/q0K5lXgSdZOEbIEyliE= +go.opentelemetry.io/otel/internal/metric v0.25.0/go.mod h1:Nhuw26QSX7d6n4duoqAFi5KOQR4AuzyMcl5eXOgwxtc= go.opentelemetry.io/otel/metric v0.20.0/go.mod h1:598I5tYlH1vzBjn+BTuhzTCSb/9debfNp6R3s7Pr1eU= -go.opentelemetry.io/otel/oteltest v0.20.0 h1:HiITxCawalo5vQzdHfKeZurV8x7ljcqAgiWzF6Vaeaw= +go.opentelemetry.io/otel/metric v0.25.0 h1:7cXOnCADUsR3+EOqxPaSKwhEuNu0gz/56dRN1hpIdKw= +go.opentelemetry.io/otel/metric v0.25.0/go.mod h1:E884FSpQfnJOMMUaq+05IWlJ4rjZpk2s/F1Ju+TEEm8= go.opentelemetry.io/otel/oteltest v0.20.0/go.mod h1:L7bgKf9ZB7qCwT9Up7i9/pn0PWIa9FqQ2IQ8LoxiGnw= -go.opentelemetry.io/otel/trace v0.20.0 h1:1DL6EXUdcg95gukhuRRvLDO/4X5THh/5dIV52lqtnbw= +go.opentelemetry.io/otel/sdk v1.2.0 h1:wKN260u4DesJYhyjxDa7LRFkuhH7ncEVKU37LWcyNIo= +go.opentelemetry.io/otel/sdk v1.2.0/go.mod h1:jNN8QtpvbsKhgaC6V5lHiejMoKD+V8uadoSafgHPx1U= go.opentelemetry.io/otel/trace v0.20.0/go.mod h1:6GjCW8zgDjwGHGa6GkyeB8+/5vjT16gUEi0Nf1iBdgw= +go.opentelemetry.io/otel/trace v1.2.0 h1:Ys3iqbqZhcf28hHzrm5WAquMkDHNZTUkw7KHbuNjej0= +go.opentelemetry.io/otel/trace v1.2.0/go.mod h1:N5FLswTubnxKxOJHM7XZC074qpeEdLy3CgAVsdMucK0= go.opentelemetry.io/proto/otlp v0.7.0/go.mod h1:PqfVotwruBrMGOCsRd/89rSnXhoiJIqeYNgFYFoEGnI= +go.opentelemetry.io/proto/otlp v0.10.0 h1:n7brgtEbDvXEgGyKKo8SobKT1e9FewlDtXzkVP5djoE= +go.opentelemetry.io/proto/otlp v0.10.0/go.mod h1:zG20xCK0szZ1xdokeSOwEcmlXu+x9kkdRe6N1DhKcfU= go.uber.org/atomic v1.3.2/go.mod h1:gD2HeocX3+yG+ygLZcrzQJaqmWj9AIm7n08wl/qW/PE= go.uber.org/atomic v1.4.0/go.mod h1:gD2HeocX3+yG+ygLZcrzQJaqmWj9AIm7n08wl/qW/PE= go.uber.org/atomic v1.5.0/go.mod h1:sABNBOSYdrvTF6hTgEIbc7YasKWGhgEQZyfxyTvoXHQ= @@ -1663,6 +1694,7 @@ golang.org/x/sys v0.0.0-20210315160823-c6e025ad8005/go.mod h1:h1NjWce9XRLGQEsW7w golang.org/x/sys v0.0.0-20210317225723-c4fcb01b228e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210330210617-4fbd30eecc44/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210423185535-09eb48e85fd7/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210426080607-c94f62235c83/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210510120138-977fb7262007/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20210511113859-b0526f3d8744/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= @@ -1841,8 +1873,10 @@ google.golang.org/grpc v1.31.1/go.mod h1:N36X2cJ7JwdamYAgDz+s+rVMFjt3numwzf/HckM google.golang.org/grpc v1.33.1/go.mod h1:fr5YgcSWrqhRRxogOsw7RzIpsmvOZ6IcH4kBYTpR3n0= google.golang.org/grpc v1.33.2/go.mod h1:JMHMWHQWaTccqQQlmk3MJZS+GWXOdAesneDmEnv2fbc= google.golang.org/grpc v1.36.0/go.mod h1:qjiiYl8FncCW8feJPdyg3v6XW24KsRHe+dy9BAGRRjU= -google.golang.org/grpc v1.40.0 h1:AGJ0Ih4mHjSeibYkFGh1dD9KJ/eOtZ93I6hoHhukQ5Q= google.golang.org/grpc v1.40.0/go.mod h1:ogyxbiOoUXAkP+4+xa6PZSE9DZgIHtSpzjDTB9KAK34= +google.golang.org/grpc v1.41.0/go.mod h1:U3l9uK9J0sini8mHphKoXyaqDA/8VyGnDee1zzIUK6k= +google.golang.org/grpc v1.42.0 h1:XT2/MFpuPFsEX2fWh3YQtHkZ+WYZFQRfaUgLZYj/p6A= +google.golang.org/grpc v1.42.0/go.mod h1:k+4IHHFw41K8+bbowsex27ge2rCb65oeWqe4jJ590SU= google.golang.org/protobuf v0.0.0-20200109180630-ec00e32a8dfd/go.mod h1:DFci5gLYBciE7Vtevhsrf46CRTquxDuWsQurQQe4oz8= google.golang.org/protobuf v0.0.0-20200221191635-4d8936d0db64/go.mod h1:kwYJMbMJ01Woi6D6+Kah6886xMZcty6N08ah7+eCXa0= google.golang.org/protobuf v0.0.0-20200228230310-ab0ca4ff8a60/go.mod h1:cfTl7dwQJ+fmap5saPgwCLgHXTUD7jkjRqWcaiX5VyM= diff --git a/mk/golang.mk b/mk/golang.mk index 0b2a2c55ae2..7ede944637f 100644 --- a/mk/golang.mk +++ b/mk/golang.mk @@ -70,7 +70,7 @@ test_go_fmt: TEST_GO += test_go_fmt test_go_lint: test/bin/golangci-lint - golangci-lint run ./... + golangci-lint run --timeout=3m ./... .PHONY: test_go_lint test_go: $(TEST_GO) diff --git a/plugin/loader/loader.go b/plugin/loader/loader.go index 6bf13a370c0..3c52a4105ad 100644 --- a/plugin/loader/loader.go +++ b/plugin/loader/loader.go @@ -241,6 +241,7 @@ func (loader *PluginLoader) Inject() error { for _, pl := range loader.plugins { if pl, ok := pl.(plugin.PluginIPLD); ok { + err := injectIPLDPlugin(pl) if err != nil { loader.state = loaderFailed @@ -338,6 +339,7 @@ func injectIPLDPlugin(pl plugin.PluginIPLD) error { } func injectTracerPlugin(pl plugin.PluginTracer) error { + log.Warn("Tracer plugins are deprecated, it's recommended to configure an OpenTelemetry collector instead.") tracer, err := pl.InitTracer() if err != nil { return err diff --git a/test/sharness/t0310-tracing.sh b/test/sharness/t0310-tracing.sh new file mode 100755 index 00000000000..bbc7cb1e1b6 --- /dev/null +++ b/test/sharness/t0310-tracing.sh @@ -0,0 +1,57 @@ +#!/usr/bin/env bash +# +# Copyright (c) 2022 Protocol Labs +# MIT/Apache-2.0 Licensed; see the LICENSE file in this repository. +# + +test_description="Test tracing" + +. lib/test-lib.sh + +test_init_ipfs + +export IPFS_TRACING=1 +export IPFS_TRACING_OTLP_GRPC=1 +export OTEL_EXPORTER_OTLP_ENDPOINT=http://localhost:4317 + +cat < collector-config.yaml +receivers: + otlp: + protocols: + grpc: + +processors: + batch: + +exporters: + file: + path: /traces/traces.json + +service: + pipelines: + traces: + receivers: [otlp] + processors: [batch] + exporters: [file] +EOF + +# touch traces.json and give it 777 perms, in case docker runs as a different user +rm -rf traces.json && touch traces.json && chmod 777 traces.json + +test_expect_success "run opentelemetry collector" ' + docker run --rm -d -v "$PWD/collector-config.yaml":/config.yaml -v "$PWD":/traces --net=host --name=ipfs-test-otel-collector otel/opentelemetry-collector-contrib:0.48.0 --config /config.yaml +' + +test_launch_ipfs_daemon + +test_expect_success "check that a swarm span eventually appears in exported traces" ' + until cat traces.json | grep CoreAPI.SwarmAPI >/dev/null; do sleep 0.1; done +' + +test_expect_success "kill docker container" ' + docker kill ipfs-test-otel-collector +' + +test_kill_ipfs_daemon + +test_done diff --git a/tracing/doc.go b/tracing/doc.go new file mode 100644 index 00000000000..d8ba6d9e9b9 --- /dev/null +++ b/tracing/doc.go @@ -0,0 +1,66 @@ +// Package tracing contains the tracing logic for go-ipfs, including configuring the tracer and +// helping keep consistent naming conventions across the stack. +// +// NOTE: Tracing is currently experimental. Span names may change unexpectedly, spans may be removed, +// and backwards-incompatible changes may be made to tracing configuration, options, and defaults. +// +// go-ipfs uses OpenTelemetry as its tracing API, and when possible, standard OpenTelemetry environment +// variables can be used to configure it. Multiple exporters can also be installed simultaneously, +// including one that writes traces to a JSON file on disk. +// +// In general, tracing is configured through environment variables. The IPFS-specific environment variables are: +// +// - IPFS_TRACING: enable tracing in go-ipfs +// - IPFS_TRACING_JAEGER: enable the Jaeger exporter +// - IPFS_TRACING_RATIO: the ratio of traces to export, defaults to 1 (export everything) +// - IPFS_TRACING_FILE: write traces to the given filename +// - IPFS_TRACING_OTLP_HTTP: enable the OTLP HTTP exporter +// - IPFS_TRACING_OTLP_GRPC: enable the OTLP gRPC exporter +// +// Different exporters have their own set of environment variables, depending on the exporter. These are typically +// standard environment variables. Some common ones: +// +// Jaeger: +// +// - OTEL_EXPORTER_JAEGER_AGENT_HOST +// - OTEL_EXPORTER_JAEGER_AGENT_PORT +// - OTEL_EXPORTER_JAEGER_ENDPOINT +// - OTEL_EXPORTER_JAEGER_USER +// - OTEL_EXPORTER_JAEGER_PASSWORD +// +// OTLP HTTP/gRPC: +// +// - OTEL_EXPORTER_OTLP_ENDPOINT +// - OTEL_EXPORTER_OTLP_CERTIFICATE +// - OTEL_EXPORTER_OTLP_HEADERS +// - OTEL_EXPORTER_OTLP_COMPRESSION +// - OTEL_EXPORTER_OTLP_TIMEOUT +// +// For example, if you run a local IPFS daemon, you can use the jaegertracing/all-in-one Docker image to run +// a full Jaeger stack and configure go-ipfs to publish traces to it: +// +// docker run -d --name jaeger \ +// -e COLLECTOR_ZIPKIN_HOST_PORT=:9411 \ +// -p 5775:5775/udp \ +// -p 6831:6831/udp \ +// -p 6832:6832/udp \ +// -p 5778:5778 \ +// -p 16686:16686 \ +// -p 14268:14268 \ +// -p 14250:14250 \ +// -p 9411:9411 \ +// jaegertracing/all-in-one +// IPFS_TRACING=1 IPFS_TRACING_JAEGER=1 ipfs daemon +// +// In this example the Jaeger UI is available at http://localhost:16686. +// +// +// Implementer Notes +// +// Span names follow a convention of ., some examples: +// +// - component=Gateway + span=Request -> Gateway.Request +// - component=CoreAPI.PinAPI + span=Verify.CheckPin -> CoreAPI.PinAPI.Verify.CheckPin +// +// We follow the OpenTelemetry convention of using whatever TracerProvider is registered globally. +package tracing diff --git a/tracing/tracing.go b/tracing/tracing.go new file mode 100644 index 00000000000..6cc8f6ad98c --- /dev/null +++ b/tracing/tracing.go @@ -0,0 +1,136 @@ +package tracing + +import ( + "context" + "fmt" + "os" + "strconv" + + version "github.com/ipfs/go-ipfs" + "go.opentelemetry.io/otel" + "go.opentelemetry.io/otel/exporters/jaeger" + "go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc" + "go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp" + "go.opentelemetry.io/otel/exporters/stdout/stdouttrace" + "go.opentelemetry.io/otel/sdk/resource" + "go.opentelemetry.io/otel/sdk/trace" + semconv "go.opentelemetry.io/otel/semconv/v1.7.0" + traceapi "go.opentelemetry.io/otel/trace" +) + +var exporterBuilders = map[string]func(context.Context, string) (trace.SpanExporter, error){ + "IPFS_TRACING_JAEGER": func(ctx context.Context, s string) (trace.SpanExporter, error) { + return jaeger.New(jaeger.WithCollectorEndpoint()) + }, + "IPFS_TRACING_FILE": func(ctx context.Context, s string) (trace.SpanExporter, error) { + return newFileExporter(s) + }, + "IPFS_TRACING_OTLP_HTTP": func(ctx context.Context, s string) (trace.SpanExporter, error) { + return otlptracehttp.New(ctx) + }, + "IPFS_TRACING_OTLP_GRPC": func(ctx context.Context, s string) (trace.SpanExporter, error) { + return otlptracegrpc.New(ctx) + }, +} + +// fileExporter wraps a file-writing exporter and closes the file when the exporter is shutdown. +type fileExporter struct { + file *os.File + writerExporter *stdouttrace.Exporter +} + +var _ trace.SpanExporter = &fileExporter{} + +func newFileExporter(file string) (*fileExporter, error) { + f, err := os.OpenFile(file, os.O_RDWR|os.O_CREATE|os.O_APPEND, 0666) + if err != nil { + return nil, fmt.Errorf("opening %s: %w", file, err) + } + stdoutExporter, err := stdouttrace.New(stdouttrace.WithWriter(f)) + if err != nil { + return nil, err + } + return &fileExporter{ + writerExporter: stdoutExporter, + file: f, + }, nil +} + +func (e *fileExporter) ExportSpans(ctx context.Context, spans []trace.ReadOnlySpan) error { + return e.writerExporter.ExportSpans(ctx, spans) +} + +func (e *fileExporter) Shutdown(ctx context.Context) error { + if err := e.writerExporter.Shutdown(ctx); err != nil { + return err + } + if err := e.file.Close(); err != nil { + return fmt.Errorf("closing trace file: %w", err) + } + return nil +} + +// noopShutdownTracerProvider wraps a TracerProvider with a no-op Shutdown method. +type noopShutdownTracerProvider struct { + tp traceapi.TracerProvider +} + +func (n *noopShutdownTracerProvider) Shutdown(ctx context.Context) error { + return nil +} +func (n *noopShutdownTracerProvider) Tracer(instrumentationName string, opts ...traceapi.TracerOption) traceapi.Tracer { + return n.tp.Tracer(instrumentationName, opts...) +} + +type ShutdownTracerProvider interface { + traceapi.TracerProvider + Shutdown(ctx context.Context) error +} + +// NewTracerProvider creates and configures a TracerProvider. +func NewTracerProvider(ctx context.Context) (ShutdownTracerProvider, error) { + if os.Getenv("IPFS_TRACING") == "" { + return &noopShutdownTracerProvider{tp: traceapi.NewNoopTracerProvider()}, nil + } + + options := []trace.TracerProviderOption{} + + traceRatio := 1.0 + if envRatio := os.Getenv("IPFS_TRACING_RATIO"); envRatio != "" { + r, err := strconv.ParseFloat(envRatio, 64) + if err == nil { + traceRatio = r + } + } + options = append(options, trace.WithSampler(trace.ParentBased(trace.TraceIDRatioBased(traceRatio)))) + + r, err := resource.Merge( + resource.Default(), + resource.NewWithAttributes( + semconv.SchemaURL, + semconv.ServiceNameKey.String("go-ipfs"), + semconv.ServiceVersionKey.String(version.CurrentVersionNumber), + ), + ) + if err != nil { + return nil, err + } + options = append(options, trace.WithResource(r)) + + for envVar, builder := range exporterBuilders { + if val := os.Getenv(envVar); val != "" { + exporter, err := builder(ctx, val) + if err != nil { + return nil, err + } + options = append(options, trace.WithBatcher(exporter)) + } + } + + return trace.NewTracerProvider(options...), nil +} + +// Span starts a new span using the standard IPFS tracing conventions. +func Span(ctx context.Context, componentName string, spanName string, opts ...traceapi.SpanStartOption) (context.Context, traceapi.Span) { + return otel.Tracer("go-ipfs").Start(ctx, fmt.Sprintf("%s.%s", componentName, spanName), opts...) +} From 5ae47522cc834fbf7d9f1d1ed2645ad159b5bc1d Mon Sep 17 00:00:00 2001 From: Marcin Rataj Date: Wed, 6 Apr 2022 02:06:17 +0200 Subject: [PATCH 338/414] chore: deprecate tar commands (#8849) Closes #7951 --- core/commands/tar.go | 3 +++ 1 file changed, 3 insertions(+) diff --git a/core/commands/tar.go b/core/commands/tar.go index efc1503cdb8..4dcb22be8b2 100644 --- a/core/commands/tar.go +++ b/core/commands/tar.go @@ -13,6 +13,7 @@ import ( ) var TarCmd = &cmds.Command{ + Status: cmds.Deprecated, // https://github.com/ipfs/go-ipfs/issues/7951 Helptext: cmds.HelpText{ Tagline: "Utility functions for tar files in ipfs.", }, @@ -24,6 +25,7 @@ var TarCmd = &cmds.Command{ } var tarAddCmd = &cmds.Command{ + Status: cmds.Deprecated, // https://github.com/ipfs/go-ipfs/issues/7951 Helptext: cmds.HelpText{ Tagline: "Import a tar file into IPFS.", ShortDescription: ` @@ -74,6 +76,7 @@ represent it. } var tarCatCmd = &cmds.Command{ + Status: cmds.Deprecated, // https://github.com/ipfs/go-ipfs/issues/7951 Helptext: cmds.HelpText{ Tagline: "Export a tar file from IPFS.", ShortDescription: ` From e309682545a7be80541a6cdd160468d10e72c69b Mon Sep 17 00:00:00 2001 From: Marcin Rataj Date: Wed, 6 Apr 2022 02:10:13 +0200 Subject: [PATCH 339/414] fix: unknown fetcher type error (#8830) match RetryFetcher as HttpFetcher --- cmd/ipfs/add_migrations.go | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/cmd/ipfs/add_migrations.go b/cmd/ipfs/add_migrations.go index b5b6c31a137..58b62e4f777 100644 --- a/cmd/ipfs/add_migrations.go +++ b/cmd/ipfs/add_migrations.go @@ -9,7 +9,7 @@ import ( "os" "path/filepath" - "github.com/ipfs/go-ipfs-files" + files "github.com/ipfs/go-ipfs-files" "github.com/ipfs/go-ipfs/core" "github.com/ipfs/go-ipfs/core/coreapi" "github.com/ipfs/go-ipfs/repo/fsrepo/migrations" @@ -37,7 +37,7 @@ func addMigrations(ctx context.Context, node *core.IpfsNode, fetcher migrations. if err != nil { return err } - case *migrations.HttpFetcher: + case *migrations.HttpFetcher, *migrations.RetryFetcher: // https://github.com/ipfs/go-ipfs/issues/8780 // Add the downloaded migration files directly if migrations.DownloadDirectory != "" { var paths []string From 7b2c7c7f166f33f18a995e103acbe3774ddf1408 Mon Sep 17 00:00:00 2001 From: Justin Johnson Date: Wed, 6 Apr 2022 10:24:23 -0500 Subject: [PATCH 340/414] docs(logging): environment variables (#8833) - Document IPFS_LOGGING deprecation as alias to GOLOG_LOG_LEVEL and expand doc to include per-subsystem log levels. - Document IPFS_LOGGING_FMT deprecation as alias to GOLOG_LOG_FMT. --- docs/environment-variables.md | 57 ++++++++++++++++++++++++++--------- 1 file changed, 42 insertions(+), 15 deletions(-) diff --git a/docs/environment-variables.md b/docs/environment-variables.md index aad022e3b9d..fd57b819264 100644 --- a/docs/environment-variables.md +++ b/docs/environment-variables.md @@ -17,28 +17,55 @@ Default: ~/.ipfs ## `IPFS_LOGGING` -Sets the log level for go-ipfs. It can be set to one of: +Specifies the log level for go-ipfs. -* `CRITICAL` -* `ERROR` -* `WARNING` -* `NOTICE` -* `INFO` -* `DEBUG` +`IPFS_LOGGING` is a deprecated alias for the `GOLOG_LOG_LEVEL` environment variable. See below. -Logging can also be configured (on a subsystem by subsystem basis) at runtime -with the `ipfs log` command. +## `IPFS_LOGGING_FMT` -Default: `ERROR` +Specifies the log message format. -## `IPFS_LOGGING_FMT` +`IPFS_LOGGING_FMT` is a deprecated alias for the `GOLOG_LOG_FMT` environment variable. See below. + +## `GOLOG_LOG_LEVEL` + +Specifies the log-level, both globally and on a per-subsystem basis. Level can be one of: + +* `debug` +* `info` +* `warn` +* `error` +* `dpanic` +* `panic` +* `fatal` + +Per-subsystem levels can be specified with `subsystem=level`. One global level and one or more per-subsystem levels +can be specified by separating them with commas. + +Default: `error` + +Example: + +```console +GOLOG_LOG_LEVEL="error,core/server=debug" ipfs daemon +``` -Sets the log message format. Can be one of: +Logging can also be configured at runtime, both globally and on a per-subsystem basis, with the `ipfs log` command. -* `color` -* `nocolor` +## `GOLOG_LOG_FMT` -Default: `color` +Specifies the log message format. It supports the following values: + +- `color` -- human readable, colorized (ANSI) output +- `nocolor` -- human readable, plain-text output. +- `json` -- structured JSON. + +For example, to log structured JSON (for easier parsing): + +```bash +export GOLOG_LOG_FMT="json" +``` +The logging format defaults to `color` when the output is a terminal, and `nocolor` otherwise. ## `GOLOG_FILE` From dd06dd00184138bb70c6773a3ba8f257dcbd5a0d Mon Sep 17 00:00:00 2001 From: Marcin Rataj Date: Wed, 6 Apr 2022 18:14:15 +0200 Subject: [PATCH 341/414] chore: add CODEOWNERS (#8852) --- .github/CODEOWNERS | 7 +++++++ 1 file changed, 7 insertions(+) create mode 100644 .github/CODEOWNERS diff --git a/.github/CODEOWNERS b/.github/CODEOWNERS new file mode 100644 index 00000000000..5151ad178ae --- /dev/null +++ b/.github/CODEOWNERS @@ -0,0 +1,7 @@ +# Code owners are automatically requested for review when someone opens a pull +# request that modifies code that they own. Code owners are not automatically +# requested to review draft pull requests. + +# HTTP Gateway +core/corehttp/ @lidel +test/sharness/*gateway*.sh @lidel From 7871a0beb7b9a4462f6bfb910feb37e3d95e18ee Mon Sep 17 00:00:00 2001 From: Marcin Rataj Date: Thu, 7 Apr 2022 04:33:13 +0200 Subject: [PATCH 342/414] feat(cmds): add support for CAR v2 imports (#8854) * feat: add support for carv2 import * update to multicodec 0.4.0 * add sharness test for carv2 Co-authored-by: Keenan Nemetz --- core/commands/dag/import.go | 11 ++---- go.mod | 9 ++--- go.sum | 34 ++++++++++++++++-- .../README.md | 4 +++ .../test_dataset_car.tar.xz | Bin 0 -> 386472 bytes .../test_dataset_car_v0.tar.xz | Bin 379056 -> 0 bytes test/sharness/t0054-dag-car-import-export.sh | 19 +++++++++- 7 files changed, 62 insertions(+), 15 deletions(-) create mode 100644 test/sharness/t0054-dag-car-import-export-data/test_dataset_car.tar.xz delete mode 100644 test/sharness/t0054-dag-car-import-export-data/test_dataset_car_v0.tar.xz diff --git a/core/commands/dag/import.go b/core/commands/dag/import.go index 476b986c825..77d688ca9ea 100644 --- a/core/commands/dag/import.go +++ b/core/commands/dag/import.go @@ -14,7 +14,7 @@ import ( "github.com/ipfs/interface-go-ipfs-core/options" cmds "github.com/ipfs/go-ipfs-cmds" - gocar "github.com/ipld/go-car" + gocarv2 "github.com/ipld/go-car/v2" ) func dagImport(req *cmds.Request, res cmds.ResponseEmitter, env cmds.Environment) error { @@ -160,17 +160,12 @@ func importWorker(req *cmds.Request, re cmds.ResponseEmitter, api iface.CoreAPI, err := func() error { defer file.Close() - car, err := gocar.NewCarReader(file) + car, err := gocarv2.NewBlockReader(file) if err != nil { return err } - // Be explicit here, until the spec is finished - if car.Header.Version != 1 { - return errors.New("only car files version 1 supported at present") - } - - for _, c := range car.Header.Roots { + for _, c := range car.Roots { roots[c] = struct{}{} } diff --git a/go.mod b/go.mod index cbae3de58ae..d89921df144 100644 --- a/go.mod +++ b/go.mod @@ -60,6 +60,7 @@ require ( github.com/ipfs/interface-go-ipfs-core v0.6.2 github.com/ipfs/tar-utils v0.0.2 github.com/ipld/go-car v0.3.2 + github.com/ipld/go-car/v2 v2.1.1 github.com/ipld/go-codec-dagpb v1.3.0 github.com/ipld/go-ipld-prime v0.14.2 github.com/jbenet/go-random v0.0.0-20190219211222-123a90aedc0c @@ -94,7 +95,7 @@ require ( github.com/multiformats/go-multiaddr v0.4.1 github.com/multiformats/go-multiaddr-dns v0.3.1 github.com/multiformats/go-multibase v0.0.3 - github.com/multiformats/go-multicodec v0.3.0 + github.com/multiformats/go-multicodec v0.4.0 github.com/multiformats/go-multihash v0.1.0 github.com/opentracing/opentracing-go v1.2.0 github.com/pkg/errors v0.9.1 @@ -104,9 +105,6 @@ require ( github.com/whyrusleeping/go-sysinfo v0.0.0-20190219211824-4a357d4b90b1 github.com/whyrusleeping/multiaddr-filter v0.0.0-20160516205228-e903e4adabd7 go.opencensus.io v0.23.0 - go.uber.org/dig v1.14.0 - go.uber.org/fx v1.16.0 - go.uber.org/zap v1.21.0 go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.27.0 go.opentelemetry.io/otel v1.2.0 go.opentelemetry.io/otel/exporters/jaeger v1.2.0 @@ -115,6 +113,9 @@ require ( go.opentelemetry.io/otel/exporters/stdout/stdouttrace v1.2.0 go.opentelemetry.io/otel/sdk v1.2.0 go.opentelemetry.io/otel/trace v1.2.0 + go.uber.org/dig v1.14.0 + go.uber.org/fx v1.16.0 + go.uber.org/zap v1.21.0 golang.org/x/crypto v0.0.0-20210921155107-089bfa567519 golang.org/x/sync v0.0.0-20210220032951-036812b2e83c golang.org/x/sys v0.0.0-20211025112917-711f33c9992c diff --git a/go.sum b/go.sum index bb719927a42..5163daaa5b3 100644 --- a/go.sum +++ b/go.sum @@ -38,6 +38,7 @@ contrib.go.opencensus.io/exporter/prometheus v0.4.0 h1:0QfIkj9z/iVZgK31D9H9ohjjI contrib.go.opencensus.io/exporter/prometheus v0.4.0/go.mod h1:o7cosnyfuPVK0tB8q0QmaQNhGnptITnPQB+z1+qeFB0= dmitri.shuralyov.com/app/changes v0.0.0-20180602232624-0a106ad413e3/go.mod h1:Yl+fi1br7+Rr3LqpNJf1/uxUdtRUV+Tnj0o93V2B9MU= dmitri.shuralyov.com/gpu/mtl v0.0.0-20190408044501-666a987793e9/go.mod h1:H6x//7gZCb22OMCxBHrMx7a5I7Hp++hsVxbQ4BYO7hU= +dmitri.shuralyov.com/gpu/mtl v0.0.0-20201218220906-28db891af037/go.mod h1:H6x//7gZCb22OMCxBHrMx7a5I7Hp++hsVxbQ4BYO7hU= dmitri.shuralyov.com/html/belt v0.0.0-20180602232347-f7d459c86be0/go.mod h1:JLBrvjyP0v+ecvNYvCpyZgu5/xkfAUhi6wJj28eUfSU= dmitri.shuralyov.com/service/change v0.0.0-20181023043359-a85b471d5412/go.mod h1:a1inKt/atXimZ4Mv927x+r7UpyzRUf4emIoiiSC2TN4= dmitri.shuralyov.com/state v0.0.0-20180228185332-28bcc343414c/go.mod h1:0PRwlb0D6DFvNNtx+9ybjezNCa8XF0xaYcETyp6rHWU= @@ -152,8 +153,9 @@ github.com/coreos/go-semver v0.2.1-0.20180108230905-e214231b295a/go.mod h1:nnelY github.com/coreos/go-semver v0.3.0 h1:wkHLiw0WNATZnSG7epLsujiMCgPAc9xhjJ4tgnAxmfM= github.com/coreos/go-semver v0.3.0/go.mod h1:nnelYz7RCh+5ahJtPPxZlU+153eP4D4r3EedlOD2RNk= github.com/coreos/go-systemd v0.0.0-20180511133405-39ca1b05acc7/go.mod h1:F5haX7vjVVG0kc13fIWeqUViNPyEJxv/OmvnBo0Yme4= -github.com/coreos/go-systemd v0.0.0-20181012123002-c6f51f82210d h1:t5Wuyh53qYyg9eqn4BbnlIT+vmhyww0TatL+zT3uWgI= github.com/coreos/go-systemd v0.0.0-20181012123002-c6f51f82210d/go.mod h1:F5haX7vjVVG0kc13fIWeqUViNPyEJxv/OmvnBo0Yme4= +github.com/coreos/go-systemd v0.0.0-20190321100706-95778dfbb74e h1:Wf6HqHfScWJN9/ZjdUKyjop4mf3Qdd+1TvvltAvM3m8= +github.com/coreos/go-systemd v0.0.0-20190321100706-95778dfbb74e/go.mod h1:F5haX7vjVVG0kc13fIWeqUViNPyEJxv/OmvnBo0Yme4= github.com/coreos/go-systemd/v22 v22.0.0/go.mod h1:xO0FLkIi5MaZafQlIrOotqXZ90ih+1atmu1JpKERPPk= github.com/coreos/go-systemd/v22 v22.3.2 h1:D9/bQk5vlXQFZ6Kwuu6zaiXJ9oTPe68++AzAJc1DzSI= github.com/coreos/go-systemd/v22 v22.3.2/go.mod h1:Y58oyj3AT4RCenI/lSvhwexgC+NSVTIJ3seZv2GcEnc= @@ -245,6 +247,7 @@ github.com/go-logfmt/logfmt v0.3.0/go.mod h1:Qt1PoO58o5twSAckw1HlFXLmHsOX5/0LbT9 github.com/go-logfmt/logfmt v0.4.0/go.mod h1:3RMwSq7FuexP4Kalkev3ejPJsZTpXXBr9+V4qmtdjCk= github.com/go-logfmt/logfmt v0.5.0 h1:TrB8swr/68K7m9CcGut2g3UOihhbcbiMAYiuTXdEih4= github.com/go-logfmt/logfmt v0.5.0/go.mod h1:wCYkCAKZfumFQihp8CzCvQ3paCTfi41vtzG1KdI/P7A= +github.com/go-logr/logr v0.4.0/go.mod h1:z6/tIYblkpsD+a4lm/fGIIU9mZ+XfAiaFtq7xTgseGU= github.com/go-sql-driver/mysql v1.4.0/go.mod h1:zAC/RDZ24gD3HViQzih4MyKcchzm+sOG5ZlKdlhCg5w= github.com/go-stack/stack v1.8.0 h1:5SgMzNM5HxrEjV0ww2lTmX6E2Izsfxas4+YHWRs3Lsk= github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY= @@ -476,6 +479,7 @@ github.com/ipfs/go-ipfs-blockstore v0.0.1/go.mod h1:d3WClOmRQKFnJ0Jz/jj/zmksX0ma github.com/ipfs/go-ipfs-blockstore v0.1.0/go.mod h1:5aD0AvHPi7mZc6Ci1WCAhiBQu2IsfTduLl+422H6Rqw= github.com/ipfs/go-ipfs-blockstore v0.1.4/go.mod h1:Jxm3XMVjh6R17WvxFEiyKBLUGr86HgIYJW/D/MwqeYQ= github.com/ipfs/go-ipfs-blockstore v0.2.1/go.mod h1:jGesd8EtCM3/zPgx+qr0/feTXGUeRai6adgwC+Q+JvE= +github.com/ipfs/go-ipfs-blockstore v1.1.2/go.mod h1:w51tNR9y5+QXB0wkNcHt4O2aSZjTdqaEWaQdSxEyUOY= github.com/ipfs/go-ipfs-blockstore v1.2.0 h1:n3WTeJ4LdICWs/0VSfjHrlqpPpl6MZ+ySd3j8qz0ykw= github.com/ipfs/go-ipfs-blockstore v1.2.0/go.mod h1:eh8eTFLiINYNSNawfZOC7HOxNTxpB1PFuA5E1m/7exE= github.com/ipfs/go-ipfs-blocksutil v0.0.1 h1:Eh/H4pc1hsvhzsQoMEP3Bke/aW5P5rVM1IWFJMcGIPQ= @@ -594,6 +598,8 @@ github.com/ipfs/tar-utils v0.0.2 h1:UNgHB4x/PPzbMkmJi+7EqC9LNMPDztOVSnx1HAqSNg4= github.com/ipfs/tar-utils v0.0.2/go.mod h1:4qlnRWgTVljIMhSG2SqRYn66NT+3wrv/kZt9V+eqxDM= github.com/ipld/go-car v0.3.2 h1:V9wt/80FNfbMRWSD98W5br6fyjUAyVgI2lDOTZX16Lg= github.com/ipld/go-car v0.3.2/go.mod h1:WEjynkVt04dr0GwJhry0KlaTeSDEiEYyMPOxDBQ17KE= +github.com/ipld/go-car/v2 v2.1.1 h1:saaKz4nC0AdfCGHLYKeXLGn8ivoPC54fyS55uyOLKwA= +github.com/ipld/go-car/v2 v2.1.1/go.mod h1:+2Yvf0Z3wzkv7NeI69i8tuZ+ft7jyjPYIWZzeVNeFcI= github.com/ipld/go-codec-dagpb v1.2.0/go.mod h1:6nBN7X7h8EOsEejZGqC7tej5drsdBAXbMHyBT+Fne5s= github.com/ipld/go-codec-dagpb v1.3.0 h1:czTcaoAuNNyIYWs6Qe01DJ+sEX7B+1Z0LcXjSatMGe8= github.com/ipld/go-codec-dagpb v1.3.0/go.mod h1:ga4JTU3abYApDC3pZ00BC2RSvC3qfBb9MSJkMLSwnhA= @@ -601,9 +607,12 @@ github.com/ipld/go-ipld-prime v0.9.0/go.mod h1:KvBLMr4PX1gWptgkzRjVZCrLmSGcZCb/j github.com/ipld/go-ipld-prime v0.9.1-0.20210324083106-dc342a9917db/go.mod h1:KvBLMr4PX1gWptgkzRjVZCrLmSGcZCb/jioOQwCqZN8= github.com/ipld/go-ipld-prime v0.11.0/go.mod h1:+WIAkokurHmZ/KwzDOMUuoeJgaRQktHtEaLglS3ZeV8= github.com/ipld/go-ipld-prime v0.12.3/go.mod h1:PaeLYq8k6dJLmDUSLrzkEpoGV4PEfe/1OtFN/eALOc8= +github.com/ipld/go-ipld-prime v0.14.0/go.mod h1:9ASQLwUFLptCov6lIYc70GRB4V7UTyLD0IJtrDJe6ZM= github.com/ipld/go-ipld-prime v0.14.1/go.mod h1:QcE4Y9n/ZZr8Ijg5bGPT0GqYWgZ1704nH0RDcQtgTP0= github.com/ipld/go-ipld-prime v0.14.2 h1:P5fO2usnisXwrN/1sR5exCgEvINg/w/27EuYPKB/zx8= github.com/ipld/go-ipld-prime v0.14.2/go.mod h1:QcE4Y9n/ZZr8Ijg5bGPT0GqYWgZ1704nH0RDcQtgTP0= +github.com/ipld/go-ipld-prime/storage/bsadapter v0.0.0-20211210234204-ce2a1c70cd73 h1:TsyATB2ZRRQGTwafJdgEUQkmjOExRV0DNokcihZxbnQ= +github.com/ipld/go-ipld-prime/storage/bsadapter v0.0.0-20211210234204-ce2a1c70cd73/go.mod h1:2PJ0JgxyB08t0b2WKrcuqI3di0V+5n6RS/LTUJhkoxY= github.com/jackpal/gateway v1.0.5/go.mod h1:lTpwd4ACLXmpyiCTRtfiNyVnUmqT9RivzCDQetPfnjA= github.com/jackpal/go-nat-pmp v1.0.1/go.mod h1:QPH045xvCAeXUZOxsnwmrtiCoxIr9eob+4orBN1SBKc= github.com/jackpal/go-nat-pmp v1.0.2 h1:KzKSgb7qkJvOUTqYl9/Hg/me3pWgBmERKrTGD7BdWus= @@ -1130,8 +1139,11 @@ github.com/multiformats/go-multibase v0.0.1/go.mod h1:bja2MqRZ3ggyXtZSEDKpl0uO/g github.com/multiformats/go-multibase v0.0.3 h1:l/B6bJDQjvQ5G52jw4QGSYeOTZoAwIO77RblWplfIqk= github.com/multiformats/go-multibase v0.0.3/go.mod h1:5+1R4eQrT3PkYZ24C3W2Ue2tPwIdYQD509ZjSb5y9Oc= github.com/multiformats/go-multicodec v0.2.0/go.mod h1:/y4YVwkfMyry5kFbMTbLJKErhycTIftytRV+llXdyS4= -github.com/multiformats/go-multicodec v0.3.0 h1:tstDwfIjiHbnIjeM5Lp+pMrSeN+LCMsEwOrkPmWm03A= github.com/multiformats/go-multicodec v0.3.0/go.mod h1:qGGaQmioCDh+TeFOnxrbU0DaIPw8yFgAZgFG0V7p1qQ= +github.com/multiformats/go-multicodec v0.3.1-0.20210902112759-1539a079fd61 h1:ZrUuMKNgJ52qHPoQ+bx0h0uBfcWmN7Px+4uKSZeesiI= +github.com/multiformats/go-multicodec v0.3.1-0.20210902112759-1539a079fd61/go.mod h1:1Hj/eHRaVWSXiSNNfcEPcwZleTmdNP81xlxDLnWU9GQ= +github.com/multiformats/go-multicodec v0.4.0 h1:fbqb6ky7erjdD+/zaEBJgZWu1i8D6i/wmPywGK7sdow= +github.com/multiformats/go-multicodec v0.4.0/go.mod h1:1Hj/eHRaVWSXiSNNfcEPcwZleTmdNP81xlxDLnWU9GQ= github.com/multiformats/go-multihash v0.0.1/go.mod h1:w/5tugSrLEbWqlcgJabL3oHFKTwfvkofsjW2Qa1ct4U= github.com/multiformats/go-multihash v0.0.5/go.mod h1:lt/HCbqlQwlPBz7lv0sQCdtfcMtlJvakRUn/0Ual8po= github.com/multiformats/go-multihash v0.0.8/go.mod h1:YSLudS+Pi8NHE7o6tb3D8vrpKa63epEDmG8nTduyAew= @@ -1207,6 +1219,8 @@ github.com/pascaldekloe/goe v0.0.0-20180627143212-57f6aae5913c/go.mod h1:lzWF7FI github.com/pborman/uuid v1.2.0/go.mod h1:X/NO0urCmaxf9VXbdlT7C2Yzkj2IKimNn4k+gtPdI/k= github.com/pelletier/go-toml v1.2.0/go.mod h1:5z9KED0ma1S8pY6P1sdut58dfprrGBbd/94hg7ilaic= github.com/performancecopilot/speed v3.0.0+incompatible/go.mod h1:/CLtqpZ5gBg1M9iaPbIdPPGyKcA8hKdoy6hAWba7Yac= +github.com/petar/GoLLRB v0.0.0-20210522233825-ae3b015fd3e9 h1:1/WtZae0yGtPq+TI6+Tv1WTxkukpXeMlviSxvL7SRgk= +github.com/petar/GoLLRB v0.0.0-20210522233825-ae3b015fd3e9/go.mod h1:x3N5drFsm2uilKKuuYo6LdyD8vZAW55sH/9w+pbo1sw= github.com/pierrec/lz4 v1.0.2-0.20190131084431-473cd7ce01a1/go.mod h1:3/3N9NVKO0jef7pBehbT1qWhCMrIgbYNnFAZCqQ5LRc= github.com/pierrec/lz4 v2.0.5+incompatible/go.mod h1:pdkljMzZIN41W+lC3N2tnIh5sFi+IEE17M5jbnwPHcY= github.com/pkg/errors v0.8.0/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= @@ -1273,6 +1287,8 @@ github.com/rogpeppe/go-internal v1.6.1 h1:/FiVV8dS/e+YqF2JvO3yXRFbBLTIuSDkuC7aBO github.com/rogpeppe/go-internal v1.6.1/go.mod h1:xXDCJY+GAPziupqXw64V24skbSoqbTEfhy4qGm1nDQc= github.com/rs/cors v1.7.0 h1:+88SsELBHx5r+hZ8TCkggzSstaWNbDvThkVK8H6f9ik= github.com/rs/cors v1.7.0/go.mod h1:gFx+x8UowdsKA9AchylcLynDq+nNFfI8FkUZdN/jGCU= +github.com/rs/xid v1.2.1/go.mod h1:+uKXf+4Djp6Md1KODXJxgGQPKngRmWyn10oCKFzNHOQ= +github.com/rs/zerolog v1.21.0/go.mod h1:ZPhntP/xmq1nnND05hhpAh2QMhSsA4UN3MGZ6O2J3hM= github.com/russross/blackfriday v1.5.2/go.mod h1:JO/DiYxRf+HjHt06OyowR9PTA263kcR/rfWxYHBV53g= github.com/russross/blackfriday/v2 v2.0.1/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM= github.com/rwcarlsen/goexif v0.0.0-20190401172101-9e8deecbddbd/go.mod h1:hPqNNc0+uJM6H+SuU8sEs5K5IQeKccPqeSjfgcKGgPk= @@ -1306,6 +1322,7 @@ github.com/shurcooL/webdavfs v0.0.0-20170829043945-18c3829fa133/go.mod h1:hKmq5k github.com/sirupsen/logrus v1.2.0/go.mod h1:LxeOpSwHxABJmUn/MG1IvRgCAasNZTLOkJPxbbu5VWo= github.com/sirupsen/logrus v1.4.2/go.mod h1:tLMulIdttU9McNUspp0xgXVQah82FyeX6MwdIuYE2rE= github.com/sirupsen/logrus v1.6.0/go.mod h1:7uNnSEd1DgxDLC74fIahvMZmmYsHGZGEOFrfsX/uA88= +github.com/sirupsen/logrus v1.8.1/go.mod h1:yWOB1SBYBC5VeMP7gHvWumXLIWorT60ONWic61uBYv0= github.com/smartystreets/assertions v0.0.0-20180927180507-b2de0cb4f26d/go.mod h1:OnSkiWE9lh6wB0YB77sQom3nweQdgAjqCqsofrRNTgc= github.com/smartystreets/assertions v1.0.0 h1:UVQPSSmc3qtTi+zPPkCXvZX9VvW/xT/NsRvKfwY81a8= github.com/smartystreets/assertions v1.0.0/go.mod h1:kHHU4qYBaI3q23Pp3VPrmWhuIUrLW/7eUrw0BU5VaoM= @@ -1370,6 +1387,8 @@ github.com/warpfork/go-wish v0.0.0-20200122115046-b9ea61034e4a h1:G++j5e0OC488te github.com/warpfork/go-wish v0.0.0-20200122115046-b9ea61034e4a/go.mod h1:x6AKhvSSexNrVSrViXSHUEbICjmGXhtgABaHIySUSGw= github.com/whyrusleeping/base32 v0.0.0-20170828182744-c30ac30633cc h1:BCPnHtcboadS0DvysUuJXZ4lWVv5Bh5i7+tbIyi+ck4= github.com/whyrusleeping/base32 v0.0.0-20170828182744-c30ac30633cc/go.mod h1:r45hJU7yEoA81k6MWNhpMj/kms0n14dkzkxYHoB96UM= +github.com/whyrusleeping/cbor v0.0.0-20171005072247-63513f603b11 h1:5HZfQkwe0mIfyDmc1Em5GqlNRzcdtlv4HTNmdpt7XH0= +github.com/whyrusleeping/cbor v0.0.0-20171005072247-63513f603b11/go.mod h1:Wlo/SzPmxVp6vXpGt/zaXhHH0fn4IxgqZc82aKg6bpQ= github.com/whyrusleeping/cbor-gen v0.0.0-20200123233031-1cdf64d27158/go.mod h1:Xj/M2wWU+QdTdRbu/L/1dIZY8/Wb2K9pAhtroQuxJJI= github.com/whyrusleeping/cbor-gen v0.0.0-20200710004633-5379fc63235d/go.mod h1:fgkXqYy7bV2cFeIEOkVTZS/WjXARfBqSH6Q2qHL33hQ= github.com/whyrusleeping/cbor-gen v0.0.0-20210219115102-f37d292932f2 h1:bsUlNhdmbtlfdLVXAVfuvKQ01RnWAM09TVrJkI7NZs4= @@ -1433,6 +1452,7 @@ go.opentelemetry.io/otel/metric v0.20.0/go.mod h1:598I5tYlH1vzBjn+BTuhzTCSb/9deb go.opentelemetry.io/otel/metric v0.25.0 h1:7cXOnCADUsR3+EOqxPaSKwhEuNu0gz/56dRN1hpIdKw= go.opentelemetry.io/otel/metric v0.25.0/go.mod h1:E884FSpQfnJOMMUaq+05IWlJ4rjZpk2s/F1Ju+TEEm8= go.opentelemetry.io/otel/oteltest v0.20.0/go.mod h1:L7bgKf9ZB7qCwT9Up7i9/pn0PWIa9FqQ2IQ8LoxiGnw= +go.opentelemetry.io/otel/sdk v0.20.0/go.mod h1:g/IcepuwNsoiX5Byy2nNV0ySUF1em498m7hBWC279Yc= go.opentelemetry.io/otel/sdk v1.2.0 h1:wKN260u4DesJYhyjxDa7LRFkuhH7ncEVKU37LWcyNIo= go.opentelemetry.io/otel/sdk v1.2.0/go.mod h1:jNN8QtpvbsKhgaC6V5lHiejMoKD+V8uadoSafgHPx1U= go.opentelemetry.io/otel/trace v0.20.0/go.mod h1:6GjCW8zgDjwGHGa6GkyeB8+/5vjT16gUEi0Nf1iBdgw= @@ -1507,12 +1527,14 @@ golang.org/x/crypto v0.0.0-20210220033148-5ea612d1eb83/go.mod h1:jdWPYTVW3xRLrWP golang.org/x/crypto v0.0.0-20210322153248-0c34fe9e7dc2/go.mod h1:T9bdIzuCu7OtxOm1hfPfRQxPLYneinmdGuTeoZ9dtd4= golang.org/x/crypto v0.0.0-20210506145944-38f3c27a63bf/go.mod h1:P+XmwS30IXTQdn5tA2iutPOUgjI07+tq3H3K9MVA1s8= golang.org/x/crypto v0.0.0-20210513164829-c07d793c2f9a/go.mod h1:P+XmwS30IXTQdn5tA2iutPOUgjI07+tq3H3K9MVA1s8= +golang.org/x/crypto v0.0.0-20210711020723-a769d52b0f97/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= golang.org/x/crypto v0.0.0-20210813211128-0a44fdfbc16e/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= golang.org/x/crypto v0.0.0-20210921155107-089bfa567519 h1:7I4JAnoQBe7ZtJcBaYHi5UtiO8tQHbUSXxL+pnGRANg= golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= golang.org/x/exp v0.0.0-20190306152737-a1d7652674e8/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= golang.org/x/exp v0.0.0-20190510132918-efd6b22b2522/go.mod h1:ZjyILWgesfNpC6sMxTJOJm9Kp84zZh5NQWvqDGG3Qr8= +golang.org/x/exp v0.0.0-20190731235908-ec7cb31e5a56/go.mod h1:JhuoJpWY28nO4Vef9tZUw9qufEGTyX1+7lmHxV5q5G4= golang.org/x/exp v0.0.0-20190829153037-c13cbed26979/go.mod h1:86+5VVa7VpoJ4kLfm080zCjGlMRFzhUhsZKEZO7MGek= golang.org/x/exp v0.0.0-20191030013958-a1ab85dbe136/go.mod h1:JXzH8nQsPlswgeRAPE3MuO9GYsAcnJvJ4vnMwN/5qkY= golang.org/x/exp v0.0.0-20191129062945-2f5052295587/go.mod h1:2RIsYlXP63K8oxa1u096TMicItID8zy7Y6sNkU49FU4= @@ -1520,6 +1542,8 @@ golang.org/x/exp v0.0.0-20191227195350-da58074b4299/go.mod h1:2RIsYlXP63K8oxa1u0 golang.org/x/exp v0.0.0-20200119233911-0405dc783f0a/go.mod h1:2RIsYlXP63K8oxa1u096TMicItID8zy7Y6sNkU49FU4= golang.org/x/exp v0.0.0-20200207192155-f17229e696bd/go.mod h1:J/WKrq2StrnmMY6+EHIKF9dgMWnmCNThgcyBT1FY9mM= golang.org/x/exp v0.0.0-20200224162631-6cc2880d07d6/go.mod h1:3jZMyOhIsHpP37uCMkUooju7aAi5cS1Q23tOzKc+0MU= +golang.org/x/exp v0.0.0-20210615023648-acb5c1269671 h1:ddvpKwqE7dm58PoWjRCmaCiA3DANEW0zWGfNYQD212Y= +golang.org/x/exp v0.0.0-20210615023648-acb5c1269671/go.mod h1:DVyR6MI7P4kEQgvZJSj1fQGrWIi2RzIrfYWycwheUAc= golang.org/x/image v0.0.0-20190227222117-0694c2d4d067/go.mod h1:kZ7UVZpmo3dzQBMxlp+ypCbDeSB+sBbTgSJuh5dn5js= golang.org/x/image v0.0.0-20190802002840-cff245a6509b/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0= golang.org/x/lint v0.0.0-20180702182130-06c8688daad7/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE= @@ -1536,10 +1560,12 @@ golang.org/x/lint v0.0.0-20200302205851-738671d3881b h1:Wh+f8QHJXR411sJR8/vRBTZ7 golang.org/x/lint v0.0.0-20200302205851-738671d3881b/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY= golang.org/x/mobile v0.0.0-20190312151609-d3739f865fa6/go.mod h1:z+o9i4GpDbdi3rU15maQ/Ox0txvL9dWGYEHz965HBQE= golang.org/x/mobile v0.0.0-20190719004257-d2bd2a29d028/go.mod h1:E/iHnbuqvinMTCcRqshq8CkpyQDoeVncDDYHnLhea+o= +golang.org/x/mobile v0.0.0-20201217150744-e6ae53a27f4f/go.mod h1:skQtrUTUwhdJvXM/2KKJzY8pDgNr9I/FOMqDVRPBUS4= golang.org/x/mod v0.0.0-20190513183733-4bf6d317e70e/go.mod h1:mXi4GBBbnImb6dmsKGUJ2LatrhH/nqhxcFungHvyanc= golang.org/x/mod v0.1.0/go.mod h1:0QHyrYULN0/3qlju5TqG8bIK38QM8yzMo5ekMj3DlcY= golang.org/x/mod v0.1.1-0.20191105210325-c90efee705ee/go.mod h1:QqPTAvyqsEbceGzBzNggFXnrqF1CaUcvgkdR5Ot7KZg= golang.org/x/mod v0.1.1-0.20191107180719-034126e5016b/go.mod h1:QqPTAvyqsEbceGzBzNggFXnrqF1CaUcvgkdR5Ot7KZg= +golang.org/x/mod v0.1.1-0.20191209134235-331c550502dd/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= golang.org/x/mod v0.2.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= golang.org/x/mod v0.4.2 h1:Gz96sIWK3OalVv/I/qNygP42zyoKp3xptRVCWRFEBvo= @@ -1688,6 +1714,7 @@ golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7w golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20201214210602-f9fddec55a1e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210112080510-489259a85091/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210119212857-b64e53b001e4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210124154548-22da62e12c0c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210303074136-134d130e1a04/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210309074719-68d13333faf2/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= @@ -1756,6 +1783,7 @@ golang.org/x/tools v0.0.0-20191216052735-49a3e744a425/go.mod h1:TB2adYChydJhpapK golang.org/x/tools v0.0.0-20191216173652-a0e659d51361/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= golang.org/x/tools v0.0.0-20191227053925-7b8e75db28f4/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= golang.org/x/tools v0.0.0-20200103221440-774c71fcf114/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= +golang.org/x/tools v0.0.0-20200117012304-6edc0a871e69/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= golang.org/x/tools v0.0.0-20200117161641-43d50277825c/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= golang.org/x/tools v0.0.0-20200122220014-bf1340f18c4a/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= golang.org/x/tools v0.0.0-20200130002326-2f3ba24bd6e7/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= @@ -1777,6 +1805,7 @@ golang.org/x/tools v0.0.0-20200804011535-6c149bb5ef0d/go.mod h1:njjCfa9FT2d7l9Bc golang.org/x/tools v0.0.0-20200825202427-b303f430e36d/go.mod h1:njjCfa9FT2d7l9Bc6FUM5FLjQPp3cFF28FI3qnDFljA= golang.org/x/tools v0.0.0-20201224043029-2b0845dc783e/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= golang.org/x/tools v0.0.0-20210106214847-113979e3529a/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= +golang.org/x/tools v0.1.0/go.mod h1:xkSsbof2nBLbhDlRMhhhyNLN/zl3eTqcnHD5viDpcZ0= golang.org/x/tools v0.1.1/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk= golang.org/x/tools v0.1.5 h1:ouewzE6p+/VEB31YYnTbEJdi8pFqKp4P4n85vwo3DHA= golang.org/x/tools v0.1.5/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk= @@ -1933,6 +1962,7 @@ honnef.co/go/tools v0.0.0-20190523083050-ea95bdfd59fc/go.mod h1:rf3lG4BRIbNafJWh honnef.co/go/tools v0.0.1-2019.2.3/go.mod h1:a3bituU0lyd329TUQxRnasdCoJDkEUEAqEt0JzvZhAg= honnef.co/go/tools v0.0.1-2020.1.3/go.mod h1:X/FiERA/W4tHapMX5mGpAtMSVEeEUOyHaw9vFzvIQ3k= honnef.co/go/tools v0.0.1-2020.1.4/go.mod h1:X/FiERA/W4tHapMX5mGpAtMSVEeEUOyHaw9vFzvIQ3k= +honnef.co/go/tools v0.1.3/go.mod h1:NgwopIslSNH47DimFoV78dnkksY2EFtX0ajyb3K/las= lukechampine.com/blake3 v1.1.6 h1:H3cROdztr7RCfoaTpGZFQsrqvweFLrqS73j7L7cmR5c= lukechampine.com/blake3 v1.1.6/go.mod h1:tkKEOtDkNtklkXtLNEOGNq5tcV90tJiA1vAA12R78LA= pgregory.net/rapid v0.4.7 h1:MTNRktPuv5FNqOO151TM9mDTa+XHcX6ypYeISDVD14g= diff --git a/test/sharness/t0054-dag-car-import-export-data/README.md b/test/sharness/t0054-dag-car-import-export-data/README.md index 77679af390f..2b6b5c00f24 100644 --- a/test/sharness/t0054-dag-car-import-export-data/README.md +++ b/test/sharness/t0054-dag-car-import-export-data/README.md @@ -22,3 +22,7 @@ - combined_naked_roots_genesis_and_128.car - only the roots of `lotus_devnet_genesis.car` and `lotus_testnet_export_128.car`, to to be used in combination with the root-less parts to validate "transactional" pinning +- lotus_testnet_export_128_v2.car +- lotus_devnet_genesis_v2.car + - generated with `car index lotus_testnet_export_128.car > lotus_testnet_export_128_v2.car` + - install `go-car` CLI from https://github.com/ipld/go-car diff --git a/test/sharness/t0054-dag-car-import-export-data/test_dataset_car.tar.xz b/test/sharness/t0054-dag-car-import-export-data/test_dataset_car.tar.xz new file mode 100644 index 0000000000000000000000000000000000000000..f64f2411d659c92a71e517120c1c1fa3844c5e18 GIT binary patch literal 386472 zcmV(jK=!}=H+ooF000E$*0e?f03iVu0001VFXf}+>Mrm8T>v^6O3ojnHV%V1A^!9+ zs9OV0@SMR=bhvsL3{=*O!MJr@Zp{JXeM?R5TjuX{X0i^xWX{RT2G?B04_QSoJVqT} zm=698Hr!2mu~-J_6Y7nJuyx#>7Z$I}WGwCW&(mW3tw`;Mf4Yaw3fn5oV?ici%H0>5 zTk{Zc559CFnRid{@$>A1Qr1?RopG;m$*diJ*F#d`3A6S-+!MIn2GE015zk{o72NrW z_JpfItI!i}e43nZ#!SWUjy8yLfBBNvTXUs;0HhSOuJ3$27y+g?l#_jmm`6D~jE&Ir z3xT|JX?IKwn!6p;tGQY7DW6WbRNSqGwrB~VoFK})8{zNDDq|*M zRLN`>X9~{?V|h)v-?H%sxuabU`@FRyRuwcH0^cxBGP*{J1nbSCqEO1Z=V}$6rV1b! zZWYj{Cp{weEKc;;kJQK>&YM89fS3fOQOoY8nq#XP{8?DFyT5EQF9 zI*y(!!zl+R@O`)|c$5}#xw~1Ff$M65Jr~-JKe(9@0%A)B&ES8M2#8TNC)ZUtDl{M! zJK(`pyED#!@WMwYJd3h4VAq*{x{tG@XinB>1HCiFT833MmgFMmy3?I%zM#ZdqXBGZ z9lDOFXig%yu^ZulU2XwW`$4Z!4(*Ug7FJ*?w#tv98uj=fDNXBayzt}%sWb$t0o*`1 zMqch+XINep-ff?}iT#=Gzq_mjcz78Q6q9;plnq|!KklOatqUm`>z9@TKysxlNlmc< z9lb_wcs8#%$zIXoN)(&JXUzpO+#Kazdi!ol$KEcMZu|d08j0BqA28$;S{y}|1(BDr zAra|9Xf0a~LyL9BIun2}9X>&S61$x_rB}>G3|E0an`_@VDSQl17FfwZkG4;RKz`99 z*}}%^R*0~L$027KB3wm{x_hfu;|z+1*^BA%f~e8X7AOe?a3Y1W!HJD0sNk6~Voh8J z+%>iCpRCccf4~~a*NcClUf1GiF8T_T_Y7?bx^kHZ7F&P$+%#?uBpPgT1iX>^X8aH_ z3p3!;%?gQ_ATH|QJLs=SjiIoZc!|%_@k=fr0pyg&BD1NJ>k%EG#a2J6g7 zm*AOS#(~#)8iYI{mtY?$n~ z#pQsnhgK;5mBaqMtr#&Mfw$4H8i)xellQBxOgU+jc=8euEhqLjv6r;tWk|;+X)j`@ z{FXW<%HYyCb-9}q&t1>18W889cw5Kr&jZXIT-Y~yMXxZ``VJ|%&im-egm$jLm@wZ@ zI)7=02>$xxWIa6hU%)q&+i$#5j1zt_I)<=~hx}`QMI(BBgNmANw0n)eJGQ zkCc`oSd^TL$LS+Vr7*{eYK(*h`PHB$TeRMLWXfWEuP%KPpk~5hjzoF$C7G29!)Y>2 zPgq}>%zaZZWW-m=NGrxU5VEmw>7GO?M1?609zb=k7p^T_N^~B%PO*Wv;*X_Sx|qznK*p!p7y0Gow{R z%g}RTArkSCkx@T}NhSvS=v{mJYEZ&TCM*u>)CbUg?&-Q`5vaNHNHQgmNjLJk=7fC+ zGV4DraO=hE#}IY}SZ?w2MKDLEtP=T^@Y-Yo(I}Y}dacaKVKa9u^tJXHvA1_p+T{K$ zV_=6iDJ*Zjbr*YK{i!Wu=?D*}3Kp1Aq%(n!357+<$bBvgfh_e5hjBT(gxb3nldzg6 zvyO|sX+NJp5U#&24xKS))v+|5<+*i7?1S9Cd=#N$`Ef6QPA_xLsmUGHUe>u|GH3qn zM?rp;X}*AwOt55}XAP-%>aP9aE`6sc{5_Go1Bot$)rJ_}C;HtGQxgw`=+O~mA&(;5 znJ~6)V0pgdaj&1*ApJY-{|c#UNUbM~4#_vHMZ(W!S#cJ^(i!zJQy;*<&a)A;xBv&u zS^Z1OGan^hCR|2=ILzo^22o`YtTMWiJl|OeDA!P*a4dJTNMw^H&oVI4pS&~CpH)*H zYbuI-?%AQ#W&udlNT8gu4f>3IT!puRf0_4mK<_E!-$#30V`O1t z_$=+g77<`iLDa4)F?bSSe}eC5Xl<2qDWB~0q{s2vz%$Dahk_NbVnmN}^56Q>HmIL) zF)l)l9Y_YBVM{`x?}s5fu#!#x^-l z^5#g#EiKXiKo+Cs1GV}g>wElLv#8WA#PXXjgb0;c(!YamX(_=Bf!H5FSWGMY4jl3X z>CKhp=CI7qXICQnr?UtvofIldT@zkZ=-|7XYGEP*R0TSD)xIoe?Cj;OiSXk%bycl?~e70AvLrPFt)rH&bsp)!6IaKiz4%+?t z47ukh%k(c)nxTd}L#eb)(RxHqG7u&*M~fA6j_&rPs7BOvnHdCJbE2R8yELm;9R$I>d z6AJFyW<33q+<$-hbJ<8}RWjRYi(5DQZZj!xMvc!V*a)=dmTK(CnJ_3gu<&|6wKGU=gPLf;L)8PJMu!yOobz#jmEW0+gkm!^ zSduLP$+X@cMGq&)Zi<4E@p2G!df8+|F=B+i6mgG!q|pO)>)PHBzuP=1rzIruh@qnvR)P5c_jG8&$`OHYjE$|kagINbSD9aDt>Inb;Ti=+~m$^A5T{`abcn| z#Vv}xiek0u^&*%P7)Sq=AB%g7(76=c$}#Z;W<5ALtfZaD>Z8x+qsNH1I#!g`-iq z+I1{&@u&!`u0}`C@7M~o^l2a8<7Iws@_p$Nvl9DLK|;^Sj~;u2c$PlBc;$baS^dK- z>1OJe?f_^Cf>j_i6P+LF_iiXcKxKl9;(DC$NodQHHnffvU7V(xgTsK3q(D8WzV~dF zZp^2wOl7W}BUovmZQ?vhzJiYyBv3Z349} z2$QG;K80dG8B_?Xkko|F3Y*+z4PLqYjM99yDi81Ck^aNhR?qcRo=k0ka?ZPIfO=FL zRhGEx$yP3!P8*>thrLsG`LL0o2CAP=(ulmsJeu8H57dqTldo%ac5A~ISlYg3Zll(p z__0BA8>Cfl!R;H?>F1CBd_+(P3(zWe(vG~tArU>YV(Ovca%0=IXbOR?;E@_XEhWH%g%TD(&e(Kvt%~!9MP-Vfaj5);t6WHV#pzmj8zQfp1a2FF9E@q&F5y(5 zqZ9Ez+!$RHVQbOvbv3tRu(!vXITt3HxCDag(XL%UTkF`%9%3qiVLy|rVt@Qe6)^Z%4qmP zfwAk=P?+!kZgGCI z#@&#m<9ZH{xypmtd!2p+1AF7)EsUy3qvu=wFr`m$GH%H8X1B39 zxNMF%+{d>Dv&lQwNq87B3fOk!xL1DgdtPQ<@DI#;cUP7W$jMKp6jZTxbs45^?o2{1 zVZSwCYcf%Cs92r1bcX=el>mQ(227IszA==U_L#mkw+aMNaJj@PoD_`v;BDmV7M(L+ zXf6;(rtAh%09RdFaHh8Q9~F}$um-4lxd(9yj}wuswID$-H*M+ckch#9-O z#HJ;=j~F=PxbvfLv%IYrs>#wjN@IEp($eW;OL{<(RPhM*CnOPJS3b1Vss6bocuRn#NjrAt z$B`__{fb`%9=Zzum;93q?X8I89+`z>ebt=h|FJyKQXDE~HqolI42u;ZcX$=BOxs>K`xh;%r6hM!J*cF^zxqq{X-AeVqt0hM)o(JA8VLdCdM9+@Lg07eGx|^m!vg0 znOnN~D1TO?#`8$>ly0Gp7>+4??N2`HzuEZ-H^T<5$!HIwZEm8X+)}`6sZf&W8sE(P zk#=X+R1M&s+{4gK%a_&+F8ED-{&q`!<>;bz5SkT`@+DnCiU=QLN86nBJu17Zsz&aZ zCR))Wnd>vVf2OR&9 z=cfzNAPH(A#@Lxu4!1X=V7B7BM|qv9^uiL(vnNa1$ApU{dP|O7utvMq=o2wD-&a;E zSl&euGZ@@lV8$4-h(dueV2tCHjNFh}mNm#;GsEIP)|D~A@Y@QrD<1W35KRqJuGnH? zRIZnTC{FCoV2-c%Oh%kDN26w~_-VFphn!%lMt5oDmyvF*2pO|GM=6OhF&^r1?LSKr z7y6wP7nTpPf3)Y(Cq4=EunhO5=+CEBPu77gc=Dh?L*^SleOE~r-Fs2j2uGj%qexv; zoQES4cOw3@TQnDs@j-42LYVOYA{`nzRGVLp#xMq;-bO)?#-nV=$%ams`42TuciC=4 z@a>R|wUr?x{#Bm~k*}a5QX~=1P;Tr9$mz@8X-PhipQ^u3By?J&--;W=X(XQ$IT-MRwAc)JXx zfp(c7LS;*p8PqPMTtaj1Hj>{RhIbEfTJd1?>2_YWBiFmGFQm zz_0E=Lko;}dl_`>&VT1)3xl^Q6EK%p>bVH{5el9(SZP2;nY+#RT`v@K#trH{DHiF*_I#wT(#&8)uoBVxc{Ujrb@>^y zmWG+1#pU)n9cjPDVnnm-rljeFyBi0G>-Elz`BZ%O1m$kUf~ZGdzOZmY7bmo!)Wn}^ zajbDmsG-c18=>L>0$^kvM=ywoRJp2z`+QW)217493Z1dfpd*?r#!X>cobwZ+Xc z63d)xus1OJzY$j;U3JRun7>U<6avtfE}fY9g4fFSrd1Wv6OID@Ir3nYA@tCu zOAM-NTT@Jtyy0~cX~A4pd&fnn@q%$=w^o|l zW+{kb2{cgS-Q&HUjHiKzcy-AWFW727SyXWQsK1XwygHd|iBrOqi9?y&&R3nLuow6P zL$d;_7|+nZR{b8*tl^svO@nv-^7Hyfl=K+Yq!DZCOc)0*_sZA({#+I1Y(FVS-B0#PEbkpN`fvh(zwe4sdq zOnF)qSBq#;I?*89iKsas?@_T~uEO{{Py&52Nb@A4rA2d)RqRP$*J|7Pwi2*vqc%Su zF#)kit*jA594b`K$h+q zt3OJKNRTkHHL|(K)B!@rM~bU@bbB*;E1rAc$W|j_#qvys!%4byPA`O2yptUjKwvHE zR#t|NJ*f|gVl?G`t5t4m#2U|8AcbcbMWgD;b!H^;R_ADaqjL-^=_}Sy|QtE zY)>?@+D^_5)*m{rDp%}O+r0m~o?2KmiPnEwKd>zzM27;rJW0ZKz~42yFN7U{f1s$c z%vW-7TE0BHd$iU3^EPgqH?|WQ$W?2%us|x<(YA2@T?=L$D80k)@c?^1_#7oV2d%NS z48A|>JXVIgX?o3K6yH-5Korh>+=}NgQVQ^wD-9hQ&G2*=)%K5~f#xXnt4ajoM9&EQ z^c~nUuk_`t08aEUH#uxp*a0FC>7?>9MHS81{v;!{p!}x2%6aw1vJ_PFogt3SD z+!hQto$Fr>aJcfNA57Ew;1W9+0IkX*Q!L&-!!I`X{e%)SO3BZF>)m(CgDQIeHQDBJ9~I6`Vm(hRL$l(?*5AI7(O0GD3yi}`oW?tt4HnjY%#CTnft=PR=aH}ej$Fij@_v+09q=0JZFJ6S z(HKCqg4}8qfjAH;Dgkjl&jNnx;d#Ff4yS>&lzw&wY(~-H2+=SRH-!xe*$QlF|G%UF z)n(5oQVJ=P7Ytz`yaS_aEDpzSh^d)ZmOaqhHsKg9{-2srQ*g^RVF1(#IS){_Ex+xE zS^4aYj4aNvGp;@*usf|m#p(Ry-)A1$3N_Yv5ns~=Mb@_Sn9M5Dr1_pB;!tWG$jDj( zwt(V8n=GxhAMrTg58SO{L@M#Y;;!#kqwcFD^O$PjNxC?fy|Yx_@)Sy!n9iLa+Cw7W z!Rq<{FLW?JeXv`yn1Qx3Slfs$f^t?Pc!p*mV-x<#OHV*`-$2O_xE@DnJiR0@mcf&# zjY!ekWQ3jInEJP?{kr}3G!Rw5l+B?B-$@8(uiXxUhUghaeKtCJQj#y72x z?aT#&J3y(DL?(sf8(J_VM*`X7<|(F=fYLKmRMkP$-}Tk4*gsePx_qifp$ohn?}ih` zSlg%(u9^i(Y$|9+LDA}9E2wl{p|JE>&`Md8DYqq%m6VsYvA z3RfwHEY{|ZY zveRyNFx$}6l#`^OIyFQ9iYC>4?qi`U$iW`p7)wS&B@P9WR3F4wsPV&5@a?ZV3doKjCW{&`JwnSVHde`O7rVc%BQ4jau!jA&d=mk z-&~NNX)#alpToD}&j-<5VqYA8YLv|+rR{G`7Kpw2f;|722)Bi`TXK>})*?>W->a$C z*Z*tf7muQEe@6ha$K|v2V7c_2Gx|Nb&@0D>FsSJ)ZrMS4LN6>qLxOcgGNO1jx zq^60CtRbjImPsbiwv#M~2H_isP%W_j1%cgk+uW&#n3O~Z4D)x_Ik-V-5!9vtG6Jv+ z;dNiy$Xf@VL_YNm#s*EjMVy96!MhBAVpa{Llq~hCk->mlnGKa|ILuiD<*Pv4v0EJ4 zG7H}T&Ze-yeBBVD@6AO%L{6O>Bor1g%d@`nobAExc`MCP$gQwQx9^GU zze^0ZkQC3I@JCbm^A~LmGJ)k{C2i(qvkfgcLB5aHP$724u>4`NycN_u*F@1lPneD; zrHx+}j*WKk>scpTJ}vHN-Qd1Y1LP3z!R$lZCg~49awBr42q_LpWsTUtRe*0DRl`{T z`dO4ZmhwUXZeY-2_p2nRouS}>((&dx2_)))j%2SSVO8IMs51bmH>keFtk-Qy{RoVgEfA?8SPjkFt#6XXK}!Cd6` zrduCWJ&V>3co3FSf5(|B-%2^zQEt`FoH|Ts!d_w0e;(&YzV=ieh2(SKhK+$Htdp$; z4LVYqBQjOh_TwioNn%;aIl-3C2i?8bQo?~R)Ker@Nz& z%qEen2>li&*t_(*Pymuxb`2rhUJYC?x+N8DX6>|QID=Fu5RhmiM^eGxcxAMlL%v$p z(Y2Y9aUL#)+a;Lm)N&k2;a=)`LweN~N3rY?82rY^XPj8I-H{GZv>Iy(i3f~HZN^O< z-;WY*Cjz$?^6Wel?x8DpZKZ#tf#<^GEG@#B%Fj+~UFLR?-6m`hma^%CW%-)fKT|z` zn{V3NT!L{9B*s*;lEP8{ZEpTldHt`yxBXG$>tlQ(r#hM_G|pC1BygY#KdxF0M>PDL z0v*Fv^vr>Q@Rj4ymN74(5u;4%Vpyp!Mh$AKrXUrxW`uQoYDHPCR1-6cPL$wqZ-Ru! zLpl`^`fXhP)*!s>*V+{Gn)8IpN!vbSep(B%F%O$vpq6?%K;Rf;WI6FDbTNmAg%bse z`)yj3Z7ax=<5Mz7{9;9tA3HB%#VwyN%>(3UbotAi%lrm92 zY&nqC-vexQ7^!0LH=3Z-UZZ+r%qkoBL-HqFXsQ3kb0+cUr3|~P;CjTT@F@T06+}UV zf+)O}biQk(>6r*B2GS(H#=7aZ%p9~TFx)L~9PH_kA)^1OhMk9{`sy(O(3*w=o#w^YZjhTdy~LUt?Co zp5a9hIi+NR-ws46>bQ;MNkFgW*`}v&ada|8VhddvO)eeQAmoWmTibrfMlPRB0N^{8 z4Rr4a(MKFypZ`nzpB_q$6-V@V_fA z%WK6TbL|Hb@US-H;ruJ?kc^63CrdKobviCHu11A<6ZsLzHq!H_J`R3X(3IV&*w)x` z`5F(KfR1hWC@@bKA*t*7sAi-m8pabZf>o9owsA{{P`8>xb)NfYm{|aMMJg#RwZrVp zD1EU}n#YeQ4ei1-Y0P?a7!{!ke&vun-tFMw{%lUu0^(H8CNLTeWk&gJbi(Ph-Dp64 z=s_TebxTFn^6--KcWNBP9O(J;}wV_(mo!J1lD8LMO#PNA&XP41z9D9+{;4Qb8) ziz*WTUg_@?sC(>yy*Gy#U&2{QzPe@jf25`Sok{}$uiD;)jP@YlWjE~9 z=TbQj zSL*yBZ-E;~5z7s-_!3;L+5(B+Ae(ak;^8I7W8{W0jV?4S>6stGX*}i03R8jv63RC* z3=>mLNHPASCw;N8$dQC$eLlTX_9QUhGg=z!!u+Hp45v_8Mn}73J+UG!KFZIDH_(lq zTF~+q*X4utp+Vg@@Q}}d-T2js?35ffeH=_NONskvgU%@hl0bS?^6kG)G*_Jbaxi4b z{Hngwc!#}`N=T=+=4ILYV~mb7BdP95ARRVsAwTj`d?no#)tjcn^=|g-%YVF64h1l_ z&AVUJiyfzP{$&s*6EdlAnfpqY1f|sRWqQISu7e$6YS>Wem9-sDJvDO#JnR)F)IuA+ zp%w>ZE*{o}`r$dBxR4$cc(b3f<()O{wOUBUy+Y3DWjiO{A_+QuDSiS>zC(BKadYi? zXT1?1phjW!%2^ksbj`!#jC>U?jPrg<>kjVOpYk@`eX%)G3G~$jyN$32b85S58pnjP z%U#W4q%1?XqqK&l;2wa1fXo;)eMv|tv!MFQh=hbfYeE>%_5GZaRU#V|?x!+NF~7rU zDk3~n1mCE0Di`s-Fx@cAuS+`ht71V)hIN`ZFt2<|Aa!K+D(gsP2L_cgf%NEGiZ;3iG?Q3YY~D3B=b5HGqytDXUi{q#c6 z@S^dUzk+**DyWsK9VMl`r*c>cWdIsgc0LIXPJ%7*6GfofzYe+kdUYutq6?p@t(T1h z@MY!;ljKGw{LA;p&&lG?Oksx|Z43v0dy1hwP4?KXeO`GvtW7Cf+^V1jy$$B_3Jv^w z`|!sQ0{gO`3JbLG2}kH1JC79`77+Z<7^u&-Gs_fmOSPDl%W;<~#wXDUjS!tt>Gz9w z{xfVSA&Yg|UppA*#<8nYoT<7-59TG#ka4JpXwt`g?cG^=ADi&}O7fy2+&2i#lx1)1 z;(oS5FO11|WMTmlCHif>^W`=?rG<;s6b|j#Pwg!v3r)ozmWSygeUJ7Nghmv>2N(=e z+?_E*c^UsUViBzUc}+pK`$?NB4W-`%!ML<%;T#cQY1a_tbWc%dI=Cj3i=k|m zj^L3j0aBl?5a8c}?T?f%EoL0o`An;E;B)>+X$deCK(n3a+y`t2Wf>Smqa1#;R4rs} zwV@S_zz7>DHaD1Xn!v(hV&FJiF@byYt^USmm3exMzH zA&124MOr*NWUiHKYK-9FV+Q6I{x{`9r6wd;8h_P~TT7gj0^6mfcb-04 z)l@eBc~8s&m_fmTB+1nvQkC0}4SoPYn#!aam}JtApgcyVi|U$R2eg|qdMq3&ud~^H zaH9TFbI=!^IUoUvXZ}Nx__P;@Q1TSWR#enBcAq{)aEFfsuq|VZX-v@(XOnAzXv^4E5kr_S^ zg2hGQvzvV3^!0U$nak40|0>+!bG(HjNCJKi6`jvG5!gF#$NcS41^x7wT!T;PB4i>A z?w=?HSI)Uf0#Z`Xde!i0T-^X=w#w3*Ve^!fmo5nLk&WV7H3;aho(4hq4xio5!={iu zlFWu(p3V{SN(B$;mJvV1m#$sgxs}}*A7F?(ffujK#c{DT#Z9oK%H*D_GN!0y&WIwQ zFe_d1Xx9u^=>X}r=v54+a68X3dOmam_THA=`-~*B>+jK&{f#XX z2AXCU#)I%NU*E!eR)g+&)f{%bHpa=zNZ{WID#=gc9$6Wt26tFzZsI6oH;Vwz%h~-c zIYvA?XurNbxrC{tR{c2W-*do)dULR30w`ldOz{(B_8h?5X6%LzEpk6(5)&+#LaHv# zO4ksU>-E;sFN@fc>v0XxQM`53)E+pjye3Kgq%bfuP#Q{Sbr1BHvWKl(vNN@Y1_g5) zXL!(beu92FRvm;9(pAg7ECIb&nB4`@lUFm@KtGyzGllX+#gOoN*dAgN3Mv zinnJ*@8_|%+P!ZK!-;xNh}f9nN>6Q4H_N)gP%)JyfV5pG(3D)?rE*!)|MUHl_mS@# zuTkh-3NhTlab469J@dW9x}rF~mRL+U13+vs3w1?b_Ilx!->2whIAMz@0hNPE74Bu1 ziZvw=3$Hm=$rKKs0WYRddfBQaj(yS_DAIQQ<=r{_6X6I?1@#!Z;tNBlK7TPb4agEA zh%Mk6!w6$Y$o2s+0BKoVHM7b6ALy-olF9s%bmhjR@a==48@iRT#Alu}(|NqDU1X*Q zSyOf&F}=lpavzBW=QGA*uU1Rg&9{j*N;^d@q;Hybjs``_?Qzgs%V*$?U@|wxOzX=7 zjZuc&&nP`e-f1E4@sgkZ!X|c~0qQ5~GjS$ktVKr-sVi60A>D#Pmc_aYV9LuMY74?=rMDdpt>sABx}#$WG&f(2!#^SoKcO2)M$8cS4n>RCm3PQBiABo78$2W};&_7&j8#!L`@$YIi;#kD< zLPk{0b*AoJxUWM_VZ<%NEOJl7hdz}H5KC2H;**LulUrJxDyGj5X(@oG9-i-i#U+Rg z@lRCPQQ*cj;j1ttdj~%HJ|fP@I210{KDp5Fdc-Y(`ER-FawdtEbH}u>NwURo5?8rR z0(xxI?xk&M1W42F|arX(M$^2U9f$GU5~eF zk_NdaxVAtIb{%jReRWQ~J4A4DOOhpyHY$Nn0>lt9A6!t?Wfw? zPf+%$?HBR=E4t139y?t!1T2_v*I|vCCp>aK%^+GfKRyWnPocDp$Eq#o54>5U1 zTy~gcr+a%jC+j$dc@#bt=cA6{1y3DiAgyt8bT&kFiz3tD=;1Noxxbz9Jkc}iXn|G2 z*?&}GClFB$i&%AfP-PDrOo@U*5`4Qe^@Ab@7|PO}|L4f)qVkLKb>gRdq`gr&HZIbh zMO%}@cx+I?FQwr+Y0d{ag?t8t2zvLcMcao0$!Wh$BfG?vFf}BYb~yV-OgWW*b8csS3xqVVR+KP z6Ha;bN9Ctj9dwGODm4ww+j&HM#!VjX7ODes;4^?<(wx@YEX1?;WGO}ap6XlB>;ET* z@0hg+R`Myw6^0W|6eA~y*u^#mjhFEmmA#bCUbaZs%43{Qx+Pfr_f)e&2sG|xE9f8A zf1PK&Cg}cFX+8~jtZLGT3CUBdyck>m2?N?7{n~GFJ4P#AUc?pwv8Vw6Kv3m9Whw)1 z$MjWmGX9laPv`9WL(g&8us|m6vGR*ibgfSt%9SrKPt0~Hct4#h>1~yTITH}((eD8+ zf5T#AjaV7c453%VlyHF55MD-VS;+ce*@IAJXX_w!|9R`)S`wt`>kJFOrKQDdU=j#u z6CjTQQ5=u=BM(`wxBWm09NRt0+#^eSY5)p%16D(Q)I!&;HD<;ow8~`AyJs;5syRf< zY@`F@E(&$Zl?(8%hg05AWK9mK2cE7=h@W^@3(l0tqg}_8wi85vm>6Fj>}D%=&UfRzs~>Nwz+GZ_YdpAh=h-m@=}+uH@C~Bb`*q{h zckte`euwc{0H+T=(-T3$!e>#UzkMr85_3`b9Bc&w)hcr58#5Le`}X-fp^tqqqgiKr_)jd-QH8#Ynsp1I7b@eF4<_X)ckJ(i>WH z4f0d5-IC)nw$VQ81(P6#-cVz_o1+GWCo3@9-R!nm2$k_fsw>i;NOxapaA8oFt0$iVQB9G;)fcr2Zt({~{wFt( zqIe7m)vg5>!*sj6lXJVB|7>d!@O@OwN>xIRvuBLRIMo`JrT;H!vCIgJUrIqOeM?M+ z<}(>+7&X@)7ac@5i~WL(G7E!^k{ot}U)(kgk$3-j$?Q5~i@^2_F^4VA`@J^J_g(O= zU9>->YOC`m;K(DeFbT2AJ+^qb$oalpV%n+9_!`aSvLogb(gCvsxl!+VxWRXuz8imFIfF0tZ}MrRsOO3Fr@A{}yTKmV2%MA$bB=w18B56=mQQLVdvLqqa4ry zfm=9-9t!i@+m(dum+fQuVl2RvI>!QvW$@f^Pm+EaaWJ3}KzvA`Il59i;FhB{V{rDn z=)yg9TB>PKYu?y!ta*F$G>xFhgfJ4d4+F_>Ak(@n;_{T9+ zeQ%LZM(MoDS)@rdo_pTt>Xk*%2c1eNPe=!c>FUKZEfv^fE-5^U?iO9OP?XNS%67wk zs8F=8z_?-uMs)<0kv#<1hndj4nMGiHX^Un)*E=lB$|TlExw1+orPcH`M@bPf67ySi zIDX}ZMqTCNobfv;3V~XT`HZJ;C#oKw;`rKG$}`O$S+w&qo(=1lX@$?*a4fApkJBMC z%$*netcJbG6Dw-J)7p~(|KKW~4UAvtF9^Q11R~L%br=JC;9F(RX&eHgBVIe87qlo6 z;Q5=OP5hM^0oZ#@o;&YE?AT^q0nc_n;?TE=V-b1?Ev-;i>sVf?pb{%#Y{676+?E+y z349-TB$=HnJib_1lURj^Sp_^!L~2N+E+u*i<*lC;A4Z0NkZqkF9OC^NXZ4r%q(;Uc z!#hbFlH+cTIrH}vX0)IT>o;%Mi3DgjANa)+BpOS~-`o_xRD>pU)2zjq?y4TOQ6Eh~ zBxA#SD-j&4znMgG{8mIRF3-H#h{TrA>37ojNUNfQYV*L2cxSn}2P2ZHBDrGes_wY( zJ(l}1Sgd-fviy+k(xpA6-=K;}G~fLh$Wb_%EBpF~C^!9Xdn$D&+UXf06W6U;7~W?+ z6h5B_=CQK@$C6G)N!uwa^h>qifWqcDvk@gi8v@Y3?I_3OY<#XDGJ9h5brXjc(J?~o z2n>0#5QlTQqIvgq42bo~I;wYbJm^H=JZ8Di7Lt+U93bAG}BkYvT3Fw63sZcGXr4oN%k z8*raWWJA@s8$of8$Iu3HMr=SR^VssLvFM3lDl}q6i+=eeai7=4`fj&eSVC*04bFwz zypB;gsdwYxATu%;Eig3V*>F{%L{nrWKD}FL0-wVFloX=jv{@+n5{rhh&~q9@Rao9Q z7@IfiNp8o~U+E)^YEiF^?He{>;YSm=JeXD_#%y5?@{FINpsv?fOpK89I>y%Mj!z)K z6d_t#(|JLPlmT0F{D6YmY`@q*5QlCYe70tfZ`%Y2+y6e~aswD&&&xsxRE~+AN|^PP zK1aeIl5{V;D=7uGX9@4m+o+39$H#8YJc5r5HePjZ#gYU*p<3rUah&h`u-0hGr%bM{ zd%JCRIK1zxwBQ0IIUgc1)MwbJzQS{(5?`s|)|KAbC10}Ebst#AF!8a)beDcfPjcDg zg}alMriay6ae>u|Q0n^WMZ;Ooy?GFQv61{7PmS^EA$kAr`&)3=78bRn8F2s%*XG5%IMBWaLty z#fdJ6LM)i*i&@E~nVM{WU8V^ADg8uqgMxO6Lz}P%#k63hOmY6G$2c+ORGOffshJk0Ya*TMU<=d$9TNb();em4 zg`@%Y`*Y?obeuNz3<*hOf423vofi|%u5dX#(bFEZ5>$*tN$x-_#uR=3I^j8Ol*_)q zxpa|XzjxevQNKUexWQcX#=#_%0mpFjmWaC6`Atj zF`~G*{0YkV*P225aO*Z2*y(`Vw>D)Wd&AEV6H~?z@X5&Kepk zEhWimoA6(lZP7*9v=Y|nkJpwGc%s5bfVIcxjSrtVJ_3Q=4$nPm4#%dRN#$=ZWuT<& zJQ^&s(a$cWKin9+Yc8I!nOUI>tQ)kn(TJWf+x-@O&?6!X>5g@I>L z{pamyCT!m`icj5%Cj_Ld4_64)Txca6d+%VDx`@%}k5rvx2v6EG4tJ>Ua)kgp9~qqRJCDhnZEDk-)*@1%;A}|13RF_42b#?o(fkf1q^(p*3cto=ISPJY$RqBIAir zDZ+mo3!!S?(2ocWpLf2%`iZ%*OmO1$%J=mtV_vXWY$&Jr zWk`y^>L>@IQnw$*qx*$lPQ&7@@6%uKbr&NgO3)lK_w6$#!iFC}h02-_jt(1_mUB60 zha=XKRyQn194t{1{poisQO<#np*G3Io6!>A0KH^aKs=uwZ4-y}F~M}?G<>X>+Jfj5 zeKCGdbOPyqgJXAkMw2uPU4J9c$9+jG`PIFwbQZEP7(%8bTS!)e=GaA{uasbPXR9=8 zpca$Q0VY~P^GrGXfzTX6C(Mu1&OHYnkIeKHkpZs#TBmZQ>t*IY1KcP_KnaJj7R>moGof61itvA+#R?!po4(|Da{@Uhg+X0t|mWtBk(iG^v@2hsz z)9fq0(z9qw!f;pw|GgD4K9q?Tr$N4=d@R!UQta3>ddVA1oZqrJ zjGP=rmXL@CCQ&@mn z7yVKOE&&x@>l~oqsj2gZ1i{HbMLj;asq%ws%ppcMMq&^C84Sj}$!F5t8XZ|JTDZ4{ zJgfd3>{{>bHe8=zgBq#jh4n0I51*HQXVlka5R{GKHv+DOPlh{(a}|HUX)_36S{@Dk z{}$>lWWCS96K)JGA|vP7(=xXswc7Me{foNHTlADCF^FzU9?gQG1V`h*vHpZGg@GGM zouG@-T>`u%gL07@N*bm^?|U=|TV?&jv-G&@zL)@`Sc5|>VCH7y$E$gY<&RJy z7t4UgJyXRvmhZ;hh)9jais_qj_IdYJU@J%d;(WumXB76)-voSp$T3SFXEIO8X%Bc8 z9_m49*pSas8{!ojOWga(>Kr{$&2xQyPcnny2rC(ePFJ#7KB*lEoLB?ohcH9E5C9wo z`gXx^4y^U3Xk|mS-K`lp%4@URgCFp33T?lOKFbf0=r^u=NrS{OzPJeBi=67GgoB?O?uJTBu!!O4& zS@9Ohs<}X2Os>Et5NEKJ4ABEyX5qh0mvn=o1T)10hmy-bA7G&aH z?CG7>US5PW387R97a=MPv&#Y)fuRmtJzh)Xf!~#@u?b?XBJ*>=gP&yH$uiX7?+H$=BHjpBvl($tJjY?KFMt@)oDm_kLBMv; zHDG#jB}N~+{E;CbJs`r4D$FE_^<)78$!oWn3WoV`#S+fErN2i?oRymr{3vcm%AOd{JP?A`9uW5WdZe^ie4En@c81~ z>P(iiy>%|(?O3`^HD39>nqVbagC6@$C#N_5I{r^M-wxB-DumACo^ccsz%{`M;kbWTeS zcyltjmU^GBYI*gJB6`^@7a8N4+Dd|oFvX`-Lc53Svmit539nb{AdXvqAa4Z2MddwJ zZxB9XkUXX*t89o0dgnVfoCZnjG`Gv5?veu|A*tbzdT5kKlgcvu0V|ez2;o)QjJfni-!?7 z$)N@WV(tm|tC>)20LK+qEGofDU0o0~74HXo5-3Zb{Sc>n9EWFJ&Nu&f1p~hR5)IP{ z(vHU7r05{MaLjtw%{~4P*~&BubHWYL#5dKl$M>{_JL|vR0X9BvyN1)9u~MJ(x&Ra~ zfJpdkzzTrICtqi{2-N*Px(}hKXwMln7*Gfcky&`; zX5(-Qntv~qB0SFeH%If>&K8R#%?zdUlb^xZ=T+og~NkhQSR3$GZCaZ9?t1UoNOXV+dEP+!zu z+B&E!tWU6p;Vf0K2=;W&X>7rbbqwqC9C0zCnY(av&`&mi-l;G`hLnLMwJ^Vb41m0k zaDE(4e4By&RN?olm0)}!K}lOP&BA>z4rlfQW3z|AgIVq3Xd!ROkx0|@35+|nQK;0n z$i^Vrlkse!gM>Q$!+H)JogD$1-pb`O34fllBXi37OLcXM`<+=E!oiob9uJM7>#`bl zwhk;7%~F>xVmlGBh53=pJ*#$4^FG5FEwMix!4ryeE~lZpKRpxqCEb(pT9}1-Fnu{$ohrK|@D%VJO3~*yovFg_-8nQe+b@-Rqi;uJDXS z1HgVcp^#!{jEV6QX#%wR7_5|V+41BiG2}cTawa{(NXd= z1iDB5*@6v!5UOPEt7(dlJm(tdFc+5ghf%(y?T52y_|R%C0fhgR-p)v)@QA?OpTt79 z3(!K*{}B0CYo$hCTg?HNHtkpKyOX)v@b1xjczGtbn+aqfi9LjmA(IfV3U~Tjd-MZIPM8RB*fTNuN=pS~%6%VDVm$}zD-Gt55&rCDy8gTu z20Crx_}5GO*C13}`XB%iWy=-ir`fpT7?CL{uibHZ6u}2XvZ_5vpy$AB9*XfP9(-X*>3(Y=Tl*5=7Qh&rus6SPiHSDTB)+iJ? zuU0aP%o7N1fff;R79@+fWc|8jJoxF)rUh&(u4T)-GZI1RyF63HR zFVnqIkvC5-c=Y2<`(q#4{Bz$`Bzew#$8iuynrN?l1`>z5B^Ok~U~=C4bfAan!V6Il zMH?A9k~eJMQmJTV{nX9P2<+cbt}rEZlQjaIH`AcX|LuayLCMTnWUCMg;&kl0I5raD zyvPj0fJO+D{r--uV!~dj3v4#Q#7(c*_OIPeu!@!>M;D$d#0Urm-A~HOhZAcS?$n@) zP71@>AFib2I;>Agm2ru}JU8;-tu$WCW*~YKK+>sLJ$GP0Fv!j`-DuKsE8K#J3?_*d z>dz$d2N;;|V9Oft(8=$b=%({TQC7@;!bu#3AYgf{F+5HN6r(+y4mcDEoK#GnW(w3% z`9TaiBE6`u{zxmfI_hWY77NBOds8{qq7kqtTe@^S`LgAoB*b_OVE&(*Z@9~lys71| zS)!mQ+pO~d(IRbnujtLb70kThRmtK0nYaZUwK70I<`d@Sxj0eoH@6{K6F51>vo0(L ze?So(P*~0ZKu|3B+%!iUDAI%-nO8ZbSf(reL7O_!qMrc`s(`S0K~ZWc5MCcnyb(C+ z)z%HDR5%w;+1gZ{#|@5du|cpT2us6$>czWtG+QI3=xN8~s*u1uWTOy(oc?Ug!LGZD zPs?A-bs>Qh`9*T6PJTNZY3?;tAI9HNZFd`az=A~l_6$b+V6A~j;0Vf~#&gj}`_CS= zhH3WAH4v<}CI`BNPicf>1+hwx?G4+glD8#cxmt98mrW;U$J;!+9=ULHj&fvWAa)$6)G-eZ^eML+#cF%XYPe(RRXFzFNjfJ1bB!`${F`eF>|iL$`7ccTa7 zs3lN?@?bg6&#Oa%Z%m6{8@ppG8URglp+q&v%FYv&)ziJ!{2sxFwB^MAnKGU48Gwx` z`o5He*m6#D4_~IM0|S8-S+k`ZL7SwSF@mFlqr-hHYkxupfrjO@-Yo#YP;&TcKBN4D zhjhpCZjz@h1TA^^2T2m688M@c!J1maHusu(}@#jf5Yq_*kde9P%ih1!#?hhk<%sY>56# zL(m|s0%qE<1X!BM870h@uxd$K{fS)ON6L6udE618U?GP8VJI+gZJ9Kd7Q9=bln7cU zh^4?pn`g;kzSb&EkG&{8eizJYOghUlpJJ=$A5S{9 zis#8~N3iFoIWCQz&EyuJsr+raM-Q;vYBxBmM@acA)Bh6CD3HH?Kk(8bujBA zCK-|P(`@$C=c9rY5eE5E|nMAan77DR8?pT%>N(yUjbpv5`j8? zS+5JWpB(n4@mY`D>Lr8P)Sk}aowC$7bI^C$X!x+CUMUd|i@au(bvTO@b_j}rQeR|N zlGd-dY%*a8z;$1vFJnCQIPm$6VOWc9Ix38FTD-eSvqj5D}aDPv|?;9 z1eOi41|+yr+PRurNC{qS^L28UwGLgDtHG+Ae7K$0NaoI%YSma6I&S@d-rMM~0-l5`X5J1Xikjlu{4+k~q9dNtG&#nCJO=rgl zoBD1Kaykv(h~>*I)bawX3oh8I&0qVS2#35Uatw z=V>1Y#1l#^DpiNIr{`OS==&igpnMOtQ~+%Q(mS*iE_(jjh|3QB7ET7qe%iu|8zdw6SjFEuJDqmWCA-e zD-@cP1$9sAnH@{;g#$$Dst;1%`{wqjNGrj_9i4qARxC@}nrz~m z;qkbn`1x2UvX4T)@4$d&5I(Vp$B>G9U%0kY5v^29kXVemjMB{sycT+AwC(Firng%l z039c~SK&s7Y;Ex+)Ki>8?8+|ap{ zg=wg-I|8E099ce>nn*Mh%}`9BgP}-Ec@b(n874Ar}YPSc5(;FnTw zNY4Bpb~30vr!PV;&Y(}=hEA67T}XI#9kmc8k!T`bS8=H@ln}Ag#Z?DE2B8J}s&^Zh zcAEe0JtofZoG$`iUEzmtTxQ=`{_odZ?3L?wyr}xRuAz%|d@Se?DE=IW`LNs3>uRVF zdj}El6_EC#ciMy=?!*beFl3DsK7N5o7560Ig0Miz(P{f>qU^bCCh=ihZDvOQn7xX) zo<64Yd&#r#3=%-3m7y$$Ug(5r{j=WlmrT+2)1k(I;ZSy=a|IQ^qJtqy4KZ9tKIgg< z43vFLZ7rxteGdb-xy&e8=$dxNd)P*FWQBLXPr1xc_J6nG*-JR2Cr&TN!@(>>SqqpM z6bE5XVxNDC>L<*s8vxV~wNHPSGz!+82t$Fp0|}N(ykqgI1L;eL1hiJ7a6|;OXp92= z4)!vfNp#(IwqTo)G8yll7dJqdGrVW5r%u2(JLn>4+S7Z&fAuE)_54b&GbuugzYDj1 zxySdJdtg%q@5fuXqII@DWEd>qX9A9RES0D3kP`=#izt@E+g0X0a+c(s)n z8P^zEM$1adwM604?I0y`df4lAfGYF*!v5J=#29B?^l|iS$GSZ!3!=V!!10yc;j(~` zNEkOustx2^V2m>i(T~mc-|HlJJJaX@Gsn4Ne>ZkaqFFCvU|jF!O}3~sjxV{mf3-b= z7;IQcjnROhCf=d68;a(LD|IcC@GZUAek%e~jh#8rH5zEe5K0mx26V=!N_!|x%dBH%E(4mG-{BY|t;V~X*KnLfW+jlAnfw2gTX*|Zi1tU?QI zLg?poTpT>wU%sM`7|cQgtr5;`38B)sgvoEcsrP!}#3@pK*GPwf{stj8XBKp-DwXd- zK+Dd6vVjA8cao;(|0S zRp;27bo_b-AajRz4jpV2+AGHC$+gi8H)6Sscu^s2ZCYG{$WK}~MuPI~c@WfN|JO7t z?ef79x^uCA7=4}N)>ll}gvfG6MJy?~YGSO1)jK+My;wYSXKNrugBKvBz*Jp9{Ott^ z|GjC?p$_B=eqQ%r=F+9Mp8}8iFfv!g8@;7NyD=kekjgKQuRk=uX)VDw&6gZ~>*A*E zfM1k7fjKjeFA$CCROY8E>6es#C(29UrxK7Pr4aTWRKNOfFw$k`7TP+t)YONG)A`-9 zh2OExqd{NdE^^ggdzj+hmy`baWnC{i_4s1=i}z6j@pSDVk=;rZU{td1l>7H#hq)0v z!!`Z7wi9+3Tlgu@&l;INC>O$`OV=wdD#_?Up5YuR(f!rHO$c-m$YU87P~NELoAE~%=tdQtA5!JK;3&Zdt0a0E8`V!4aO79j$p&z$xf;DZc>2I7$Scd+y;K4}SlsBR zz)|GP3I$Q)=!HV?MR7^+>%09^o-M;7p_uxT(_*=Dw&v2e4x7LaG%dxCFT!Qn2VYLm z#2N?&N_n7ipEc4~*kLOIA~Kh0hVuMIybEf*V(1UhQUHYvHgzBNxH7ikB4)E7gq4yX zMWoDv;gx1XpcuYoC8<(2H6SKyqlZ@Y$o!#C?4lFqVN_pB%+w(;SjT=4@5w#T_EosZ z-dAIbKI1DQEKIdXeHI%A6AL6}^TvyWaCZ+~5zZF+(SXUf!<86zi5^E}2RPl3Z}IgO zvwcX(ub_Tw-9AJ$oPr^TDzY8}w3sX3VBwF>MVf(i;TpE@oei+)OM)eap-P0rNQ1Lt zgM8IokroCPLP3Q5=$SC921Shk^xXHoA`-9Evg&@zc~W4f-(f4^5qKta9qsDDNxt8*kR>T zhWdCWz1}%HU%+|;`#H3Z%%gad&x-0UPT;9XnC+)KW^>t^IXbNJc9H=6YK@|4^;Yf|Aki7V<$pE&p0Jm z^9rO1uN3BGYsUwtlJt3Wk^o^HN6F(nJec+#g1x zU#&FBcG6Eg_aJW0?=(}@mtubuBvGIM3;KPTeDhYZm7fr>>^)sur3grP_GTWlK{&%re3DsSzI&FG2o32 z>3c1o75;WnUMIIRuje`n_@dOkG|T5@*?^~^-_(0TjfJqwd#bTdo#jLE1=iUe0ymg7 zpSs*{IZy3NB2ag>Fo#nO=jqBF18wUsWKY-hw306r_%;Dj6YAACQE51>$Gj2J^8wlb z#5$8mf=$~@=#Xc7Iy`uDrRm3{H`ZO&A;e51%)&LzJ z(2ip%u(6m^f#R@kl5ccynb`kO$LHi2gMYGCBwO-ps|@XqmrTt}oXGq~y{%h*x5hv+ zCyj1i{|;%!d7Vi-@?LJ6<5O1S!hH-VYT5t`qWc*Ne5`#>jvtXLe$3gDxqOsYRoR}P z|7L*#mGF+qv5}fvBO27gAut06vsRds)bv1tYvo__TxxmE$y6WJW(iOebW-0EbSwTC z7_U&?TtFl}VFp0br{fsTEj6r~WE;UmLLfz(D!a)0T+FXb^gRg|;K3dkck1-9>#*p^ zY{3~z7D$4U-v$ld4{8|C}1hQ#L5znau-Z?1Nx}V|171(E2VX)AENB_lYL8LfNdi zKw-Ac^`0BTqx=TtvTvnA496u`t&YiGMcbUDi;rz*M!r&hJK*w+!&pe$#^TXaFsEA# zS^fS(Kgcg}6Fdq>P3l?hsyz=6;A172NMAbdRsu zuEYn>!r>aZFA1AHo#k}>)jL#Hj!31IDP56bZ^qXLKmsIQ_QV=t+AG+{LOCS7mJ4zfuzZ8M!LIzHj0t-`sX+H22svi z6mu=I>?v-n<)=$@2Qf#`^mN)2N%;Al|3`^D7d9%Bf+l?ztA^T@EBd!%;^}~Gtg)ph zK7E29rCVS$YdnI~aw%CU4L~RbTarZ1yI8}x!OmgC;89u&S40|wYm@-Q1A#oI+{K_n ztbrZ>cS{_x?!m$lszur}J3-Hzd|sonNkmMA7w72;!91~ceLd1W{JxNXjNNlVKgGo( zAy*3XvphQ0b0#U|GCxFhOi|tM)_1URf=btEQ~{CmOj`li(kqgTAApD59B?A>Nq@(3 z1=;9!!F}#v*pRmzP3rbK9p-53Hje)dp-$C<;mU$m6e=Pj;9Ecwm`IfUAE^BR;L=E`vRnpaY~{S1$uOZo|^pT9qvi zK&;^ip%0__LtALAN$860)KygVW*GfSo4i&e(g(npH`yL5`;PputxbPJIS#!LHgD79 ze2vDd(HBlaN^Y1*0fMJzJ`1x=ZP@7$f*XP55qalgS^1fpZcL|?eopnKi%JiLoC2Ww z;2RCQ3_e2PE}aOQl4cAO(c_3kxysV5$lecNOu5wG6k%4@lm8{(pa*2e8P(G@~ z9&njnl)^0D4xQ0!ZQS#{9WBm{QEfxXYR8VFKqnZqNEqoG5+2607Crw%r%u?>=zqc!Uvef7yCm_&AZAMY)fNeRF9afGf7%~E$$4rJkBE@) zcQ<2q8_s+zcQ;ZzZN&-PylFU0G+A=)$N0UT`g1ZMJFL+i69KRP1G>ZUl?}z~u8Gib zS2L#SI!SQYZ6i~#jD_8@=;~pZc3o8b3S%|JP!<{wfj~QourG4to2^4TgOY8q2f%wZ z`=l6Eka#RVWe{a*TJQmvhSMRYf=zm@>L2hE(g+mPDY)?M?-B z(trq>@8Nh2MDmmthD=VmR`oN#vg?&Rrct*I7|4FH_)))VqUCzRzW$MjLsfN)*g=I+ z`aG01Qdd_^=^FzxyW3D(Wg)$3kkzgfi!5uuci@D%sKEMnO7GT^t7TzDepj?fA&*}6 zE>vHB!(CW-EZNo7${IvG>2`l|0fttuMOx4<;EV<({dy$j;pze1N%02u3q5VIeh*CM zv3(t%aaLoINDEwDL6Lq_l3U;S&gjQ(?iKJsjTh*?K#1)-Hb*KhWwm#RUF7A^LAqE>Uq*-rT=(Im0QaMf!Gf-?HhBiERAV@ZM&vKI;a8+XDk3Gh&sT^y-zo4gn>7nuP0)HWMMq58$$;fr2QTPQVvH54T?AhQIWyP1WnlhB=;mb@feNJfv%x1QdCw=S81c%~K{#(%qvWt^yb378_ z`^KV<<4(;YcV1;&nj>VLyU}z^4P8Bs{_jf|!@~|6k^?F|WqZu{qR8?$1xzW7(+=3W z^;~0DMLmCI8~TKss3TXq*IdKu%`XDzy9KB|$ms%Uuz?>?8m|_R@bqIAODZNkMQdrc zf`WEHG#KZuDB}&>TWW>Dn3M z7?@$x{zUbJWkuF%yi*{HGgDhMn)pmCH4-b>$eTLf(*o#}pk3sd@o7`Z*R)|aDAYU3 z4d&wW$fS?5y@*WjhZ0!0`o<=)gcQAS;T9$yn&`ASuhitP8S)E$M9>EedXb8Hg-Hj; z{pV#HapH%bk-eRW|4_x1+Z~RQrc+TW$z5wYaN2nYLxTsl+$C=&WAH6Z+!GCwGTa{P z3CCHA>jpuLT%+s7B+FpCU`4d}v9Ng^MG)7=DZH)rlu}@*{s=xx@*N3;X3@F>UM(Ys zen@#feFoENzXNIk8q0->bC0KFoPVU*5FOXW8rJvQo@cp{C$LDt)F?X|sN)9%-kMJR%_l8v|a0ldC7`}{sy7*S}+-^(ck${tgP$L0$aGy*_$uF=}R#C4lvEFw(l+kcUn0*&(|wralSrtnR{Fmy*yX9=j_ z?*?;~ES*HzD=X!D;Q$qr)2(~Yy#zwosqO$$Q|P;2+xQvD9P?W{^g{;c@d`@C0{F53 zWVfGqG&WcZ!O>Gq=ZkC0vUWV-Y&Neu1@z|0yf@p3D7>t=Id`Wh->Y)ZEW}n51J~4b z(D@DQ5me=}46Im*;zg3SIyGO=Kt4%c5z#xVeiEmDYXvqiJUnrCcHW5BFXHG4S7#i= zMV0$xQzF%J?NHF2Pd0cvg+Zq@&bQ7FOJE~ z<$S{C@3GK#p>gBntS)TkBcUE(h zjH!B!Ep%bihsc~MW+f2C4|9!r`yY<41JieMYY-w`$bEtn@$k)73%2(A?_&&$OU#xj z-!XtloByem&t4?&xAap6=C;}!r$8&C=y!SgKS^%wb!$<(hlbiJW6yD&iV{+7uqDjF z6_c5hipR9Bs;9|TGC{s7t5LLF2IS`H(&^en5HI@`7Yq~Q?oi$l>kE@189sP!;&-%gp2vb*rjBHE_ zner+6e}$<}WUY`ksC08v2v^Aciw`71LSRwa_waN|J)PWsJ52h6$O2hVJ)WHe{0_kr z^+DndSbsZR%KEHXbvSf26Ibj_H7R&%f@jM2R%DuhgpW_^yL^*^bMa^@TZ3m)EcUJf zLh2$Y&}sg)sZbrS-C&V%_9r3!5S%NN#a_P|p4iMByQ&jmcvGOj&SAVRT&y=Hp&ajI!C;9MTi1Rm5VJRdfw+?3_Fe4elmn`23y0cx064LO^Exk;L< zjVDnRwAYwI>bd|UH}!xnmGAyYvj=`1k&Cu5=}>q1{Nm81C)QL89&c~j4bOqFL28eh z!X-Q_Q&`s?UZ2w{8D$mkKQI=$de-9Rl|Z%9g#VtydB_X8v=e&t=nmbephrn(d+3rK zHkRj9j64PvmaHnlyMv-FtcpFEWln2HQegJ^=(=LPhxnm6s3qwO)q7RnxlVg=PgCw1E>cvp5 zK8X@ZV!@)HZbV$p!pQz4`CeQdZY&bpuM>pmGMj*NB!fM;szglm*3c$+c7(OFzzj!P zw7_umxCK=^^<0FGs38Z&1fwl~>mSW}f&cmWkQ(6#?G5Gm0xnQtY+8Oce4!4TdVrrvhU}Bo`D+x5{%5lD|p%OVFz8dbc-)^mXWku z5Nth?1}sV}6U(T0Ud_iWih*8SZ~;!b{gl=I^6|X?A`FG4h4>2%BJbWaGfZvqgd3>T z2;j>tU~levCl@0T`g7L*SXT!GKlS#B(6y$#%PZ`$sFGKsWk{O#;4SH!zxr>R#R#;= ziYaRC8Kmj3FEoIyQp<3%Fq+r)eMXIp2oPS!0Z_ULSjlqIivk}cjAL-D3<5z=C~0@h zemDgfR$5|9cRpY@NZ44{wt$t>8(mHtOp1er03$tmESYqN1NTOg_Jj#Sy41+)A#=Q2 zCwEF_N7O%d)@ztL_ozsEp#p*eS+q=X{yRU(Bp&Op7_k|*)r?|D4S-|Ku3B9VVaYch z>w?3+%Ae|h{>?_&nzwMzb&hBtlzN)_`=6s~c%)_~G}5yNo-9Ea?W3||Y5p>YD?3o7 zAk0;bb$8jrH#qf){Vt@&N@}c#Lyo2h9BH>a+#vpPK*oy4)t4?~^-y23^UW4baahdj z$w0~Vi}wH?)(qfS+ZI9OJyj2xEXj_O^oZ=s4VWZa-SGLAZNN|8<~c2aJ2&lDKb%~mrX$n|tEYgY3NNzZ=7D{j;36J<9e{3?LDl z6#+B?<4Jb*!Q|%SXmh7_HS3{r1bU0#{@t`HYxP3ei3Lsb6LHN7l#BFvbt;0eXSp{} za5KoH?2{$>oMZ`_{RpXp4Pkj#f7kOc&dgw%jq&Q8@WPu)RK{ZHqusTKjuNWc30DnR z=#WzlZU`0dd4lz#Tn6ax66V%`AWlVbrB#@2!~vY`U9712jh6sB=&If&)kSq-$kgYY z(%?BW*VqkT);5AE9JhTMx;V&02-Q-INB0Ss|yt3xY&9kg12 zxPmwZgza{8lzZi2D)Tlj5ec%l&Lt*W4zFml@~EI~woX!FA2VvxA_L(xP@3qAgr(D^ z_5Xw^`GN+cSRxAY%e7#!lph(viPoFijkyp~Dc8Tm4wWAKK1Of<1Z=!w6yIweq{tr| zH#%sxm-KoE`c48||NN!r@C@8DGE4(6bf9irr+0TcuCN9dr|47&5Cxk}o_Hlck!FXl z){hI4GJR_e=M3Ys(V4qlRgW3%N`H0q4Db&v6~&sgA<~1<%m8hOs1k`viqfdu95qH; z-X-*l891n-h0QTmg`=YzZUf^Pvc58nB8DumRf@^UUq3%+1*~@M2Vy?G>{QSZh6=?4 zKoS1+mdv_jzyrDJhl8qQhGQ5=1a`YqJ|_QfG#x#Lz_tgRu75M9Y{vp35Nf3v`4<8< zm0~v$#{q5-XIK0dq{wfB9ivkmD#?MU{6$pPi;H&U$OFnK4##SUI7SklP5cUs zE3A6Wd@iz>lE%1?J^EQt2<1Lt99sB}?}Q@Ij0@cjh-PbwSZToOp=_`G*%BGu%NBU2 z>7f^~=z0%vyYuty?*q`mSmNg!YRyO?4R(0{A=^Nj<-b@51^f=aP5nKz33)6r6_O!r zX3+TuVv@qmp4?Y5*)_H_Or(R&2AqzaYFK-dds>{blGmaS^_e2<_uwvlui+r0QSe8m zAu?2~Dm&F-Ml8Rz? zE`u4vgj|X<=`f=(xx^2Ly9&VoRV{2bU0-Q5MWhSbFfA$yCDF0?6WE6blEZ;+QH8wM zkMc?TPqNKs$;SPrM`;n9JaztoQp;0}X*kBXrns3@EBHTjbK~bmARD%jX#$II7~Ww4 zA9KDM(^i8-O;fkO%G+=*fn81zUb7Z7Ii#bS7vsj^2417hd*_R-f_rz^&beGAT8Bfj zEmwinwJy^q$P`gj45?huEZqaNRwiWK*UANNfw&{V9gkE+?}EV@k5M*dD=B`Ry;zuY z3TO1#=ofhAZ^@lTD2qG0FitOj<%fD%<-4i)n`*@WMtt!Z*uvlkqMVSKM zy3*a_6#=_KLKF>j0Vdie7nr9jGhGaoNHEwTeuQI28?4=#KN-O^Tx$@rSix!GlZyO` z=ApifIaTA%r_CBuE+*@U`x?)h8?7;sg{!NWkt+5(TDO!vJrZKKJx%ODgNx;l?U;8fH%~2P@=vji>sXzg!CcaJh#F zkktu}!rijvTn%|xGd(J^tnj5rGUOqtSPlo|54nXDS?Av19BiywOl0^3fb3KAT@lR9 zzQ?>|2&#}UjB22!45-TZfy_lF{=Hf3)@uL}-iAJ=w@|7~k)?IX;SPM`Q*kd>FLJ~% zm9B>80{Q%9N#HYZfr=3(2-$E1&xRmxg6=eRwx`I;K&K z1DYKZC(giv#OL}!6z7D(^^>6b-Q5>k49SJcMwv#ey4R? zZ7PH~_eJW60ey1dh2HMiePF*T#8A)xGk5Myob<8h@*hdXRYAGV-zbXh|dZUw?eh# zDnnJA^&oiB)Vj>yWLNShKMC|!(-Dl1vW}|=Z6%4Tnj(wJa5_~qW7aW{9&2MV+-Tq| zy_6g1Ux?L`TbFQ8z;ys$WZ_DG6Pg0@S`BPSbAVSRU7Zm+&D&f(CCja4Z_h@tJf#LY zc28o7y^0pN?b`6bsXsrSRP8hHSw!2trSlxS^lyJ{CySB*flH9XDCWf)qr~vt+w&Em zejIRo@Q7BpmAJ1#d;Kyr;z1u@!zS&-iBsDDmqL_y{W@>N>ck%)S>G%f592(Y+AMWb zC9)z8%zVoqtW{AYnc$c;MV|rHJdD{YkyL+>ZvWL2zLq+ok1#>{#9zG}FbWrCusW5& zW}Y|on->4?x>W$f0soD8L}u&EFA?+szIm?>d%%~B%}2P+M;1RX*x-rf0g6U8K>7MS z)k5~9_fj_^$x;rkAtcRCKnS-&<7XuU@~h*__R7KJbzbR&E_Cf#B|(8>2DK~yB2=g@ z$neCmufuv71=7ks<335 zG4=z$AZxw!3yDxndh*|xq%~@6`^<+f*Q|_Sl1t+uk;=TchMH2w`QWFw2P;v0Gqk2T zu3-AvtawevpuX~l-qbY*?Or1a4Fjfcl`?`Omrl%LGFV>X9Gqf$s+Oe^@!(k_yP-g} zXhu)FwzlGnZn)rfxK_gLk{hd8RhRPM@f!s29vrkklZ88kwvCp;6d4-P@eED(Kc_Wo zM~d8P6P)z)MY;-@oAv=%#HKS+UUsF_9LZ?&uuMEyc4_|dV!5&C30l*AE9d5N`sWhv zI6}2qs0zT;DTsHFMz56nsZIIcj*&TqahFi}VW3|r`zAN_ciQ+I8{BMHsguP(zDgCj z?;q_(zowT%{4I_gI50c|E<%k46ndl)v@tjahjAY#B@Fz?+E`aReJIKgY>2Q9XZg*p z0M3aRFh=KSw_NKoMxCP%b~Cs(ZXtO_hn z<)(*8(w5>vgu1WZ1Z9eD8eiu9Nn7|VF2c$bl9gEJi-$0Xr7ZK8(oz;lKHEa(sa}Pl z9AUlF;rxU08d{A6T^=D=Rc6OQx8v?gCH|+0@_yg>>)*AJw5d93@Oi)xM>DJh;aFQPIIgR;TEJqwral* zNR2{~RYNEX0&nZ9$Wu&HbiJi)xk?l?4W)V12z$%oq=t+emkvVCJ$a|Id?&#Jx*f9* zat>c`bQ~*MdY_jT+&SXzRXH3NR5a?%mEAE3mD6{g^u?=)v2mJQc!@bUDA|*~u2}xX zz?A>c%20~*t;fg$Teju(q-uQ7qJI|E&b$P?4F#t{PvcPs7L`5bo%K8@ ztMz4W+pR;PNJ{9`g6_SNLJ7iA+847LIJuuBI74f%3FAvF*CzvRX{5T7a!$kvt37jIo2~@0(Muqz`;4xsf3f=x||x-=^=B1FduJY39Y^XKyzLZl-;`#d;hT_C5lziN2F_1n`5&A4mqj z=GSew1zp$aTsLm=$jkO0#;yY`zhZEE<_gSE9Kgoyw6ruu?wYFuvcYY2CRYfeU_I6BQuqyHISTs%0!+BIahT1%Fr%lT`;01V9E#z< zcu%vy9g8IW1y%A*dz9$b6QKj8TS6emPdH=Zf`lyni$szw{bea?@9s8f4 zRd%Xh`MLhBxt>bLMAiJJDSlJ%bdpy%sJ+*dv0(~+fyinv+0blkV5E^Bz>!jNsJ6Bj zVX#DR#q%IxyvEje7x^Z|gW$zHYAmx!r86(5U-5dU_zeYQ=(2)U?gY(dZ2q~C^|hJD z$2@g^^a*-T-j*|6*w*HbW5=>}BCrw~@Byl9S@#7|i>CAG@&+|w2X$3qfka5XPf{fC zd4qj{4-_DzTI?_Xf(@WzFioDGF29kP0A*9|jiIHN4ZB&f1{V0h98xe2iI%*8R!}1W z&tKcHtD&lQ4RA)Jb!d#Hgvqna150l9ps^vSIrkp0hZZPb>=+fl>yao;4Fg-^7a^#$ zMGA}tnx42{Glk^O)EwsEBFC9B>kj%LN!xj=0GOZVLTO_Nx;miK$iw zw(~h{c6Jf0atPQ`33D%DTb=4X&_BoyRbeD(x)l>KWXC_t92VFE5CM5PfkznMwA9iu#;T!l=eB93J{!P?KmN>4^F@vGgL=6zp!{Rk6D(eU zA(Cg)_Z2=*d^a*AuJO||YrhRHJbr~UJ~30L^WYL1Vh_}7GZ2&w?6&3705eT6=~YSs z+538w0WDcDlh4t(kcd#8RAi-_J^O)YVH1(0@q=qRz`4Y0`+*nXWm%~5jyZbr;HTc= zwKOz&4;Qj=Gs)HoiRn4v;xj|iLzjZL16W3(qy}t%Z<&*7utUaByD*&d4M+z**lw0} z#MSYT+}fAtG=tm9SfV*d67MK=*JEswX%0Y2`qhB`>cjZw}zD%@hj;4mDz zPkzD0Y(nL}Gll7r9Off)B{7pk2jT4=U*TA_>qxmtPi>VlfyAct^SbhK0iMXc|FQoJ;M!o7hq(9qXQ1ee0pp+%BFU5{;+kNa(vcms zVY}SG+zaboY*L(y9`DRf8fRQX2BRX7{vEAPdCH^JZ*D-wh03YyV^u&PwIITyDq_)} zV53pkLc1}^8aA(FLzDXf(dL#B=gfwv+$u+ZPKDW*284woT(4#jyQ++oTCrTD$Yd~R zXcved-jB|Lm%2p0jbS7A33RuTxp#?{HdQR<24|YeKzh+hHVOI)hOB<3fl5Oea=U^r z%uKY`12}+d@8Mj18#RYR=B4X!WqHC2^6bBI#$fnn%Yg)q4SK^FCu)e8Ul2-h*D0@N z7vY-LGeF@iE1J{w^D8SN1x*YO!e&g_qr>k7jZ6PsfWz6FxOiR`KmOv6YNrKBYH`(b zdJf{RU<5?s+W^Bj7SZJ!4Q3!lQ{;W`{V(JKh1Ey5A{zE9RQLK=_+{wuRMs-F9RD-b?Up-XMdD20H@-1Tik_nxg< z0ZDL?s;_u|&@M8U!s^`W-DOG;Y*E&N#!yy7ANR*(qTU_s2eyZIK^FAd!*76JpR=Fv zT(+4`8)CQ1>MjTfsVKecWnF?~QR+;s!PwN2JK3iR|9G)C6^y2OEaKUx=gpWa&;t0p zYopeLT!{{%qre8pTCvoW4`F{3<06w}{WOuZ9L=vf0YfVLpD1lnf821SgrQO1#$(9u z@(A2gQic^Yw8VPgJ@NbvPxEn2TnwBOOFz+^Pn|D#b~8TE$s|La6!&g9#%VW`OA%8o z{n|tuJxkWX#yYvoVwC+Z0?9fyV^2 zJTWr>#kSmL(*KN;kDGgjX208bG~<&f78fQi3zq&kJz6!J+|5A-<&Q&Sj1F4ijzMk; z?Z9Y_19~uRrMZi7^B9!rQB!(yPFLZ0fl%8n{R6;)>pjTZxbO|{+ijxJB;&v6mRe%{ z@Or*}?i1(@Ps9xadY}a)Jlc+(1ZY=C>XpZW+o3Lflw<~;0Um!sNv?>X9D~ruum8KH=q0>Du$Q4aO$SPt{3{VZ zhxNu{9Dv%bbY~fUn_@6%M#Y%u1l(?7cJvnr1+`5n@Ad9+F42!C0W|l*=dIrr{zPz^ z5IeZEtU)qSi`ivaD$WqrM_o|BcbzWUMQL|b?#jzi!PcpXgQMR_2jq0N%r3Y~{`G9T zT#npAO6Iemhb9@PTm(9kXt`rZ=H0Qaw?Z2wq`Y`ZD6EO&2@vVndr=;|# z4rN9)^V7<8AxIO8mp(|NGZPhr7MY8C{fk_g1R0hwMn*Aw!6j*Vhp)eGsujgruEFh^ zYnGdXyPDzah9$#ME6LNJm@Q)!jmf7ZS)JFuoG0 zs&0zA5ofC9PtL-dD?S~p?wW%hUP8FjJH;X&!8U&pOHrdc6~Ss-Q%)FhGU5_g1XRryvU?7Sw8*yh`md@=Mo+ z1!utqA6DUt0q&7HfOvR=e@X|$^;&lNK<3AieVCs7V=7aK^F;Jo?~dTZc+jQ(Kp!T4 zRKxA`xHH;+@#kLVY@b5~X|34TcTQ+s-rbhQdOK zDh)0_l+M~LmbW_yPSeJo4bWwfHHO76kb4Zy_^h@^bSgFeoyDtC?K_E+^q`i95aDLQ49j+NguZXWrar9i3;|0ynho3v4^_V;YAO#X< zLPm{+$o^s;1c(^l8B$_?!>K|B{m3_AqkQDQRLVvZd>5ggN_P3%T`4rPtZ0#@t@k~% zIpx!0QTTXDv9llD7;h94bF{F}vNt5qONH+4aoSn7V-BRr;(WuMRh~hGmT*L+zW@JZ zXi&ACTOonYOwUA+L<71MS!)i-E3jt(GtEsh5JTDb?W9zMLT%9uIbl>@E2^;Xi#R?D ziXO&w`fRwq1dn!lf_f2ZZsosKVMR$k8V^jE&~|^dnlBtw0AXLJePy;-mlbnOx>%I2 z-AofRROZ`G&Y*pv> zL{)>iAR#x5=5IxxVba}63(u($a>nk&a%!Q!4_?)^PfuQcYQMFMHKj}A7#Jo6XxoDf z*_9&&P)Sn#b0(PV9-IVuqdaOcI4L-jn^nIPyNk7DUJrE>-x!}KW^Xw71&unYEMlCv zbP~m|^NX^uFY|g-8wS+~r4FT+p?du5J{vXdH!GU3xsS=7%x0b`TI$|Y(IT9uIlCE} ziP^#=<;?=Lf2M?9<;zAkSad=q*LDIz5$(4ykA2XRELAfMZcj2n60&p9%Debcq~O{ zV8`ye=N=^P2&?oc`+nqW7$4oO2ZiMJDL+NAJl&)e|JY>7N$z&gFnm2@IvW|Be;rx# zom}7jC*Az5(t3G>Tk}kLYsk-~5Q200M3~OoA@9eHfC^XQ10w2lTwNa8zH@3;K$b0h zk&v}sBs)P2PA4K4pyA-U;7E4Bt6Oc$wDY$j=zjZ5NMR0L$avGGo6ZSc}IO8L; zkbEX0Vj2EHU)7w&<@&yEv09NMs&SRjJW?c+2*!*Zxm;g7c;TYkd0d+}Bf<%y*MKp! zbr?j(`f-&yH5YHIRHUl!A+@BJ9##g?c;PE%A?g>oh%!~IN&B(3QaOz=77Oe*TbF5R|am;Fz#Dom?5rh?|5QMSl%T$H}<3~P_n@e#;|M#<>@ssy2 zncjtu!~FIKnS;+l*lgJxYp)Iw$^ZcBX+bQM6hE(_CB8bi;9fsXd89x(4KJ>BO7`{M zdnH>(mk)wd3mssufHDV(>qE4xfzbL3GD@^C(Bs_+h)$beQd^4mwo-IbWSRI*EuT1+ z|7s6LynD+3@`E?Z_II%TC)dIZ@=_fF`fPKp^i65vqCW&lwKI!K8Lj4-6?%2@cBFu= z-%694aYHxK;UztdIZdY75k`iCPPBc~EQp~s7;MaAGTk;r-1UtEdEAHs?SRi@6**s` zgKDqN%q#Y^%Ri@+3_elzRwJ-%KARrt(vo=keX3@SPD{cd=HO>&(vh8M{g&Iob+G{8 zvLcboXFc&$)VM=%yFBcTF@TjXiG6Q)5N4O1>go>Tn%U%a9hIU!4?i+zOi%q( zUrw-7Ez%@fYC<)aZV5?zab_V62P644Y`n4z7Pa@o`(+&bZBPYn;h$E6OHF7iJj2NzkR!bDp`Cm&uNykPr$(O(iTtz5~YJJy!sN@*s3NNc!J&BJCke`g^dq zj`=2GcZI&#+9InDb8?Os*}=}=wDnO&hy4jB<46g>dfP298?U+C@Y?E+wcAmQP{S*V z#?(gc42;QHK0Wv(1Z3`Ld_NxsA^lyJrO~*B!5VhT7fHhRc7`&$d#2&}}Zln5&W0n+Mbw(mdLA(or!N&*0y7EZl(r^%t+*{Brkj3h0t z^dNmi2w~nMnu66J+?Rnv@c48{I&lf%la68h@Mle>fi8HL!jW!S&OkerL!WNtL4O+q zb7OVy*ycGQ^%w)VA}=-2rU|VrHNUoW+i1^Or4j)~_=&;UpaPy2wwNZ6>hdcyFC|3k z64orXY}Fewmwb2kC1h?doWU=9v4hvL<50aIY5W2qTXUS2Df@uyl;im8FgZ~rnN%|p zL^|E6OcbetmnHD1BH9*RB!cIlEHWWz8mf9_6FrjQjRn(W%!NHb-SpjpbaTBWb~Izw zc%)6@=-Hhg(~j1qj}CDQd9jc6+HeNmrNSo{ zqgcHC{SA-&ZA<}NS6Q#WI{b0>afv;dAub_JmXR4fQ5=(jfKWuZ-|z8ut)%)dNenGr zcMcv}{vN4Zw;U7k;FbcTK~hzd3;Zp{D(VlSQxjKwwn6_7TJm?AaApxvVT-CcRqQCa z@YUsfqn68R-aHG3DYs~B(t;8-v=8=b-L+VL1s}=diNDZlCM=AthV{4-#maco{MUn) zsmBG4yGPUEy~vcY$-$53uig8`-129E=bq+ooQD z>pT$U;Ha7H5sldF%U{ajgJyD>_}ECyBio@{Xqk;g5h$0SEBNZTW=^cffbGmKP6xK* z*!mC(eJc;WO6_iQ zW`6cM?il^rG6V|iia@1(@(j}rJG>`TC_6aAvm)44gZ6fS2fGGzE?q6^+C>gBBWgMa zGRp~jk(n0rh03monc=tBkM2u~uW9iC%wVg((uvm8ejxV*CAnA4)x9~6wvnS-dCoviT+x5F!x zcdrp-0Vz;sA}L(Dn^lYo5I-{O3`%kzms_7(TDC1nmOeZnVgXk;SSy)B!RH);Za`{L z7aDe}?T!9<=!PH-^>*sOMv%qpRy680k68?H?yzA+cV-YT&6(e+O0S1DO#0BA6FdRM zL9hUSji3YprAgT_RU{VVdr{4}C`YKm<}@rJH=qwudFL9)E4VnXOw?8NfHJ#Vt&D#3 ztxD3g{q3OCUJi?X;{n#e;{pK`-Az5H8FgJujbeE*+8BT%UT(e8n0K<^b$%ZCgv1Vk z;yUY;+ZPY59ttZLYk{szqXdzOI`92k4Vq@(7En+Eg6WS#m}NK z(j`d!*nrG8OoKhJ!BI*w1ue9XCH0$N9-GoBmxlu$p;kSIPK==rYL>|J=h8`)%$2%a z@+vcn2Ae{%7G`2!$DO>VhM1&NKSn;KwkTNm&h`FEc=)6J0wm~uU3I;#Atsj;;ey)& zfCO&=aLh^x=k(6wVP0VB-i|#>zag34(x3@JuANRNHPllE8u-mB{vDQx0PAeWhtJkE`O{yJzEs@zK(4OyF) zTpwI^36tbn zNe4PI?O7q0QJo99LT>V{7&@`D-NTz>lhtlJv)CMA1UX3rj`Z6MwU{f61ur1LAk~?f zxf*2)ZG>fkeCo?KiK>ip%Qlg#{(*>M@-5gF$EJzb$KrO|_IFCky>=v|85*0#S^o=p z6vCi#L)s8f+Rt`VWl7c=sBh~t?$=%bHvik)unIEqz7;y83%EC1>SJee^^Pt|nh&HW z_%u2f(hC&;Nb=NQwk>EXn4AVka(5Bx-?c+oWcH z$j2;6a)NoOt){jvdh13%^#@~>AcXKrGFv_p%UqncmpQ?D_UT5tMtfNI*Pqencfg&+ zB=$FtUCU95b}m35&hGu`zOR9#{36tOKwX$dLOvyRK%|iS!@I&~RZ6JGd`RhSQ4`iL zwtXPr0%HU1%ZWhUi~j1^1p-QDy3)$bqyec?Z|&)*5ZkOnN!26E1I6M~wlvIX#@t`& z-$qWXp}{1YI0vub5B(qf1uEvv9}o{o#qP*ElpqSD&jFciFDi+1qV}@uF<7(c6y-Cm zqv~8w$D=lW{}nRZH|U(FAUk>_`8gAEf=EiC%c?MAq@)T))vTTJa<5TZcujxNTl|%T zEf?H*d-$psg}BB|D=k3xqFxZz7a0;(qmh45(i&N+U3kOPLv%{)H^PGR{Wdx5PgY&2 z2_RK{cSLuSgc(jmzRkR4_xqL}vyxT_w&I-0sd(pmevhnd9p$K-ulmubCRN+POG%$D zLszZ_zkv8E!TtsNTROZ()*Js(1j#uXWaSR+l2jdK*8jWYG#Ab`F&N1Atml`(}^SvdI04ZVkIMih>(;1Xqw?#aU*QWwF!j0FsSNSSTZ)qDFpBHwzdOJ;}s_Z=+a=13f%~mB0@c%pt3&iZ%y#6))7Y!di-ACzxFND5PB4-{DDWg(V)CY1~goO zbh zDgO}fOG7YB=1B^nCQo0k>}tnfSVp}qO~Xfu#TL00GPjbRgsMEE-0q;=0GW;w)Spb$ z@(gw^aCYX#!c}ct0CibEtLIol&5J@9n9|?o23~2$jLgJANzy2@ZM5m(e9j8ZNLUxz z!Y3>NY-z$&)K<(}RnVPOhAsIP#FHM6`(Mpei*e18QMtU_RF5+Il*irtbZLLq$MU-K z^L_ZT>2qD5TWK|SMs-qp9 zbXwB?tKAcmArCJ(4|nvX?o&-JRI;vh#pzqeJ59zJVJuK0U7i-5q5$VhRY(|AyM1K9 zD$90gz#6V~+M|R?2kGl5oCj#OW4#r<9b9^!3DQR1m|piNW7^ty>QcOZ7>>+HQhAZT ze<%uT%_Qw2T)4ToT9evcP{Orq)xIXFouW>f2WzL#JZd92nj&A9Ps3J17mN!A)hb|% zI1*a3)5jL?dol$qoB=}$}eU&YM2hcY@VkWVW%jUsxjR%czW3R?Q^$w3E{}1wSWS`igLh0!6Dtle`Ns_X zNkvG!;bu<^Pbek0tcGa-J@+-{0ScYwrIRtbbNKT)q+XWXG0N(13{!H={- zL&z0mS*k#|&TKCUGtH3^PBWjV*M=WB%ncwKss$xa`=~jCAZy_cv?r1I*#bT96$YlY z4k({WlvLlvXbnP>b=xF*09_P4S|Zo`_Ys^wT&){F^u0@#p}v&(=>EVGEt__bIu`*R znpY8+eY){E0+#gF@-B#;=v&0Wg``L=HqTEe{&z6i@0ndoeRvL$fk z@gb>H^dOXRs3*s)TQi@rqt1my(x}_+ra}4}xdf_)6aAQOXy8Q2jEPH8qnvzz_@BXs zt&&;Fvy(w6_((76;J+6+uO7x3LkHiEqGhtChJN+s1nL_uBja}t)u;#rWp_@l2_*Z2 zBkW~FGt-Z-r?*4vZv}5Ywww5_Q#e`+-|-T@gJBvgsFr3_3ow>yF!4oo&RQ0Z1ip9o z0C>4vLtV9tQ`RDcE%{VYpS(&FAo`L3oY_-`y4oV|xh|pEd*w}iiM_)C_tGKxZ+c4` z2=IV5bQ?H(j#EP575p?o_MrFHqXtyYAOLLS!HK2DXA5`IgB- zKV@xnxv5JJPE(5}Q2nLNGy~AXOhCn&*^_Fi`tvRRl!ugUqoSn-zbFgVfdA(s;O&F} z^O+Eo2C>+m=jBdELeI-Dl_mjtkU{z7LsbZrmBjen`$u}ry?$YgOjVXC{C)a6tKtsB z5;|fCO8{rfj&Pk8;*{w|6KRqrV(J-ZXFOpAcO|HTZiFAwO%A#iIKpx}9H1KgeW#o) zKPn>c^rF)okJO?le|!%WBt#3FmCLf7vKJmMKnkV3O62Hsftw|GRP`dW*-_?dVgGi1 zR1sQwOm5TpJPMXA9+UnNqE%ovq<2bTFc8Hp9jXwq|Fy7Ii+pI&(mAOzrOG2{FZ%rH zm79CES_7)>^B)+pkrZ$1hU6XyqaGZ^Lz3juZOO(&kV|&EA1ROCZAzg`pw&*(Y)HgJ6So`Tbf-}-)Q zr6gVRbLr-+briails-u%ZqrV{1cmp!bVrkqsWF@WiryjV3@IU7h=>RoMjr<)wfIlFgYZmEv@fYc3}R9y`wz zh>03HNRkJjAqq&WCEWOW97X>Bl}@>K;?VuK5IlH>+%4GbEnWjm_H;T&HV`xrg}vwu zP!<^P0)Bi}@(_Se{g6E4MKOkQC7|m}tuY*V#nUjM3*UMUKa`bpc>F5>c zxv_k(cm(Cy}NTo2;ai~;|46b;_*B=UuFqaya zj{R#r%FeoKEzPl5%fg8bQ)-!1z(!BBR-abg)M-iID(adf2L9WL&^l8f{ z7V_Hmy~iu6(nVi}OM!3MA)lL=;2yPN{&Q_(uX5u(!P@9Ur^_Dzx|Iy{VWjaXUa}EK zbZ`RyXcI^Dgaa&AT-eZm&yNY2{7j%VDY6M)&^!p8G2K+Q!+cLbMCmbN>ev3D)J5u?e0OCan- z6UC1MR=4}Z)pPExbaYY4<3i-bt6a7rVD#xE75+-?^(+=dAjWePDJX4#`}gUJSgJ;l z#rF7F>fPM68#c8QM{RK*=a*;%0gr0wj;9@-`*#^OqrQ>?2B)!44w!n~su0 zkL55eMncJj#GGWZadbN0Nm142q)LlcEo&0)$K=W!>LR<{rd!=YbTMv_4PK3D5Wb-L zkj5&Ng7Ko5g<(S4Ni!ctVA%V3WXifSwJs?_;B^107dTW`kmV3`Ci1K{mc&|edOn#& zS-haq(^41dfYoxd)@=CMZC~n4=TX|MGD*Y3%O^f1OCi1lmUfWSD0ToP-6x(`+o6Vk zTV|u*+jX?`&uL|cex@+nwz{`0X!axu(U7sfd$>*~Va+Rrr$J-A?OUT+o(*Z>X}N|< zO5cn6dEsSX3PSjPQk0H>lJUkLYozn_@Y&=GJ4m%8qv0Ww7a! zRDNf8m}~0xX&rYD++1_Jc&nWrueUD)qv2d`o-mw$y1n2dVGc#VX3lkY{tkO z_A_mZOhq^5_inm1?&xZ!$K)uKg2j5hCb$b%T{y?PxRp55P7U&Rku(?KuaIF1YRmWh z&mOjhBzUYK9^)xLZ>ZLI+9kO;LFsd0#Z4kQDJXKnBW9)9Bjy`7mD0G4@h)^=^9}sMFl-q$n{u zoiS#6jagaV^jOq_9t|g(a!=x??{JU2%J~6W@>LEGnYASUC1_f$H>GJTYe$t9`35c_ zRkQ3ttZlugSP$!&hMx4%7&wDG!2xU*Vk3{s2k`3k{2xS=Z&I@mt0yM>GpPC?xg>9P zL9v!lnoe6^?4LmxH49;RmfOd#nVXA3`$S}C2_C2);y=xHX90b9d~?dVO$rD}$r#-}_F9#6 zw4`0XD~AO<00jO;FZ~=|V*oUt8$tze|1g27*JpM1Fb=6#Vy#c5mT&$Cj;Rhb zAAZ_iD8dKS*QVAw2uKuI{JEm}?3o5^VhiD!ALv!NA41FbD0UJx>Pc?nZYvF{t&7;Y0vp zBsyMgs+_b_0XCZ`Jk|OzQXy7c9D(x$g5 zbdM=u3q-4zf{Mn6d7x#r7TdYZgwP8vAyWPvQy{C$y-GKJmjrTJm$bHbiBizv0>LDV@+r#w172f{s>)i;arc=e)k4BQsKyMDF+K?Tr2K&> zOD1sKM+;Bq!nv~-3yzOYEx4C@Rq{FM9pgojH5eT{1I=|0a;czq-v4RLrnt=SP5x46 zX}9dLw3AHTCOJI0v2QJJx{aphgMmt%lo_Zqku9(Ip^Y6ZUI~1C6&HS#&}E%n>$uh(e$8Rd_IqA-S@dp5CrhLTl4mfc_Oh<{&q0J&q`u z+_C_jx>nC)lO&dRkKIpmJ(=mS=}L#E6KdWBfWDH!bQ%!vpppq^ml1ig$J&&`5a*MQ zB4P34@+$+JBiOKNuqlb^{CXM0R-BC3C*z$HtxnJjlR`X%3US683hd+ZZ990vb&=-% z6!Ya#GM==?!pgG^cpv3o)3ZQbbiC>V03;h%5>IRt}{QN4AYIwA0tD52B?lSsDGkj zSKYWRs?GrfF0OJZNp?caiXg@k5Pm)Gi4N!vCJ*(w?uq+S!5}BQU=x9aE*rBins;&* zo<_S^F3^EU{|wNKOq=L%{Slg1o{qN&^_ySJmCT-_YB{IvC&kS7`^AFRQ)oA&;Ki|@ z=9W&JiD^W?Vl+Uwp`Fi4rPi3TAXj_MS5tW}woUY)Bm%>DBet4BQi8B2(uQ7txO924 z76B3xX46vjdK&<-(@N-k3-+as|JiM6J`!;5Xb}87y}0w=mQVps*AKsA()sL0L9atN z=>H0chRCYi6uFB9Sh0i0 zO`5{;OTff`XV+R}2qX98GXwiTiN(bkPAQ@uvlM11Z^WVm6euHbB@Sdtmg>FhlPUJp z!BlQ=W}BlA8UpKZ2m^UJSeM>yQF^TDwtgK0rgPHoJ*X4l1&owuJZdKT49-E&g z$e@PJ$kD+Fu(n)}bBAx=pI}4;zMIJaRPYW3c@IPF2%!@0PR5?}`Bg<4OruFQ%gzhZ zQ9;8BaUsA#oW(fVQ+OL%K&x=`q;Q@b?TMLK?tJswe;Kjzuo2q_%- zDN?HgMR0$r7*7*}qv-B8q=X#X5!0ZM?*M;>rJ{)EwAE|0w;fcFM_8-0zJkkjuBygR zEvE6f6N|^$d47<@;NLv{431iX&-V~2IIv0eXbGFHk(L`0LOP4qK^P|q557uTmBYxx zaOaFT?5t{^UQZG_DPfK(6DB`>z3>Se@t^Eq(U?ra37;^*STexyYdF@uQx-HF+JOx3 zKmN?twLr0nwe;s4(wX>O5}p3HZoZ7Ff}?DxGwE4sIE3l3He4G_-ei&(?DD^H!pkk9fn`O}5tzet940u;L!bSKZzJ{GJE1O9nUCu^DSPfRznscXzhwnY#BCZHE;c~2+ql<6{H zw$^in2z0Xst9o!8_7>EKh@J|Uh=ckuTq6TWoa#JCTa!`izBUkUWwO+o#-h3PV`2(8REGRzkvrRHdS!9f`2J0{m@f{j8*ZhR6w zG-jpc9SO6h^%7q^m$)v zeYhi*!Yp)MFsye^4R8${=Zj)j3RVk#&6DCS(c>`!RZq(v<$B-oFq1iF$rZfnz*Rj> zDJMEi_|-^HeZ!Ie`UOEt!zJ85E#vrJaweOHImkxU31aR%)H1ny2W}ol!*_BW8gtB! ze_ybNX>m`;xjT9@_@V?kI{;(IkPQmeXn~}jaHwylh!6|D9ak*#k+8Jv){|Yuht_=U z@PYobeE`A)Z#l2f_RQ89b>^TjoSbzcJmd!I`&Bm$$}vBO^4T5*-~?;dk_SLBauto^ zeQNRX!&@k6OC9_kwVjpo5d^yMt}BHyo_L5un}y}s`cZ2>WcRwVV)#e3Qhkv_l;@3t zK}3~_4T%-3h9i#&Kjn8--`1K5kwc7Rm{ODduEsMMy0oa!(c}u9*Q#b4-Mzr6FFYys z^!*%#{qVPjFr@84SMu=*jxLRK3JOaM+#5=^FMn)9MW>P}0o=DZNuhRT`$4l@Nl{pFy~MY0G4MiSz?~wf>vFry|H=yehSCd@k=nB z_tnyH*GI$EDV)Xrhqvi2vI&1z7LjJ*im33Ytt1+Q!h0u2SQ}_f66urBSJ?^<>c~`U z8&Pp<%n_?z)s6Cd>_`kY-FaP;2Jn4frOQmg68YWh_}DvdG$-yV>kica>_GGWho_n@ z;iX!z!&u#c@%W-(RuaHSVa1pex5Blyt6ja&MvKf%9hhl{+nA53DIfkT{vq*w#= zkI@M-2TCfa_1#r#DWd_&8X?@U8S!?%Fp|%%MOkZI@8D5kg0{_2Jq7+}r~YGd@e|O{ zMNLWmUGA*;)$-bE4y#XaLuPZUe{B@jIb{<@+Vip<3uvM}Y7mK*UIRCsQAY_j!II0+ z!-MqsL&IJ?&16-mYX3ZnlFD_Y5z9>UsA!sZ#SIkD(I;>K3NE^#OCn(6L)G-&Eo3QC zew+p0si*Hn^wJ|i@Pz+gJ*BI+Xh^FHrH=E*6t+*hE>Y91Vfk~wc@u#rJ_NucI9Z*Z zhBGk+#EK~OQYv}^GhEZ0U>1&uN;23vx8VMP<;R@OkgB|gA`lSe0MF`&qwD*+)irUz zeJx3+V`CA(NPXwg@TMB;w(Q@uY}(uOa|{Z?=5ka{94N)BtMa#+eqI-`oJ8ahxLopm zfYvfa0mphR1+^chj?qXcL9kEXxwxEV3v#?q1&~Ykp3y)$yaTO8<#eg-PdD2WJbJlz z_miSSooUE?lgF#+OO%zzB-v*DjQL{fup!8hokgJw^Pwt!Yn2MxbiH2Ab@66>mI{09 zr+b?3~}U^BCOJ_HjI zMCX$k2nj&V602sEmurNB9aPJD7*{1;Da$RQ-boc~dKNYRPMQ3at&Jkzt{#RoUcaYWX7& zg8L&nRrBGRA-7c}IXMFm?}7UFhsk7vfcQx6t=Ta@d>HI){qI+C0xuE@+Bwbqjl5w0 z+{V1sgK)w;)5*phA`7yoGBmgVR~jh5Q!p=Q%JXi6fEid^q*S-|EN(5La81>EH{kQ+ z_ecG-Hsomh3}UDzL_YSQrq2UNe17Uu^aEvwdAcCV7I$)V4K}XKBr$Gj5jj~Z`oqrmCO+Bh)+W8+8Uv^Ux-wQ?axRgl}fzS zP;IRSnGSaTw`#af?k1a>-4Gn#T8@emzVf+oA$?Kgq2Z+*4Sn!*M?ri2eMs{u z_5rMLC$H(X&{@h05>+#nVI^i`KF`k{@+~bRhc5TOhm1|piDZCh#LP~U(yYJI8)?pl z3abIjTzhV5#={#&74kv>^M7N#%~}?AkM4m)3Wlcb-?1iPRr<|w7B?vRF$`J5+GHU1 z--#U0mZ}~~%~6ymeXDEBLFm{L)!F~&wU%O;ZiZrGU|RUGQ*y~`S5;v~;(0;2z<$5} zq zkSCa9eUC4UJ;gNG1!o$@SM@!Kc8)lE41o0!kA@nq@jyihcYFJxlg&1oY22Q3(Hl`) zNeG7BSxfT>3Avvgga@l>>?-KmL_pD4>o3^^L3dfnN*HnV;Q&wpQrd;ukncfOwUQoX zIdWQ+r=9P3fcMlH$3j9G5Py=>9L2$dt^?w^0+@L2E9L)y{RZjH2a~kI9*xBv6S~r? zVN2j|1sFwjjj{g;s*%|VE*!2(JHtUfJDAa-(nm;#}3))eD=sQHMB$z z6|zG_F91ZOdjvGIrI^vB|2iEaY-SFN8HNhV`81c7!i@U;h}s)434EmA3*%)uC-PVN zWM#5*BBG(u)zx}@nMhxonv$nW!1)*s1!JlfbC$(*`9=<(JHAkvmhnjhIJ7Hn$2ZSO zO~2Qr5V>=-Lm)Efp={djMQ3r9&%?hz&GoOB5}y8lwOXsTo(^HLOG)^R?skq6^8>ga zYns?ecj4k4=a3+(jX*#TzDP=3DeO2^q?7`VGZseB&G5y~yY(Usp=8q`ahMC*%mv4y z3e^CXj;-qm8gaIUTAl{wM^qQAV_S0|lsLq$Z^BIcXJh3tZAx#Mtz@HccS@39=vxw-8nNYVPOn!+p8k89JLb4o zT8iP_Svx9Re^AK3H4DfB6m#g^1`4D3WR?jtDuUFPxtb#ZxD=sc8R&xz=2lO%DW>)h-tZX^xLd4+ zWYOPT0#;(KO>shtDfHHb?tLpD>}mc&t<7u~^LC#7g-aWSqcTe*NdVO6-0~gqDg$iT z)|?ERx0Z%4>je-I!`a{+$1!DcZ?hz zp^W=YG1<=33dV0!IAmRKr=jK{MupNC%BaV$Rv8wj>qyPMW#D$1YK&5%>VNvT3?%aL zZ0q4)t+30`bAJb8r!W04a%OFE55U<2pFvI%T)E70nkxT*ViGXq z>%C>B@sU-?&UOiKw9-@pg~P!k-}V7S$D3e`Bwn#9)+av1*?CnA-*v*wC-CjFQ(WDH znP?|z%U<8VIq!;$_~Gic-AikauAclDWW0DyB*YIG#@`z;X$gpwjXj>1>-D0;Y(jXWY##5vir$dd!#(kttqkC7hi#REABe#hRmB>+|@Ut_ay(=hY$t;bs$=_Y4eq0Kue& zA&TQ7gO?whHyY)|Z)T5{xbCFyBgn_>FZ8s{tO)=EeLHo3t~9ba2BJ%#<}U*VwU4QAwpF*#qwp0!&5`F{923iR;zAnAs2 zUcRKLKU7mkZ$+ls-vtrpPNb?_l8K-C+Z%7hcr~?^CH*yjAGIjUd>(h&)EAY64RW3Y zlz(Tll*5xf!_*s~;|BEXBKSpa_zQ^g9?KQ3HYxd~1a;oE0(flT*cw+X!v&I_H-^E> zFxYkq;a}J6zcddxrOOMRXo!xp7zjIc77hcNU(;Sia^|abil7_z0pBn{#KTUbW#8L2 zPyIUPQ&NPov`9u6Tt-eKJFSsgt4X2C9a?eh>ju~>TarZdA=~iMC#~q zhL3Hi68c)FTsK+LnL{T~cFwoyLEmm!Jo6prCboDKfg~B@vqQjbHA-*fR{mI3Wjh5> z?h1#HB-DqK$emxhHDo1m#;`73*4>8RIf0Pkj~-EXQeVWrEZe>Z7--UBlK|6B+HN1f zI&=}K4b|nt=*Hp!FX75WSzcAo7`hnXz3;EjB*MTeTo}e<&gf#z)9sTiBFw*mU}$hV zHvr~TRQld0>}e=EtF`3E^`~Pcb1c56srcRg^s4}hi*UDGa2WC8(rY=tx1h!P z`0Q0t*gx`w;uPWwlyk4)zOGVC{Ol8|10hg!11+?{8;M_J$PQr~FGq+%qy=!1$@S&& zMltQQECzBvo+3mu2)#Pm9y>F;Kk^;KUX5ZO6>Q|_q4laZ7$FeMgDuxmg0Vcc5U?I7 zfW)(oN-7;*2Qbp7Y^KB-N+yxj1vjrcY5htWE1?` zD~W>UL1YyC`aP-rnCD_3<;e3~EDNXpiBGBnr}j}xLg*|yVqEY)Qr|Zref4&llpJ9& z`ur%Fsx2LnPd8iw_|bF*xCzqqI+aZw4t6VgD2vQ}ndTCh$g6nZbliJmXq9yEq)d|6S` zrqWN0RZNX0CQ`MXk@iXz14QUKRLxDx1b(oewB6Zp?2`Md+!ImS)&~_Hr)SQu%+?er zR}XBGKbTTH!hBMkONc9kfmzIKxEn;7Adqk;B&b*Q-yoYgz7usdBr>h7HUuDm1gJ2) zlud|6DihZ2j=>p$&!kqP!>jQOo+Z|Eu}x`9v&ZW0yZLZz zo}6xbL($bA0n0W%QopS4DoJtRw7_xQLh{RNXLcbi-M;%?tyq5p8&=!Vy6v)yupfq< z6=a8_G_TlXxRwQSyFr^N3N6XRt;KAzV-*jrReTyJzCK=ZIg>&l+yBt-R-%ZFcEnjB z0;xoE!V|{CO(xGE(2>+qaZniX2 z|Myd`xJ}E=c$v^>&*?zJ@r3Zk@rkSvf&dj!>2*zOR3o zfm1>Mt_u>u=zE5kiL8#n6hCIsf9ilEl)Bh>mx}~9tCT&_%Thgo?m0qN1QlA_#b1C9 z6WrR7`jBj%h2A`Kd`jj_e^rW6KcvL?a%0i18iD;{n=|{MFL*tnGmc|v)I+P}HDu~= ztx=2|f7g`4@z^Zuk~VlU$e##{HZm^Hi59nL?0d1sBrt&7%mFRbC~>fmE4Q?R=2x&K zE6;VpRwtei;NmJ!#u)M`Znh0p5unu$d*=6?S#iUbIyrK0V=+<14JJ2qmo8_k1U*tn zSZp;`n=2~r;42s0` z`gk)7I$bg#ox<2eL1;J?Y!Fzto)853@6{DrfLDJ;kJK*Kx_GzFjXA;a z`qyfN1s*NIRLH{oN#_OpxxTtG6$$hVd}M`N*-$LQyi_Q;m^UBTD)f~qq+;J`>Bbv& ztcOjL?8gAI{$&g~tgH4kRf#c=Wxk5%=>~6ttIE)!mkp-C54U8DcVWnHSi6(P4ceNg zMlf!ZnOAB~GqJeuGgOfM0((@G8G!xx`KO;XEktm@Yv@89l@=3(bnB8v`^%0jV$!Vm z;4`_Fcf0z5{4S>(|MS)e(iq${Y1W|TyFlRE2RbPl*Ur%A-NdS)H4~w`LDoW#-cbg< zK|qH!45_+DV0scFJ*%qwpgyL!!(oWDboFUqJct$0WZtMxm2_3vfBS|NmpT#t98KlZ z11nIi=ILYdpc;ckbxX2>Vi)dF02T@j33_>ZiurKe5dLv6`qkdm1ARIe(x^6eNe5Fr zN8ngntE~M>VGlW4fPFwHiBlU58S&zKU^J9aE40!;q`BjTV6Qi3*<>6f5W%cq!zL_2 zXSnE`n!H|o+J=O$K9h4LZ~`J&_vZUTiOa~&6Q_~mx4cGI`1TxEz*V|=OaA9@6qnLg zU=mg5#suFCNZR%qfNNFf7g;EIYE&L%z93DeT}=~Nhbo&^1%2BUgWkrc#z!I>f-f;! zjRacjhe`dFP{;G%G$C|3Vk}_h`#gQY-ZuSP=)zMuulbC|{`sP2Gg zt*bKnA1#t|d*|J8lU`yPb;nlrY6XT#okddjAkTX@%7-aXc^5g?mBgC9cP~{rtV6(@ zUd9cpLTjdqJE;dzILKX;Qf#mVu#(Zmd+pB%1VL6n(nQRo`pP2AcmmPk#W$aeXX}Mr z9&|7QJAru!3D2HFOLe=MEdbP56sO6;-i9N z`1+L=AZW+8Y4nSp#pOoEK|dRoF03VSc$MO)oYOYwTu`dqmpnTes>8Ok z_T{k)LF5(Wo>%J_zw{Y;R}F$@>0o(BrCl!%7HrbbHu5m|b~j|2^T9nqEP;-CGPM?@ z5&dl(-S2YFpP~H{$h7Rxd8RDy_L0h8A9FMGX{JS+UopEDBpPSZ71x}qz!+Z>Ruee+(K6;J*ypeAIL!LvH3xsKz}vlEBmjugKp)q0-<{o;IUyD66MWwP) zjsI{y6t-vI`r`hpiR|?SZ8`cUHn5{SRjl{sB7t>35MgYF1k42)dlxFU_=x1Jut=)m zAg-E_4|=vQ>FLDHb@Rw%*4Amp)#Hk_CG%%x%0!%X3~}dPL(GeL=WBwJb_2 z?fl*hFf^@gLNHGWuh8BYx0OBD^ZcBBm!YHvt5f4QEG{HZr8fZVj{(Ne^T^v!`-X;( zckENp{cj(^fy#FQ)(mNjHH3aF*t`8%GOAbbYyBCUHJkQA%^n={_m=x%{}L%im?!~2 zd+{PGLl85xQ;(hrQx)x`RpLoM%P3(3pE07XXFnxK@h?bH5me*vCYlW9M6jg5YwfKBBuY|oluptX z?vRi4)%6=i^B8itEQmfc2MT_$O@4@6VI)@%bzikA0kO~ zK!K%Ab%1_AR6MfIC{!=*@ondAvzEBs(EKM7I`WzY=3JsgzwxMu+$lLLZo4zYV%Dgw zm%SbAlslV%?ns5mRCQ+2AH7mv)VHOVp-8($BXmfDoA2nN*Q7IXWj8Wt5!2U2?_qVE zJ>Wh0%U4$i(PA(ur=R|Fw_G=u;M*7&kDviB#^8(hP!eJ$>RI{Q9(AxWmhQ}R_dF!4 zU7@|03^05o8h`xwWFQ|;e1MuNt(tCA%*~;dwueju0Lc!}t2ysLlL~Dkt1~^69SR}C z;AAOcSuh2iT5*}Q7uQn1fpr)tVs<_1 zE}pv1j%j^;2sM0j-!sjQ=ROcC5eYmsd-xcu2-vwmxe9b8_urU)d6 zj^fh@Rnp+J(?>dhUxbKlm6NWbJbj0b`^1<4!o`ky6uG?JSJZ!4_HmEw0}gr zdceA_yk2?F6@>AG=JqH>_k!H$AOj{1tH-D6y{T9qN3)Y$axT;)nNmFUy0QJ~hhsg} zq63Ojt;82CsloHUm8o| zVEkkjk5c;#OrlZqpg>vCLILy_g|y9HbP>{IajWuJHN5k?`v=z#d$IgVT9G zZh8I4HQRqSDFz0Ndw8G|JJ8DFoSE%TVdnMRH7BdD=l%TNO{RfWdGyeORk%3N7A`xsijrXq*Fcx)MI6hCMxF%=&n`E_VBss_K z#m*t?n&z*qj=te49FKOgLo7J3N)8jEZ>2{hOu%VrrcFnh4o0=2@v0`7h!LCUR0gw- zLS-R&L8QS0P+NJAc&h(rjuf7*0&wV8tiq7rVK$R_KtY2j01%r&0!V6AH+LT6t4kOg zO#J)6Z&n2^z@0f1fEV{ex(DZZ>6be@$8TBO-2H;lTp4!tMEq*nf_J3brfC$#jq@Z+ z+&5Vq`Tppyw_BggH3iK^UXWY9pMX^8pq7Q2SeN7rFiQJ;2Is)UbwDsTs_-U&22YHX z7I4_90>&(0*LU8Ok1E2+`7Um!ncBLU_7mIouD%>9o$k|tKKG@CS%2LG8d50D0u{E} zt(^J9oz`BPr}8+#FI|8P)jX9gcrTdPL+zdAWf85D5CckZj|pw8ystNYZBEH?`v=-N zM^&Pb&g_%+=G+{FmLWM`d^lVj>0ob?bsC94^=#o;`uYHLmLCT{U3gaq5jpvJ;Xh!6K z9k|7m_->00ne5%t9FZj^e!S?KJL{@>Rc1|<@#5I?pUG@N=Ii9+Rbf#IuNY#CjIB@? z^~AdOFd+;ynh$Zj7VJ?{5AofKDCWI2oA>4X+Kv~{J6-( zXZ_$h=#4)5oIiVvGlD43SJtzSU^*Eysoxd_NZ@`=@NkUbcBmCK>^5P33d=bk+B>o5 zuAz-oaJ{DtlLOrs%|daBEXf#p)bRX!>^ zI#0B&IajzqnR!;L{E)$eg>*dOoFa{^2xSTG8>rLVvLo)_YyE6T|$hr`cKz9I-Or8^q|r zoccA@98-I8)CWMGYW7M0srj&LVcoBuF*I%^rNv7!bk5WL23Ly)ErlclKKF59L4iNe zUmjPB7>nz9-P}3r?ou-o1%k&7E+hXw+l3QbINX#(@X%8Ae%&P*fj`mM;6q+(uJk-a zq-LV+tO-04z{MN)dO2JtAj7l3WL|9JcN&KJXg8*_nD4Mt+EI?U-Re&J1b}47(+KQJ zTZcOCMZ;IzI9UZv^JCH&VZENmVtrqd`JW9z*h}tKC$4pG&5d7njd^a?Q#!W_p=q(| zyZ2d!CO%NQ<2OCnqPn0fdM&zzO6q%^1K_0=va15ql)(z=!+m;%zFDobH*{C;A>COz z7&Yn#jUpWNPbPeuE4%B;NDWa)uffi%Je;=~#{G>h zF0rrr7&5x1<0txHBXjq0RBLX_df;(Z(?VYld%Kw5zq1P;@RZWEo_S`%p9ko8iS?h&`*p&8t6nm3y>9jFYT;5DQdv(w}P4)u5Fw5-=87dKGQ7Wjtfk_l0t*G%Dgv-UxUYz((vY) z8`6+%SKYS7L*iPXNPEiPWq$oNRW7iXc+7Q{*JfbENO1sH0v0w!@%t4+@z=NG$S32r!Qv|iQ{V0w5!L*mzoZx_IZT1}wzsR* za=8DHMg0MKziy}8)w$|(v`1LGUk~GAdpTG2n&~3e8WagSau+TOrE#)7Da+mbuj1-^ zwUv_O1qN8w7~nQbIuQ^cr7>6<&s#PB*w(uf#rF^FK;4m~>q~Mk3&%jTnc+iZgf|&$ z%zWpyYtGK(AghOCA-#p>Bh9+13|fx93KPLEcZfF~GEMDHXjl#CV)Et9@ACMaBp%O% zpFRE33oDe-tHf#MVv#Zh=b$MpF5-|itveSXP_7@nQkaqLV56zwwK46+-s`ZQ? zd$+WTR(*2QIF_jJS<_9RRz1ucNkQj@^Ipjj)%D(7_gZQb&tIJy;(|waOqTa{J!^+E zwhPrIn0F;Scl~{mr?{4Y|B3)gF^rn(F2U~rT~QLJF*Qr~8?a2g$ZjA}AN-#;>G6RC zWjwTy%VGW>8lStl@)*TaTJupGxb2ABtQO1v0WTey5GY6OnCKt#L!`fks@o%sQ7ib8 z<+&<=cDiC02Q%?U^?ACYye1^4PHo6iW)TSQ!1%)WLY*7J<>C(4)|UhEBG!DObqtw5OtUtR4$t#G7fbXqCjBuIg$6E<{L3r9 zW)+>^MSh487{mTu1-CTWq7-Sux0Zh7Qu~xGF6QCFp~nAa@*Cp4ZzexYncsy-1YaV+ zSy0_jbmdFQ?hs54o4}u5WNl_@4 z$8o~V7>#GMBckWG;L!=B%Lk(lPY;)1qg#)>LPhDQIz`IPDojq{-ODU1-=XNyo3{pN zQ1QfJd9<497#s4tn4Yfy45*^=00NBwcO}TY*X|PLGuhSt>O1YCDxcT|#(b-8djxo@ z_pof(CE0^9l5zvT@{jk4$Vt6U<_tx4xm>t`TRnsNw#o=SL%y{D6G-$FXPTjrgA^K7 zUjMs|k;K|$e+D4W-<|APM@Ds|7N46b6KAhL*-+wJ@u!3rUiKj_Y7iYhiD;NQ15F>^RQmw>Ph+SlC_j5vJ*|NV%*yO-x7wx z5y=m`-hYc>FA)$fKDjDUeHHWg!`F^>DK11P1fiD{iUOpNM3lYf{i@g|eAQX>+-YAj8WXnPH@u-%{ zBga$3Tc6sLki>Q7GOtezHB*e`yi_y>gq=HK&ks|9(lgDcN903UyHI7Rhdt34CE{RZ zYWu-FrohTJxa^Nq>B^z%u!EsNreP{WL%~UlNcfCO)%$i#5)Yl$1b|+a`(L(I;FxVU zP=24Z!E;3Yn!=`1=6?l<*rO!k+(ak*{EmX2nk#_mYn+hdG?-4dbVwfLl64s70kj(%`n71Yg`DT(tCos>acQxP1?k z^$W7d^OW-Q{E2h_&kzxOT#cK2Kr^OZ&+ncp)js3S6Y#Jd?;5dDp-Gx@+d}lCJ zQxVYIGIuPD8nkizLbM;J$tf{lBOr2++%U3+kv!8Db*%rU&~6y3tQR~g0y8`V{2OSA zXE|=7`%+OnN(#GPHce-fESzw%?K(L6IGHYDL)f^8$^b-%XuLhIW?T6$XP|u`iF^{h z=O#?UR<~T&wTo8Frc>NkPtY}j59h0Q>IXMvpYRpHn)!B>FiD?8@`|xSWBULWLPV<$ zDHxy=P{0v6HxPm#FQ=sUn1%A0*j{a+(Z`=V-(nJJzrlB-N6-7bysCE3Hy7%RIW!6W zVTuN#L6ICJd?Pgx(k+?P5ynQyN3OYkJ}N^jF|xH9pMHCMzYXk8f)Pwb-$F#|`kVag$>$YIecMT`r0Px;eZ=SO$=h!je0I6OMynb82 z%Cco*?hHU9cshExAfM0D))_n`41$#XGwf4e_fM)Y}piiCN@ImwpxxUrzfJPbm zyLWCXygB}R3r5Wpn4aR9bez~{3udp??>QXN8n_ntH!Jq6njPK!O(~6A<~;(w zW!vCMYS+J`)#(H1(h=XR97_m*Qa|D!vo%F1!oIH!m&tur(xY z$4*0B%5!l4TiN4TPx;}4TEOu<;X25;Mi71gn8=yTNJEC4P*Fkvg!_Q$hN*D}GOcsq zIR6t&g*c_c?I}CHhC#am84vL?hA!qY>=NLCHyo(81S+BevZOQn1HhaThaOI|dlemK z#JoqaZHrV`xU6*q42@GBwPr&)_Rf^+g4brizSIG58C-b;9nO9820=(9j81y;y%aJ& zaWvLo%7vFEwA3bX^RSvc`OT5X@b-Z8pj^7{X;>EQ$fCM_w?x=a=7Uwy`4H2!^`QDE z(h+Q$0sUumbEd44)NQ%rgh!E+7w>s+3Uy6PhvUXs!_V;Wx>~8VRr2r*Bna&d&!~=2 z*9(+6xIOs`9XO1JBp+gi%;!`8wB|JN)#BNF4t01?&>MNG@WTUjBl== zq+UX?%-8#>2SC3URY9V)Wj^DsgdeHEMDU-2CbqeOe;QDV_g&)EVx1Tfm{sBfXcGth zsdqNeP(OSVE3b@n&MlznW!ic0_P}GWqlDvnTw??ysFyG^2%1|t>f+r4f+qKuGo0a} zy>VApyB!X3at$l!Wikm(IP$LMr5EBfijik_j#IbSl$gZFK0$=9)1;@bX7mO3k?Vc< z4E;IDRG1D|lq>>$b}S4M3=D?I(AC@Rslr6BXMgt?t#C*^p1=Bk)bLu_{;hV-x$kZi z#=6N0HB)SL0$oHlh>TOa<6Q0(0-d)!P)rbaowp|kgMn95LcB@W zI2T~&Cy6O%j#eJGqh9NuO~?EN?7RDZo7_R#+lIwA4_T0WqR8H^M5d~Y@3(FG`@c>? zBhKslGR}x$;ImX7KBKd>l!p31nFhm7wRK7i2?@68yUwhm1m>|nYw4X)dp|qJoYwSY zRrY7ro25SufSMUJzE0-s0g(7uN5OL!U&6k9{kAYdV#>kDZS%Amoz!}~cPjLG`C-xL zm-2xxbBYlai@DJp+)=d?oxZuOl3dsK0P2IK5}e{Tm#EYj33zS>6x$4DtP*e9h?;=~S+{043g90Tytq6=W4i`K* zY$oiGY*U|q3Tm71nQE3dH#+xD&?-lD!%D+fOQQH!D6u)?qMI6A&u=rn)ns0~`+r|C z-bg9_dnVyag%1VU6#XFRhaUL>>F7L2N@TYT^6_aBdH~3`%)vxV?>pm%2f)e#O045L zDxLk=Z8$o4D~qU4g9sPcP}z0Da7o4PWW=YlfDmr=nuU|1bO64zlEW|=&lvMLLROL) zfEbGU;8Gx_NKviy$*FEbV#5?Y*Nuk6K%%Qj%l-*X1Wj)hNTiEq-Bj*Dl;Oa-XatP( z8y@Q?ACKxQF;BtCi~Z?mh;6nlSI9kYa@bE*1FECdYZE)xlF?FCUt5>Ak*2`s*AacC zUiQn0Zt(|i; zJt#==bP_ID>s6npomV0MsiP^jQEjZSKcT^O z4T*wGWz5rca)mYrFNPHPG8DHn-#{t0kV$aX-H!xu&<^rJo4vT;T=pqd@7ATZCl#_q zI1Rj+F1gTW(^7Npmmr9}r%NLd2=_*(%r?cxX%mxUu@Cn%nd1ogYFZ~58}LbUKJ1_A zVaZM53VOu~OP&cac4*7?MigWT+O14@i0eFh8!THHCsjv1yra%i@`QL+a)R@{U znuqLfi?k~68x{np=MKoKzj!d%h&HLaXyIF?X7fb%sIY%G`tq1Tc%1z}j7nXx07o$% zYd}msBk#mv>HNu)p7X_IZ!9X+a~ngg8*ld}D_lvy^160f=hm63q;c+v0mD9vi+D;u zAk6LlbA_0wT2d82a>YU+pz)3Hik*k2=}vq6cM;{4(Y6z}V;97p;W}TrtAqsnL`v~3N|slW`)uITV<0-L7FavZJ!)GsN_HH<+y?qYy@cseB(3|f zy`uA5LVr^}LBt6${sQ7M_RwdPhPcYUx55OU=>4y!>4PN%ie8TTZqk_k8fuvZGu3xa zN0pFAtieelFm$7d62ZD5K$3HzY>MdyUn!9-32@45pP~_z#sO7v31)_^VXTZ^pk2H9 z!?f+U0B=XlZpdI}2MfzDNPtTFGYnbFl7igzL{>tVZi+uT^}h_!iwBqxw!blX#4j^F z7)$Z;I;mUD#u=b--4R4_r}w5>E)R4vuYA1GTEhErPLsw>r=4kfFAlT^mfxnks#5Gb z>G1?EfiUqy&ko=Us@9o7DryV(#lga5aCfA!Z5`BU(&*%k6*dtU%HU~DuB0A7a!9xD zbDRa59rJG4T9#W{oX(lqw1UBkp7xXnfyk!>NW@!WevY_LYt24NFc)4Em6z?g?6g=S z*kR*Kw|~7zC<;@KCj;{93gllk!`UICvH+utAv2i%-z*=pIJ z{4tH&eg_^j>0BBj^9Lqgyap;sR|m4YoACScVawVJ;JIij>v_^TKT6V(^6>+G>oqr~vnxqg_l#qZ_GuFxu(al-9a#eyVG;)Ros*H9CnW%fzJ}US1B+xs zHntZI8#7?=5bOcBb>K1G1v>Q}8S+vcI9Padx5!3WhFS)DExO>2{b~rJuD!+AV)1yy z9OLN8=j~xq#7%KXWw|reJS0e7Z#cz*x!vu9PJj{=5*w~|%*iK~u0#up)~!PDXa#ZR zy7%qhu`h=lw*g5h9)#iV;Am~wYYODg_IHTlRM%XCMA;=T>yl?g>stsZ{Dp<1h^~cK z{lblwgQY{mF%x6KmhT|MX>q!1dpJi4&Lb4;ytu^O4fIqJDu<&vD6jHhN?v+W$C(*W z%tuNrddoqGH-`0#nkeCgcMSEfXl(vEzmJFR^XG)52+i#l6`6c6l(Z64RMgePxZ>K+ z#vb}~)NB9n<%)amxuwjWa<;LGnlW?3C z=_jd|omKHbe-|a_!@Z|67rQ1M!Q_!`W~DunsbknHF*NDN#Jo@(s{I1Z8k{<9_fd=i zWmdZ@c}n>MmF>%)kw3!}VwUvV8e|RPPY1J&bvDHP-|}KS{Et#2*r*AzG+Z4HZcbvz z=*ci4j)6F5K^FQ9#f{DOe}Xk3$Iu{m3(fbfC{U-y`U>mG`4M!XCve>$^5ni5ru%*8 z1{p=6*eS%?vSd%#vv;lN>P^~LtD@b{^3Fbe2`{8{h*0HI}B4taH=n?aiF=lgTudGW6U zpYpdr2GDaxb8nu0^cI}UdvAv7np}yb`N%)2R#}J*PSD3Ym+4%sSF#hC*=J}DSt2wt ziRqv|@ph|G%SuK^3F#rktFbMmJQJ`zK4fj$gkT0d=TyIER}d=H#4Qtji-@e^Fi>cN zRLuErq8wYm@QQ>Kb>Z2+##?ArHiUwcM}vRbIN3CmDb7g5>4F6M@bylrW{cfC%Z$~4 zkS$}ujXGB>&_Yl0z{1K5bg0-^8p(zu>cKeChny_@-S&Xu+%?}WC)=xFRh57B^P2al z3Q)gpk^(I;o9@75i9;g{S^ZrqdA&-bblNw^*C+uk06w-ScA|+4p1a*(aT>-+H1Nc6 zZ$AZDX$e@n>ZnwW*D+m}h6tooeV+pbW|7?U?XhsPUzYarxzMB>=C7I z->tC{YPUZ+)In>p1l}h~*3}kE{=LB}EcCxV03*N%yly(NuF^gK10w*_gWdcGy~0Sz&|{Rc3517KRnG0kU_4II5s?H%0~s{~tzLM7ZtolE1v!AxSgX{g z?TXK)CbveOJ5_H40{CuW9Lbi72D zWXoPcA$LijTv9eOpqirIrp#6KYr#S@nr?Abz!;pHhVRJlw#*`Cke|q_L@6edcZ9W) zJ-f14EVh8FRna5bIBB7vH(-zXKoCsUvwB2361AMm8R3SRl_@Xue4>7mvqK<;K zyF~778UHKJ#+UR|bAN(=XHv%IJ68cV1(7^6*Ai%N(cs|w@IwDzu_!h_CKk52EWB~^ z>5hO|^>0vU83A2jMgRS>;}=7%#H* z52E{vvnaHo0^>%dT;v{ySlaa&*tz>Y42|>MzI;d}#6GV%Sr<#0;@!Ftn~bvhLUTX7 zD_*1uq+5TzO;VtZsr1HdWP1l6WZU(4meNbEq34uVg<1taEiY9i2j+-vLJCFUHG?jg z2B;<_FM@nAP_q@QT^@|Ny1TtBK1uMV(Mt(;%);|$PrU5u_~@ySk?@#e0hb{9oe`C4 ziX)Q*ccw}oV0-|l;1;rPD*Y-E#`vKE-tuaXt8|K66<<%cCzU zB#MDPq<(v3E{hts70UhwGYv0cDd5P$^8{J$BfeP;PLO>dFb1Fh8eIssF8}KADdKO6 zFqn)oOx4U{AFqPX6k{75&mG{}Rsw3f$HCE^R;W_wMUW&`2?TPo(4EXAKXl$^39mxE zL`5`vU{NodSd7fr1w!Qk6lMN>_ZPs?vU4BCQ^53F$^8gegNbqQX-%*$n3j6IsN1we z3JR5u4qqOMNh4*gB1X1mQr+^R4!sE&O+D_;4@dYDvyEeC!W0~<>@2r|FNz&}xf0*S zCKqQ!4CKZWRotAM$eb5W%e_?Mvv%KZG&H>zi)@Z;4PC|oQC-WfjS6Zz`nHw+f>P?; zxdMj=b%9MHUssLs92Sfi4qbouTi6`WvQ5FrIOO4;@X8JCQka7uGaUNc+KGlndioH% zma$lw#1e?G3z)bBAU?+w>02kQ~ajd%-59s4{Wl^+6 zdYGqajhc1dP|^_7m-K2y*;Ba7jk=3fS@rtJ-AAV30lv_5EwMQxt(tlZ3ATiax1A_! zOhd-=TvRKIbe}ib8;7xv#bpRS;CQX%eln)I)&*0{lBEaeH`dOvH68v*tM>fk>B%&J z8%usRxMV_PirEc}HAK#+zGqLG>|T1)35#KGwVql20em99Ob6t8IfmpFHibV<3QRAm zhljiuz7+d?jApH-?Xk+gd_beJCtS%+wG0qH9lwO2$)j7NHz$AtUWL;@?*}~E zgyQCM>&L(^8b5rdS=frZk*MA=1*8{pioE!0=_fz2kbE2ISfW4Wf>Qd=|j>cf|q zRg0RP;@kgszq^+qsk>tzdEEvFp(M8O#2e4A4#-*QsBK5H8&3mh)4N7IxEh`@6T(p8 z{wbm1q}%sLB^Lw8ROaXADovp^xHhS|zm zh1rEKOU`6>PkGgZbPi)qN!df2`I17o;%L3y==}Et zBMAv$@-*B;Y038nRXE9wY&u~=xc8Z&o^-da5pk?gL^^%oJg~BkG~H~DvrbKEgW^j` zg;SDJv1?Y~exVGxoJ8wZry|SWUoDm)e`#fze^yFPBn4cQo#x6jb``o+|3KROH*5S7 z);U*D9dL{7G5HE*>eUTnea>3@atan|y)@|E)xvCH00nB5ca7STG>RYaTuk>=nL8IE zZn#VFsE{5V)7-vsm2~(>=gb&G(4wC0T@PM;?&5JCmBB!*=a^OyGbT%`ZDfeIOfaiT~YqL6NPEDiDR)Vgv$xcm|+8h zy#U8_m3i1n!`+3_MCYp+OUQe0rL137z$4T#_S^#N&$_I0@kLBqY@4~~qnyM_dGOy1 zkZr({_8XXATl<;dqM-Eag$nr5GMy>wU}VNV-}#WP~I9Yk+4BkAdN3a=+!^G2y#&fh7{=G zcmz5H_8#OmfYi7*%JGWPg5oAfi_<>=9;*$6RX9J%ty5JvUa8J2c8^~_8Bou?%e z@$P0i5==U2Hla;OZ}kB1f3r?ESRg`atlhl=J{X|7oo_5$T8Jb3GH~Kwl!9{p>wYZi1LVDxTl%o50Ta&xYXK3t0dW?gv zA#MWFv#^sBzmqdb`jgQzoFJQr&2vX~uXvo|`@}ZbXb3hQ!1aASCYCO)TL<~XQ ze}}IRsVj$;#kTZg3$=ohpJCbrTBBW@lGqlAKc@`6blt(TA%bWWO zbBLA5UhR9e925I{R>KEfJ2#h$33LmRH?~Orqni7*&=Vz{8pWngkZA^F&9ZH4H_D0T zIP0@!>Rv1xxzbrHbt*rdHP~|diHphyu(ANBRj{4WcHR36v_A%F<^8U-@I_q;SFI=g zNn#h>jActBfeC&8-0%m`nCE_S7}CyZ2SF;LFfEYg%Gs%VkVr|Gn%0TwAfX?IKKz-@ z0e`f2kgP(?lQ@;oc>CNwj0rFjq7fNH8<<1cqf!2(H?3u)7Zgs;A`!+tplt{aI%zHQ z8nAlTEJj6>)ZDTN(RQXJglT0KxzrV24H{~k z{*l3yd1&PO3U!{9?l;K5E6#f#se;A}wYX|TjVC^?vEhOUD?Z%^Pyusl71CVU-@3hE zQD-vW8o32ppAqdphvFsO`YUW(pQn4U=&3jUUxn_#)E11ePHux$9xR!*H3GDK|ErBw zz6^w0NsD(H8R?YU1Kfj@#Bur7VOkYoDX!zV*X6aTCelA&wds2XvBQkl5*2UjqFl7(XR3SKpPeZzxiA8FNx%L%R_JuNmx*h8JIwRRPUNH%lJ-{A7?;Ld zffdHJ+&?idYV)4UG76z!_m`6fs?AHo>D?96bE2TORdW z+JC`0`pHqQqq|!Q;(}&y1V71Aqk?l9qR1p!;gNPvJF|w(&Upw%_+6*jfB0?MhO}gI zS6a(Q#Nb#L^u`-EA7LdTCE<7wWV#Y&H=P0Bb&k9fq)KClXjhsnQUXycU+?efqMG=^I;MU)wFAxj%&o_wVFUi7d#iB~?BM&AO?7Ty;Qkflfs32ALi7zp#4=Pg<0;_A#ji?Vn@&qU8 zEifu9(^lT#ifGO?=#$&OI$vF7|MzjL11=MvGHy@U7c&;mvJH#h!U3wm&b+idaRsdG z8cWsBaq(T-RElgNeb9!UeTIQ>70iTbZZ-gP338%~j-Y(0FHE>k0Ax;Tni#SkZH^_= z=5FGX5i&-+4n7nVwmoob=vC0kY^gyfK}FvBiJ+T<8ZhrBCKk%dHz1aHGEOuI9Pe=7 z_!yD!PRV=Rr#$hv`?^zG>#unLYAMtn>Fp7ZJH|!a-KF@wBd6C)8n1uJZ1cB1bLqk# z40w&vF-vq;lz&{p+nt?~@Q`VF(q>Q7To6knHOxvkb}NpiH@v$f8$IClY@}o;21~nl zA;EdOQV@8nJ+N+=%AOeFZiI;aquF7poUg;zLmAZ-gc<2Mu&gDq$kf7pv{j+OOwlBS zc=&P~c(N9GP$BXk6?&QC5x)dA9Y-*D`BZkE6*I^QEj7cee^aGk`9iA#>1wK?fusq6 zmMTBEt)kX+MV5{Ur3*6#+;p4r6NZ`QaO3(2 z6iF)H)%Uec+^e%6?g85dZKK4UqBnT35{>uk)TWf$cZeW_WbQzC;Dd#f1;%<%4dL)jigKWjw_|x~k|EepEHq3p=T;M{Ts(!ZFudo1$vUy}L}{iul@Reu^gmUyQ{Q$Hv#@HGZ9KA0@%5Lu zkiPv2F+vD zHw>vRChX|a+FvH>VE!SolGXR!$T?|dJT|w}X#f>L_bh%mqbG%c<)i%?XB4>@jAjGs zYLo&!yT}<+G3DA;SU;CE6GKSyCkjqcpi1KJwcU}BDYW(5x2fkD=fE!kAH?enqIuZ11sB8qDOqrYMyA+!SGb=A6KqmS#c%x1h>sQ^ZD(r_p zJ4XeoTu!r74Yhs8kpIvz8y?vT%;Ijj1Y~I|tA@Z`;@>rcGjv@M{wla5kZ}*yC|t-(!=>Z_lOFjECeyBOXeF zKo*Bo4N>qTKGJ@zr$et1ftJzRsTteZ5kRMIm4^{V6!lf*Ph7Z}f6#)_PNb7HnfpfV zTV4_ODduL82*1uS@gSRAII;2X4{6 zxSWaB#$ZIOp3__GYudAJXPh^4VJa~IcU?~w!<(Zm;iFCu#DIy(Kv}fB{w+^rHn3jn zdmSFAT!;7X&muL$S-@3%16_(!LruZxluIN^cE)E34-xW^l_`3DT;BH_J$4gxO3ZoC zzDxqdav*^>t;8@rO8U6u9-^fJ8_=-}wAde^dN^dhIHPK{GEj(oy!B1@y}ZDBYM}a9 z9jA3y-G*no@h56n8^5mul`9;fpn7mEkGM+Q^8uu{-AA0dLc6>!e0vp8tY;UXY$ns_|*?`6Y z^=PXgfO~htV|tBqn@l3FY4ntrJQVD`Zgts=Bg&RfY-oIEMn^tTI>crm+ar%gHor8Y z?sb`Y9h)WM6)6phF{y!t)l-y6FM7?q*L1M_9U!AxDSbEX;tI~XE8G)t8Op4Fm!qO- zmO?;c%s-leul|lWs3+ZN;9S*9zp%Sn7O+2ceS;(6-@NJfl1{Qq7~}`*cXZ9=y(C?M zx1rZaX*a+)-ln_NKCRx4Qaa8Sg_VG&VG`~f@9UH-O2|)?uf;}nP2gb~w#hYsV&lrA zx|ma%frfyyR=zFQj7d~cZ&U~)s%cNY6>bT9>hObX&L>XMu{75Ur`~6)U)(sq_bCEk zF81U8YjI9qZ_6?;TCtS3F8cOT$4-RHiR2VhD{@c!(~mrr^sO&QZ;PQ-#7A!R<9S=W zuh;R=1~7}T;sHy1!Nqym_2q+*2UelwB1v74(;RBUA0C4U2SyW=*!oh6LCzF7VV;z{mWHXRd#!&#|O<=k_>;WS(y4Ngo*xvw+%EHvhcN`cwvE-fRBmS*H~ST#vJuDxjlVjO~*1l+z4(LCc) zKVeeNS^@pohbwwrDk^aWIx4O66f|Yi21Yo-n&a@PE?bLEezFNmW{9k2O$QZN@n!ew z2&{ZG0ScSjN~ZWL^g!<>3g~9iG?D%W1}2O(@4lgMMbob)jO`TlgU*w}yE$>(^^v4W zEgXz8pGR-fI_qAN8IYB%^k_W}q!XI3u`R2+?JtK<(r>AvWk)k73%~kb^Rm3e6!8P= z(0HRFTt7Dud7)VrrC0|2Us%He#$HjZXs*H)yDjiUI5Dy3LxILLxIy+T=zAK>?++U6nU{22|1&YN-6c$aySZA@F7S+2 zw=B(3u;$O0C@Q~g+Iv2?Qh=v727m?b9aHP@V+;C|KSNt9zDAn_0m{s>Zs~UDOqnFP zPfG$}P27$nOeL%SNx$GRE_Z)@aEpw(7<)QF94rLj9B>NM`Bz3L1z?DF629{WON}`8 z44b^Fe8pGs8Xnkkh~tBR4D>n9H5%Pai>jxUFPga<-~K;CQW{~=ONr~H(__B!hA~FE ztFc{%h}iP4SQuTrOb9-`!8-c+!#%3d!f~{*IPg@fzHdh~nzzdOapnJ;DVkRKsfgT- zGf-_4;H@~7KM<;2=*JI`S2QX7O3i!#I|!MT%c4G9zx1z4r4E-c=80A_cxPoEN(#LW zS8T8q98hn01S4;elFpE;{?ai$1$I&{qZdlh@X$%rj8c40ZZk@}KFGwOASv!!?e1Gv zN0LR|P>?OHqr%Y?HiMCR2hS27zXsg=+SgKmc>~6&2l?up{Bz^zE3(wslSF1f_7-+S zlV#*DZTEwza>EcBBn8IzSS~9w{_meX$i0$Ny+^PK z&a?CCjWeiSMJ`&N9?|!O^Rly-fel_E>?h1*oy|%l_}a&=Kpf&(U?8bO;jy){uJ}|! z*kA7Wb^b9M;9pSSCQ5jD%s+Ci+mT1JsFCD4rmKu)P5H-);;- zScRi?lXkZbl+F5mY=}1ecMkfz0c^V_2Q1LWpK51;koEz#wUmz5835O8VNzUSU7_g2 zLYH({dfirnQI~@Tf@W9_=9m-7l47aRNC`>e@-@jEQmX?BXpN93~-g*9) zKri=msx39L;}MB%D1QO*2w+8f*WDfD=n=hRFp5ObX=WcJB8u4p=wx`^CglTZ@U7mF zv-#bbpup|!y_#}HV~8E_OU}X-_bV*#M=KyuMfk%SV2^M04v^}6%Dn|a2BN2-mo@C# zFMjPb@X~q`kat-k8rFHMx7J>P!%k~4(=fIY2)TU(d7Sed$hWeE z46xNV{pWtwl@Xd{15+qWB>9J3#L29;1aAnStD8mAdjV@26mCmszGW15Z9Xr59{E7} zucv|RPMci~>9A$6e?GKhxp7L~D`kLh1R0AxXVeKdBmp@zIm~h$EyJjP$Rcd{JUyM4 zyLKZV0!xIg1cd|8xYtV9&PWyq;uHN5C&CAjKwH0Yeca^BC%8_`_xfeqadQhv%+u{+ z6nZmvi%u13a)+VCiuP9*T4LJIcq&{X$rj6WrO5+~(%=aAco>Ke-6$P-fdtqX9z6Wr zAuucVF7Q|CS3C`1ihz=7KLkw5bq9iFdl1Dg-t#O5Q8@71R^=C{5R?MjTxY5a{lvCH zM30&VG^YpPwV4Y*7j%{_C#6Qc0$dI>@9CI~IgM*0`{Hm1sl_Y@f>_~D&B|1G=x-eE zpRKG%vy$}dTbBJ84j^$@!O~_>LFEvNG!MJQc9bY$UqB)~QTa3)EGB`t5k+|Q5lHTT zXPhQKm}(@*+d~=XYl+|bjLwC&FK}xt@ji5t2o{Ti)=Y*>6@xes6Mr$OxnxS{C8|IX z0dOksE3d7(M$k5^h#lIFwQ*lbHKxchxL=VEz7Z)I0jqrW|L-d=E{&pL1R!29t`Cw~ zoSk?Kzu~&GwG!#9JbQySVl-{ZQhi01b%!f-3gu|&4WB^IWW~xUIgS=oWmlR9T zB|2kcBzP{xB^`&A-U6GUlmHz^lIa`eQmQ5a`4~aFHwH)$`NxpW4hhZbx_ztFsG*)3 z1$PXqpDu2h1sh;iqd>0+;Qy(4-pIMfSG~hIG@JTfR;0m}{zTx+)zH(A?(`rjz-H zIlscSNk}cba12SHZL6xC48^=Iy_2$%NbzK{UDlv9M!{xkHd;`Jh1|*g{yQ9hn?~u+ z-}(AFCDr}dd$qvc(~;mQ#l9=tITCA?(0EvzBNH0tv$hLKTNtRnzSD4QeYWdxvTD3` z;4-eOyg)KjZ5>L26}_Vz6lVY}a$)=U^*Kau%uJnMch!I@+SG^gGB%VRiBk#bUXJQ1 z%U&}-K3=%8OH+~gTDRKfC~O6`CS!&BIDU10;Z@)o{dp*dWI{us{m(X3w~y~W9U=IT zBYMbLK&z7y?q@^)u~(qG0^1FVo*vm7Ao6V#ejmoM)Ay-HTHx)q)GT%f4gDwtUuR=) zoF1tfCs2zE5*9KUIoP^5XSS8}tOTUUy(MECK4q-H2$9nc1Yv7VB(F!R{_%aL%*Q>i zZ(>N`9SQcF+*=xmQm|49$%e4e5KFZn$0=DhYD|*2TgZ2`36Sac;nvPj2+<`aelUe| zghe&>+v8**=BF@%qs0L_6!2CqoWV!*a!XpM;Vw+`+PUm;nm#;zKtT?BH8kGs8O2BU zc~Wt|wiZF{!Lg}`T;A)MxhLpQSXs;=c~O`9BvFw$U)ro9*jAsgWU8#iC{+y{y4fLe zc`nPDo0&g2{lovfbXbmK;q!uc!Or;PHt(5`uvqALd=F&HvjAL#`y%F}bG|B1B{t(aQ2$OX`U4 zZTA)ASwh$lzS{TGVlXh~NdqJ|zAat-CHM5N4d>vL9Ak>nnL%GZYgyC5ySj%BITQ!~ zd4x~Cr9RfdC3P?+U@xBs+(Jg1EOf=VaqS}K<}G0-^L;=+-Fn1V*rp3;dczu_-L_LsZ?Aqnm9%N7$g8~Ksqy^$yE9M`SgWdKsBXl z=vY|ZD!>|8#mzU%gP!ProbD9yn(s08eEmGs&&~2A9cK2F##Bal5S;1U zgFH}i;cLrUr)~~&^EQrl-lxUn#!4jx>Xt%5{6Bfnr6+?7{%Ynpu@!vZVHcG;Np|(P z;Zx2javI#_P4@4F{T10Vn&Y=R^aW(nSF(Ubb(%QAV<*Fn`=a_+^)#5@l9FH6OT4lW zZV66O)eWU4=qzV#&0#rObbFSfe>Np)8MNDE?35h z&kGWQeY1JcKO%x4OMEzumwHsTQKgm04Y?O2Z@SmH@+TH5tue?0uY)LhhOdVFGkU}% z(DYLtmk|w)TRVbH1xQ$MlV1ryD34-=Q2B<-xF)P{G%KPg3^v^Ux^^8{J4ip1{QyGD z)WRepy&;YUgE7hE=3fC2j|=9IS+O(Ml(sN;BAgPhjGDd>YI!$`k-J({RIjAmBljJ?gNSqj-vvi6 z<lsXVqayv_m+9efMrke5%dNnG0pe2nY1J zRM9V)#(Bg=O`eEkFA;br-9)JwQ`6*efe$M9uAI26B>icj%C!8-OGj6s{ldyH7DxGA zbMX#|$u-?pR6IU*7l6wxR*TmlCorI&wJj6^34ba|NYIzS;*y_k#YI&&An+yw^nzcL ztY~^+M7ClgRvHRRpnc>I)6K||B$k+YoOt~&&z@^%dcjQ9vr598=JW`J|2wOOyvOexw#PjDoYHdo z5;|qzmE1&Azh=wN{<$>xD(Gx>LqD3nybwc+ezlWh+qK*Fd1!Xw6w4k8q)Y1*cyFWqz+}^boOj6SunenFTap)qC?ZjfFh2Wa|*k0f8r-#!qK!THG z>%y*2BxB~k0jq_Mv{}`eJC2#VJw)VtAF>WNJ4j-%g8&?6xfeacSygWzatkv#5)%#O zFJI^uTyGY&#;<9%IfAf2;{0}ttyZNMA`SxE2<}LCA;Q% zD^SMhJABKWsi^!0r@nl;3K14oH`n;o5_b2EenTc@;P=>SU3@7cW$$c{9#dvA)iXOP zxy;OGe)tLx!+v5W-DX@gb39$E2h5_f@C4B&ng_%027w)Al^RmVE1v?wGzqp>#UhD9 zCth^6vkY#3O^w$v7Ed1L?&%;7iQaMv@t;ho2waWF{psQwFo*R2+(WHeNKv~Wf*dDE zD~uA$jv>BYb__)fT*K_?KLC>lVPfg6n#LqChIPQZV(5{$N)gRkd2Y};3?{POWlo#! z3jy^aJv>n7g>`4B!xr<7V*TIK2{mv!4EKHAe)N?h2|G(Dn@El)tU;OSSekN^j$SYH z;&>_eVyK8d$2rOfxGLnvXxLE2M!Ld3;)9J3M($0Jj(;%=IQ*ZmpoVFB?}6NX@rA;|_x#OL-AIA{QMBtD7XiHP)wI4_ z+~+KyBeM-`Mbc@0bcRiFi{RVa<3xlQX5=RtbKE$@_4&grJNANESPt)pdl7(`sB`*) zC8O<>(fB&iZ3Mo%kYrV~e(Pv*C0YTUSUR$MK@Kxf?JrHaCNFxKQuO{gbWYifP~)0E zz&h#&NW8u#)NBvzOEu8_X@6;w^25o%G4D$<47>RpdD5+XgWpuKAM`x!YtF;MY>hQI zfvXCu$}qB!l!$4O+s9ZOH2mfh7l}|FnsrI$lFj_}1fVxbI#=1^JCe5p4`7XG;TAVBOFO zQ8uG5^c3^Ize4?oBf zx?Hfi?G)O+fGQ1%P?{OJjwEs$PeV^)6Jm-zz{Tzsjf#9m=g!O0Xb_-~#qFV>s|c1X z1_IGRWZCO_@3NQx_fxI9xpIywxptOxjCS?nk=p@sF4@4nGxpAyE^M2?E|}`^m_*su zwvz*jD)FkB#+v%~9&HNHq2IX`p)}6c>$C{}NZgJyiN;Ysgb%>#?Xeg%yMqb6;ivS3 z&2pnBT@|Ic?*|+7G$O4lc`!8~()5fZ?>_vfFsL){HI$m$UujSuTS)MbYzQZ)*+{z4 zGB2Jq%x;IzFDiB0F!Rh1tW0Z|xi80FRZOKnCh6P?4u(J=0rA$eHw@<1dik;n^Irt# zTV#>YBHi8B-^;;koTiM_gv1Jb`F!N<*&Y6)t8ABTFO0a=COP5gQY z@U5z_niDaV$Y!*H2wM(-FcG<%HuOB4e6r7pqS=SXrLJ@`f%g{7cz8LAA@Lv7$iI0+ zhj}Al6bM5Q0r#}I9XICqO}7j0QuEQ_TAD-*e9wzT9{q>fK{PtVB!DMhP>E!Q_h!Q) zp0k#bR<9rZ=1Jr2$9#B)fg$3P`J0>lpz;jCh_l(c1kAGYZS#Yw)UK}hF{L9aIA~is zSX69;+_%7so3ytDMA*O)VU=m42z=J)*3JvdXHYcy0dpD13QVWi9Av4mLs-t1Mt(}n zc^sj`AHG}}$!2#SYz1}Tv}up59qmxu!Rzjs9Ms0+iQmj$A7_RmSv^RZ_Z&cq)pOqj z0Oq?f>o=bEjw6CIBOUSKeir&3ivU_q(863w>7H^-l)BO+D9}A`eXe0IfemuX#&P58 zc_y-CH#uOR0f{le_QSY6%NXHtd|CMqQtkaA_BTmTnTc)!K))}`o`V1ic&O}Rg;hYu zVU}$luP+d=i}!V_um6~IV8PIM;q#+6YYp*f$51Jg<5Mlob1e;06IQ7%GX*%3apCep z8}V*FW(pePytx|aR_aVrQ!fq)6i-InXf_t3w@>Z-&BA?(;@GQ|$kr#^)TyQwlKz_4#ZgeE{sHYQ zz16v%CpQFet4YGE#-EG^fm7X-#O6=lUosAJ#RwrNg(vR?lmlw-NaN(ME6R9fnbj-t zo?$6@&W&yDoetiDWXY&kaxSoY`4sy(#?`;JPITC<;+|U$b}NJqQCoFdcY;Tnh>T(Em^|6suGLx@KR6Gm*dcmU{$Y^*^jUqFlrE zakak~b#5^3=qYLVlXj{~8sBd3>_?j`wn~?m(g(ySiOhXxe^!XPQ#OjKo^~RBW}ogl z;N`7r>v9&MsvP}ZOf;m6aW~rmTCFBn4~$2*Fa>QA*pgRf+SaQKMNU_+vg7_Un7ysq zPd5;ryg>OhGqGx|)w|)~?_H}FZYNN8_;V!{q+-KlSnkeT1anare`s7OcADY}Y;_m% zPUjB9#g7isaus;<6dj2644o!252G^zY^Y4~vP|CD(6QKP_?OAz>q|{?Bu3TUXXEq{ zrh&!-&8J>qfjPrVKEd=~hTm!6aW?pgRbWUl5QW^T|%aX85sZ4lb-w&`=idnpQU$e$g3rNutY&^Zqr64YbMIEsbMhzs?LDJH-&&6koX`DXgRh(M;5FbOuCv1 z1%BR16cpDXKn$ay*=@F_k%vLWy{iY{Hf+C_owbWd2Q|IF2|O)!2ngDeUP1S-F5U*r zQ$zGh?qJAsH(@<7Up7|+FktP$36cg3K_FHWK!kx_@qNIG@GM$1XK|qlx~}spixNw>FIlp&?!LbgdEbA`h@QIEOYLIiFOn-c1)4aomjpl_%uv zkmh;jYTh3bWI3g6*D^9q5_yjUQimG7aOw~Z7BCrP-tX5;nHuIqNh?~bjYjt_$T(8% zzn`!j0JKU$0_{>#$qSEzXn4c&i~Eo)%UfaSSHd;_EJ#Ok?3s6n4kQZR0vgAsF#uJN z@)sb@cV4)qGTC&ojla6;@#Bf`=u0RHp`-GKPEx@e_bAqftK)pPfZbY^xml_%fynNE zy+m#fd+$=bcB;8k6Qb@76NrQT+|C(+#OxaHUV|V|?J*M9Tq_X{MjxxE1~KIkM%P;z zcLQSx9)2+xqX<()6Ra1|v;eBxQ)v--k2#F!BJ^buCo}Hmk>O9x9lvK*gXxRnZBAzK zRT*HYm9mN0361M>q5hdM0-zk1(PyjQA};#xWMm}&6K?}l;p-`wMX+fbj6gG!Jj&MZ z48|US7&QZtrb9y{gUO%3Q-h+!?Q7j258)>~eA+O< z*t#;>3lS$W1a40($)GWg z{QTfIOwbx4fR*^HzmT~Q;wfr8mbFXiDxVL5ye8@zfE$B-7yAK*DeVa@0jct~xh<;* zZsQD-NCeAdiKgO>jrCGe&V1RxShRa!ImdY8n&+pgF+65=tj^-9-I)m3VzK!N2Z3n? z?%W4Dfaj@Zzq*m)nXSa1QDNISv9fh(g(Huu>yZ704WcNGO~!p}q=Nj?{a>t)oC*IA zgw&b_>z+17?+vWhZw8w6ISs*iP8}yu3Zstyok{XFM}$1OqQhqK=VQqM3a52QJg@Fm zMTR|)g<-=S=o4lozL*82t-n~cP|Xr<{AHI`s;C!Zbd1+NrNA&q+bWj zDHhul9!x6`c(3=}{~Lk0^5~v}+24s)tO0R-4Mgf_^PAWn5w7Jr5EO*t@fq4o>Rlo! zOnn2*`zAX*v~1qxafW}_iT|Wye)3j@%5qGLF^ADT38k%4s->Rx zzDWu*XEMGz-=l=z1g4R15kn0A>GJrWzbK zyghVEz8k){H8ugWz>CdT&2c;$t%0ie2$bqQ|xPSuF$GICnC_1#HXm| zT22ipj#K@xeV2{DOL0KikT|F|(pDb5N?NB@(gmYyMpjGt63{f_qk|@IpzIx5xs+hdbqMVKHPykI%{Y6gdggOl zh^qBsK@!5-!dFxibnoXiZ-(8|fsczGZ)*5TI)-1J>xEvh+(gvn0LyQ!FO4c`gvK-W zfI!(7okKjoVh*m1W@*^+qijNasz)zq=&3`Hgi`9-&`b9AKg7vbV%$9<61lEs-9@Lj z*}}Vaco%bOkGM!BzYf_IwkAT+@!77u-V=!4LXm6cu&J>5$dIxm%sU-bOF2m$<3+qEeJjOMDr7 z4N_ux*_fEjvVRt8KrOh50JA4gF<4m%>5_figeKz?AfX6LSFQ7Fbv5&#NEmF!olV%( z2=v{9u^2_tCOcYyw-kPn7x}mEHaTDY^Yh8kHBln=9(|j%$bIC%K>CJ7X@aUrDb>U} z)izT%YmSbb{#(?>^(!dr?iJ*vdg^3opeK&`qfB2NJ`u{5dm=Y=)hr=_@a=_=o*!vH z0Nw@=)z#0riTP!u)QH|=ljge^rzrfg3%n>wGnZPNaoRyHlp1-_@-HlLDf0Mj;1~Ikvr=QZr(NB$#~2rwHz0;@J{%d%GZwiI zVN~;i8hR(Jo?g4A8-y2jbqC92majk0&=JzJXtiQm^V!-LuNwqa?8WJZ>5EooID`-6 zc1_iza)bnQ2u?JG**&Dd)`)J@ty}~M^qr-ivM72D-r9&cdz3z1t`LEFnVi{1>mUG0 zY{S$MTP4gm2pat2jjUjSTC+_Z`v^}|{5Pql=MLJ``L+%Oecqt-ey`COsPNsD*nT9L*p~o-6x=$;+S?3niFq#K?SWlJ0hF{+`uHn*MdGXHdK;f>EyK z_>{I*KBs{|0g`Jm+2=o|qP|Q6xP!?k2}|SmVfB9At^*37%!XrB<3yc*L;|?*aG^WL zGXd-!N$oW^#fzyf5d#E|$y{J)vuFmEkO37fqd#`NYXg#EaL3|7y4?J)+nUt#l)wGG zH!CZsNdRlV8N>5DT-jBi6w6&hU-pV8DQ&|oqx1a#UwKutlN}%DBj32P;|eze^^s~mnwdn19yl?p0~^Pp69Dw70hGHOYF%a zk@C`I;IPRh5qOg6{z%w!G3y6*Y02Q>HfJf5h$5W($XY7WcbOQi@Vp zw3eNPySfPYDDDyIS;L{t(E{r2r#E%mgF)m=M#1Uri3r%088omJkin@Jt^E6Je>OdwpY^-{W0 zyt|=mu4aoR%49UE^VFIPS1x?cO!PzPnJP~?MpiU_Y=HYXFi~syzB1>qt9BfdMqdQl zoB|Yzgl;hcJ7O?D_Xj&t%lY2iSB%QdgIo`b5UGil97Hesq)yHr(mXe7eE|Qi1U-ov z4n?T@RCLEcq?A1;W~t*)7vqCB7yX;&c#b=M=<0m`h?cE?ZrWv<(8R5d4nmhleKDNF zNILWG$9D>Im(f(?X5SqO*Jv1s-4Q_@ANWd7J8|V8LJ{~U0ppsZ45}+D^u8QV zw8NM)Tx;7G=y|?3aDJhh0Qyi*aAbW>=U~Jmw2zw*k{Y|z=@R3>N7<&bTYhsgTJY;4 ze4qnBs7M-9$2a+4`?#~%P^Z)^wWB=SS;xyLA94ELbO^Dtt#r$2h-cZxoW3*|O&)|q zS5^T?;lI7AbEDSqE=0t=xa|kcZK3bN__HLJ6Q#pRsE*rJ&$G#T{>9(mWO{WqA8W zP@0A*Qf;snJb;A8}lwg!Yp@0UJ-eojj9L*7THmQ0m>x?QxuhD{H7)okL7VE$pK4krX$m ziVKFm_t>hrp$EIF&~?%EfnKDS>fNR3V3Ug9$>__GA~eKe5W8k0A%q6S(%wXZ;1xb zX@Jrx|3wrD!DO}5gpD!34Rl(4ZckDxEoI;&bsx=s)DRm+(nuu9|Gf#>b2HsNJe-{p zSazuk!%8{{Lg@glOQx>a#cha8Tij4=R^M=M6WX~^EvBt-^iS4HV8*)xMD%lW^OdNxb<16u&zb-_{Mm#GBGzDsL=lq>-!K(9S&D#D5J4Ohci9cOO^ zQ-Iqgw0n!!Q{k%@E&+8*#bU_Fpm9i*)kd!3UgK#}!ujjK{Lxvz90?w+r3&Y(&+px9 z#kBnq5LbSY+(KA?e73r{2EHG=% zyN<8sQG}Kxs3TfWd!u(!Q9WvJYB_oFc~|;qS(r%sGFk#52`=L@D%Xwgd}&Nm-fvm} zr>S3w7+;sxxE*hE8@1fw&xJ4rHOiBG%XwdXfIwK?DgipF_0Ro8!3iA|dBQ6s=<=tf zljQnII1_Qy_8=^_V;d+|wk^Z@wC=)x)cR{9jlUrE%H#)ch9pZP{r{KG1LrP!kfH#c z>UU#Ax1cZ4gO%4zE%p;*AmNLH-?>g^Z42-5jjI1!yB^G)X$Su4YQj|+4~%KJ@*=@R zM|LOQt3R50V2zcRoZ&qh|L=Q!`x*ixlpIjL?s|QXm`n>0UpTLpZy0E10*5x0CK6h5 zuNBfnAV^Dh=SrLQ)8_{sF+M1(T|64nT}^*IyQfj_g);H-jly0)#&c%BT94xs@M+wfRRwHbNhfzvg`o#Zt@4^2 zF*~-169jT+{Y;$-=8Nses_Qu-goTo2t?pNJE}X??NLA>qwd^FmS(o(-KT6s0HayFB zlSAWh(;789KA0a80%tEg@aHC3*}E!*-&pw`lby)47%|waR(sWZ8#rP>`qpghO@~Gb zt{!g(P%IULX|NFtLJvk`LN(r;fonXGOndjF0hgVsV@P|_u%c#If}h_tU8^G~daF?P zW6Te&3mW=~yt0*QWAiI4{FN@wJxX&CXFgtAsl|i-K9EyG(pP;{s=ASl`&HK>cK3`X z3jl#8>2(0FMU>6z;@Z{|4q}-0QK1c>P zU?Fn2Yit_HjMUW7I_SlRbx)|GtD)heviZ`Iv%&2z*n7z1YCOeaakG; zc5qQTGqb#-!T6vq*J#$<0Mg0{Q2~bQ`gUQ?CojLI`kBS+jN%}Q2pqE<%KBu zVfL{hXKG2AWJ*9`D}4LEmqxDWbD{JU>|Bd0j^k zNxNnipEfkP49Q9^VF0z4r2RR-Hve@xmka$hu3dV(7@Y0?llG zIo&?u(br~ML8tX&+NeFyBqIiQZ@_ULSaji`sPxMkH52B~j@83jUU1c6(4eNrU&g5l ztr_8B8Bzr&!5Fy0gL_9h=q(#a0GN!pz(^5D`Qbc!`{L;8%+ zA#+6imK(AlRr{g5f19RSg8AxiUi~ezlT9>owaL035g>dw6B#@#6FG3EbH+90yvXN|+nlMo@jB;XlagizbY4iddCJsku=6A~qmG6o`+e72 zE{(NNV^xLOmkZ13=T%@=ydXhejruWMmlrM(kf<|~_+bJf2fd4{04~oVO$7M`RAJm} z*-E_@!^(vf-9InU9^7aPJG!$_cMJBH_(WkewEi<0Q;XFz`f%|z6cQ|&N3X_O*f!X8 zji!;*>Ks^MysV%vAdMN(qUNck=gPGI6VZ1T|B2u8vCT+xyyedF3v0cPI%ZJE(-d3- z{QlU%qg_?TzVrUIFfv$OoOuB;z{ev!{+X-Jd~3>L*pcQYTi~|oxsN!FwMk-x0H{vb z@Pu+9a&XMA4Y|=aYCv&AC~Vh^j<)4E%;M5Q14&w6!;Fjr$7z@bDv?_`Tk!39tNVEn z&zlK!KNUH1^CLe%Jt?BgZJbM~@1iIQ8Ot&FI6r1my7fp(?e<~IX;IW@1(Rv|4Y%*L zk6E#GDGmTvBQT{pQljkwU^?6VTZ5dY&gPBpw9K9c{}2nrRI82{6D07uhPh>h3rGlx zPyc+8M3s8Cr6f)6IO2z`7y7eQUAg#!-fe8xYOr@V7CSR_EcQ|JeaJ#euM>SGeJKc0 z`SRC&)kgk4(&Pd@s0P9qeI0~vfQj2vi!I+2j=BUM%t&s$Hzf#(?ZxV4V95)|ck(oh z`{C}dPK`CI8rL-nl9P)!Pm?}vp}%1M>3s3#*QsApn}puqjA9#a@}OSYWtacaTHmiH z6X>dMSfF_zBt{ezp@^vg#TDkx1lDZXPem0`hILee{68ara9NjI6;0;!7>h(R;t9KJ zdQh6TwWJdg-Ud-VMV%Q#i%n2ttX27B)DL5gupgCU@_W0ZYJ}?GjPV`Lz9TZLt;#{i ze{Vv=9+urW2f&A{i z!8+1d+Xb|Z!zz7rTS9*M^)C+JfX8WKhWU@do$@saF@X37@~$lsML5^v?4Lya2;b6A zj~ell)N?19$73MEYl%thxAb!+ePGx|_!=?-YopjvSD^~r%9{&m06{>$zqrWS8DK7-R_d}|E009e$jDq6o{K*dSvI}5 zU)`*sm=5rLd$!>diy-S>$aSK^e`v3MEY%rjb!HAn4`jM*7YMBYLbi$SFBhfYf=YN| zbyIwFU<}%MaKAN0o7bT)FjC7l@{Sz=R+A0g94jknP2hnN9o_j;6A))H)`$$o3w9os zy0p_uK>%>#oh8agO~GNUO)ZPIBRJ0i$%3hm$xulrvM3I4M1bmoE9gpYVCC!qZZ>RU z0FkBxJ>lU%$X_zz3*xOzHIP*gaM^9!TFJZK;5Cd7 zB}ZKBFo>LHhtwYs8JA)4t1Q}Esd6)T&w85w8gr!2rcD^e%HJO*VCcvj_Jvra+)=jt znsbiWk#=fQ5;(&ts+%9ozXI(#pz>)rR=Ds)y05^?B6Nti5Fl!5miIqZND&l#4W=h1 zAI||$GkkL~TU{L=IE@OCj)H_1)8_$kJIg2$t38wydTZ04?3|yg%8)~Ot+w@x4XI71 zqOM@&=jBXx8!m_E|9-bIQ9RWEBFt7XrkcwL*=#Mo`B}EPKndla*vG9Gi>kg5NA|Zm z@5G0r`2z&G!GMO4Nz{C67ow|clH1uEgBVB6#juwQ=+4S9*b<;s&uWM~>paDop~gvq zlHmVr)x43I2;|lP9We}3E}dIoO&vDG==zU<0PYGydm5LJ;#blhL-psKE7Y`CikHyc zQ1lCS``D|roB?l(LmSqudc=<=wA*Q`8R1*i6Wq*$%dbJP;9mJZK+&tfDi&3}Ke^lG zyirEo#KxZLt&qKSpSiTwqNG!^Xc!$BVqemHSbijN1-wJI{Bdp;QU9?YSn)CCL?X7>@~Z6%C{rKnaquWC+L{Ki5HeN26jL*L63A zK)z0syrWVe3H80<@h!shq)`5(0OikZ5B9r6A2ja5`2#2cw>+rv0LSRm8&e8=BoAL~ zUcc{`PEmj@I%KWXodK!^L2@%|(TbDR`(_^Z4nDWApZpl6i|lP4*%*(=yzBgaI5AXz zV<<{fxV9+M>y-tp(PBtKc;ygDed=v7hEIKvkYjIbEHazq%8xmw)|`2EaV6VBEx z#VDk_7OBZ7XwShl>vHl58&^U~qEz`;qXQleqHiwxE>_KIAqB7rTN!jte<1Bf@SO;8l1bzv&M6tRxXsX6k-dqv! zAH61RILW?Qm!D_!ly~mvTx$A3iRgk!BsCz7S6Lo~cuv~HHE>&L$_iD5>UMx1^5D%` zv{+%R_+wJs|Lj5X06Y+AIyu3B zFZ2i2+6cgLVQ#^-2)XS#8hJ}up16}X<^cb1hn(lu_zP4v9+j~Q30*DGFw+2SmOV#> zo1?>HORq4C+sF79QUPszSKZq!S0@dJAKE6D)DMTz^=>4T=ucvgPy^DV6umnSqqGWSLI8We~WKK9Kk%zN$MzNDMY?K*7Xr zQ*51LWMagvhtoEa3@%uiIOnn`sBcp)1W+(Hd@+!AGZbTl=$kt#U02T$vHrb>?JFUb z)30L+wImUs;_$%A8mbMpAmlBBQrES_s}9!Y_lkC06J)VmOD7=_^a$w(0yT8*kl7?1n6cw(_w!|4?w@HZ z9pob+r0=apB@IQ3qIU}Y0Li@5#Dr$Qy|&6J&$NEE0U)JCydGN4B00RTr9!ZV$<3s>ifg81Gv83m6m{^V!$|LiX4lS*EtngseA$T6r}ab&L+t}+_nOy znAjeo|3|+}H~?{Bluua~<@>&YcS!dg9Gm`{-g>X%GjdTZ&;q~O00pEmYSpBe;d6zz zxHhJN4@OM1rs_tw$zjbT;uriFC@m^Fjvu>&x3Cvh)GeIv*A*2@`{rSbSV}M_W-1Y` zfVuS5z0})xUs|y$521k z>{6bp7FF0h3rl@8^94RiG)b2i_RYZEIOIfIS+_H!0C-wO*kF$!xBOLIoTOsoP+xYe zdt9@ec1b8o1&}m7xTR2xq((XVP#CG4ayvlr#K2((cE5-q6m84~1udFSv~BFsTM!CI zcFqEN3?5RATwl*MSr-d;Z?&slYVj-x_!?)076(0o)aQULW2CTAz=%Zk^IpICy#81e zfqvlW&X}oX-h%Gk>z?oD?VtGnU1$zSlplRUA&NSoWExqe5`Pl;M0_NDeb7J?we)fRQeonT^}eY)4ZO($pZ*ji$WaOn(L(hwjdDC=5iEBXxKC{glrC;VtWP zLNe5gJGksdBYfbBLl4=zd*|w&9UNeK>p_Y;)Nl$C0HiGC*dKf?Iv~&FHaoNxKrD;e zE8VW7Gg9d9!D`$~3M&A~Wv|f<#$Phv4b8wT4SPgG;LhJ0+MmmvPERa!7KYWsNPo^fu*vU)cipz?6Uwa=hxw#Il1CQ$sPaU1jyhf6$v5^olb zg;hsCy*&S)nY0x*Mo994oYbO;-sl|<9YwZdO_$U8Iw`^{e&tqPJjgwpUb?)v*EB`V zFaI8FsaaTFuw13K&Wu{bxFXxb;C9XhIe5v#HD)(MOFSQ`qw~#7ze&hD=CE%wQc~c$ zV&rFag2c{o-HO8Ez_XKdmZeF}>%#|KHw!Yhkgikm#qd}Z2f7G4Y{FH(MQ0E#xYVOnl24=kdGhiJ3;ZPaI9~|M&w8cMkm^Nc8^~@_W=^Z>!|kr|fsL(l zfGE!g3}`;a3GKR{M;Nu8kdrC%h#=?spXaIm7z2Ze=6S+6Z-2AYCb?Yr`6YLi`r`7& zxu}%C<_{B>2cm!YtW?H22@t1OME3P=$XP*vq-OQyJ=e`;C-5IW;cQ*FeGXy}d#C&NJz} z*%Lx{6=Ja}a9gPm^8U91txt+z_#ENgB()_RMIl>Cd`+|IHCQ`RwH--hR zpTFZ>zR-LTX9b&ZhvbuWJwMR7t!C1E0pUw~ZtrU%<|eJgO9N}x>ej-~rK@I|#dqg- z&A~+Q3Jqjn{_IJ5zMjaBb9MMPmJ9aCBT1W5l%mk{8J2y{Vw-#xK9|%PC33~CWJRmI z5c;H+o2~KkQYu~_vZ-20sZd}^*WsZ^$+cIKFUS}e zEx=u|%m9zT9tg(bXPhfiZPtvKalmht!W6X(Aiu)F++gz0%%8}2=V$0)NPCKQAluK$ z`yIsI`hlQ5oBGM|U1^$Ru9V5C0K;q<63Au5R9ZCwiG8986f5#+u^pk1_%m}L5AA}aj z;OcDy;;w39o_g`(l*Yzqk6e2PT8G&>_B#w{&X9bjd*yOEGCuKMU&_~uAHUf(m0Xq_ zWrcLbax0GTD2rNkJ@U#w9J|c(jUYpEhXzDAFYu5Tx(QIg?wBB|0pRfm;$HC=w3tAb zg3yIesc5!9C}Ui<26Fgx^6N5PUl&$NjG=7#B|wo$9Y2YHeFbtPvki?wMHSXI&4C*O zReTMmJH+U!{sUuK=DJc##NPfh@>I_TR2BC_uFdA)wYA3R`6JxG`BeVKM>ub1w`sFgKso7DPo84PH!$eHvri~j+*hFSl2iH+{hW91&BMYnZ=aLVO(-Te&Y*G}YcN%-_MJvy z-_1J{CPm5M=hLDv_+R5t`ME!&U6Xu$LhKsDM;pFDEKxRjEuXv)aOmqBtE*Qsf`)kO zio3LCYmH<-ZBs!Vq15$-8bc1?Ua8A_xkq55Fd>h7eHGKrk;cx3K~D+LdIhpTZ*`NT zNJP|%w8UJTM6DKu_Hh5f#&-UOTKgH3ITjQ|on`L*k=s*Xb`eCFVc|mJkdVc#(}DF8 z@GNlxx?uLK{MO^t=xg z$c^id32>YHkJOJdR?)!izi-x~3l#c=h~EJ0>E*GlGP0x3@syCgsBzJ2%e<1IT8tQ% z$ziISs)60^Wk9KfC3UM9&RFi}G#q*H1a*}2viy3%PE-5N*eIjt5>T!Acs!NyD=6BW zx%b92HKzvdWqc%{oSglvV#_gjos58q=HUFXE9fzbxK%dn*e=HMq02Cak|9@j9U6kj z6)1+Tm$2O74CtY34XIBIXd|d~10E!|D@;%4&sez9ZY|_N3`hg+QR`yjIk;r_4n|#F zvP~Mh_%Dmncu*21R3PS06$1*_(oXVA6{$w2G}~7kqQ}RW=LVLaWijiL`!B+-g}a=l zY+P?4*~exm+@pBp=wONQK5U){FoY(e{_?-=DdJ5UZZgoE1iQ%095jY6EK3!nV9t}jBN1%K5BDQJi z2=Ka8EWDJ_z7N#ULf^kkji|2e+}fh#QusK%%N1>>{Wi2HfUB7jFpbc%L=(5{s-9+T z(O*{cR)FfaUn&hqELX@!iVc2PGRjxSF{Sc6dIC5Rj|lQFEQK(b{F{tujw33MDSlkZN2WqguH;0Qy_^%s4C((8{WEh`{QT~tNiV>F z#G)C#UPI@X=>3P2xt%R1EJ$^yfraM{(SkaBBzQMPq1Ipm*yWj@-3j9~BO2I3yN!o0 zJbZimkRv>yzkvdskVFyScUr8YH>tq6Ta?kI-t8%NKH=C+&PfUPAZi=j1pbG#CjfDE z*lj8lW6VE0KRXV<`wyK`e0Y^aG_~80arq8PO)z4+^G}8k z1(4;HpG;UGD`Sd;5%Pwy+2WDCI_N-^9yWA*tOe<~%rgo$TL#JIx5LD`=4Rt2bAOzBQrNHOiwCoIaB}^e+KVj8|HH9S1pspYY7a}37ef4uqU8%9h)3OT95xhLDa7w znFuc2zYlH-j;55Mz(c~`&L`msea5;RHcT$>ueLx|!+6{tD;<<#I_+lVSgW{z4#3^w zQ{^kdQHbZHRtW}iVu@pv2jVgO>Vd?O%hu<>B6XqO=>n>iEO~DQMQkED&P|VM55={f zA4YO5m1yO;hK^;kyWeCBO_=Ob*90Ul!6e7OkM~gXuVh$=D&eTM!wX}@M_YWH+S1g) zseY^a>vXzbMQ80xXX}mlBq$IoO_R zM%a3M)7-=bWBifGx&2(++*JxY#f3o_+dkq1Z$sJFeFbTgSozD%TsTaKO*)U$s2aqW zH>r*~l5ZGuV>BgtZc_(dweB^(CqWEc-~6!+OiHf#?Wm4ZsA6Z3ec_evtSgr} zT6j=hzq{K0sJ=kx_R4b6J$YC^Lh~8+0P{-F`OfCqS!8+58LB*g8%MnI50(nCI7$hF zl&DB2KT#YB5n={$*K1Csz6Nbj<5xH!VW11^Utq_vef@Y+wa0(Sv!KOnoZxnKkUNSx zu!=)us8Sy6<(7{U&~rldzeF-4MbxnAiHw)H_I*7SJy@xsI;gtEbi`cYGYPBBqJte{ z!;-SO_G7Ey6}7h!22m@rt;c+Wtpl*4NcK16q3|SW)qCdioG5krp>7G;#tOs(q^+`esdc0gTqyy? zVv|7bHk~xy_bY=z384ImEmeG{=a1}hm;pLfy`eCq)?e3Z^3;AUCi9|K{%J_n;IMld zjzgABAHNzDZN~{0y}e$jikprdthk@$_JG}6&m=h&X1tU{Y+sacbXAXinM7;+Tyw*xGuLpFQR6#@}mom7*-}k zqDra{VjWpkFG4Z6oDhHBFASc?4rojDtQI;yx7a^8PhtXj{t&KuzQ2fmNT5b5B(|Lm zaKSg7(#|W4^QNA!5g?iMlt8DymB$i`reuD6lh}3%b=Hw@+yk&?7yBZZ>~PClj#N** z)>?qr*bT1iN$DC-#v5<;O2@f2The8CT0*3V3r%j zN|EP7MkyMngdT))=)>|Ai$PF^@Rh)yiqx+PpI_3ym*@^^gPzy0^vh}bXEh1vj_jTSO2} z$Pz4FL3kp&pa`PC8||=Eu80NDfWWFa0dpg;g4dw?;p?xnL17_601nunV3?YV0@XF+ z*dB$uH{cwKqr+l7QZ~liepH461(U-R(}JpEi1UlbI&(bQgb^1_myoh=VL2%;fYrNe z8hAD}c~&(_0hI>LrY@W3uP&1gFCyM#0xN0ZBhY?j$Db5$<_w=e`p9f@9ax45Rz2SC zVl4vsA{e|YEA@B`+9$0JL7&Xmd&M+Pqa-5(`I!KxrO^|ImF4w2JGJ%8`V=iMTsAQ7 z`-<5mnCuxHW!C79#fF+14DaPLygM(S%dZf3vjlIyl6e+Xi!GAyA@LH94WL>}%*eAX zM9Y;XQ2ZXyzs8VbnGxdxJ;F=53C+fvaPyLsvz@GNpyIR=>b^#){Tdd$6LUF1-)mIw zM)9%DfGm7rambRp>2A%BV07XUVVJ=N8lQ(b`;H~CFhNd5zdYqV@nLAiqf~*(+;fh6 zhgY6i-lJp@zYUK?WfB8rhjk#wHaX@ynR|e~naf!W+^PD^Mp??tY(_rGF-1frVY=4F z|0vZY%Bh*o?8{c!Zs+o?2mftEuvzFMw^QDX!GZHTAm;V%6?*Cizs!TP4LTu-ddg1AqmWHcE zmS?;EEGlBQ0f4CR#C4R$6N|7_T8Vs3*ZbOdf&MnTl3G-?uH>L*uCeD8M9ioa1z-1? zzKsNJQuWn_Lay_SkTPE(o;eKZ347H$YeB-=D;N_@K|>7Y)tqDXGhS5)i7~ryR*3Bz z_szb`E*l#w(+Qd`nq|^gz2)V>mxDD) zQc*34O}gU7*TYel0OY6SQHk}1BtyocYIj01pNa8F0pZE$SB)_#(9w-4Cq9-jL)keN zUeNpX#^R$I!24f7U=kV0K>$S_5)N zjr69_tw&(8$92TCpc-n zl3E{n#wrWLR0{eaF7aB`fgO^rcCwv6XEssjlj^!beRNpdG$pNa zjHr^0scq|&a_@_?3mwNWBP`jU0p+gw4L=|J7jx4gd}4ZlwOL1UBjQdJ%`TP7s~LPq zeixH*fD};F6h)5~W|Y+imCl>*^6}$gZcm)+a?4In;Y`JVf99UdVN!{3Vh&Ne zGR(kH`e1yoVVa{r+g%XaH{SNg|KJx|#}lh+&DHlu3VB9 zk`PApPO;tNMbdpGF_ZabDetapK2M^&<)33O!k!AF6umE9Po=!oLc$(WuOg?xQxoa2 zeHD;RraLQ80%B*^*vH(6{iHOK4&05UQQo8oTqSMVjrycN7Cmj7tO9L#BW_{N#Oqsf zWpvl>?HNup+e^>t{b&buf_vaXFxy<#J+HBaIRle$c+erC7Zy;d594~6@COE_3S5<* z@ZxI~4PZ$QI@bMzV=oi$YfEzU5HsV(f~_Qo^6CJsco`N{Y#318bjo_j&G4UwOWtj6 z&idj{1BnNuA~o^u*#Oy}2jC!JkCzsdpW6P$VOGh3AC-Kw zDYtP(iF>1jJvFAbUSjxWjAern1)nZfgC`k(l^fxG#)WxTJrZNC=KIQeXS<@o!4d6O zdW{!7tfqql)ijkQ0hWJ5&zB5a8%Gi~O$ca*65=Cd0Ku)ihFYiM1I6TenRHfyF64Wi zWA15t8HjTAaLz&99r^62D}g~ie&0Fyl~;C9$;*-f0@HBUTkJEVg)iNpJdrVr*!gyR z{;(Q`V|428+8~4A-3XI?og!_kaoSqg^6TIJ?lN%~=@2Out!Z~XH+}T7@~-t4t6my_ zrNP<6tpAPnhpImL(VDYjC^QJ-@<{}xzrQ_|=+y-e87aN{n!jSpcnt}c8vC>eL3=b_ zhP>3dZK<2U?YJ477#TL6y74^~lD~X0yL()Xtk!p=Vy4hRMD!_4S3(Dk8e z1D2BmNDE4Ry#3HRN5dvUZ4WbzSR|dT7728{QNtrD@fWj4YmeI|s?ERo!hZTN$FFgu zDv762#&R-QWRcj)qXaGTJNU|1t~965X%+en7F7CRaRu^^LMrS|+!h1#Oh2n6BZ2q( zsRImY2nvb4y@7&G1O)Ebi!56Iwy8|u&2FPe2OSq}Qa0ilhJzBmV{ONku3}YFkN?Q~ z@TzXyF(tF=CwaYdU`My+9LF>GqwIXX(f@p6*JJSosn2(@v0*4PUyci`M1L!PB-7pu zJMP*6v#L(YDSRzhqX8;|5i)I$9=D|R^9G8v2`EjE`fbz&(PzhyFzINmLsflwb`~p zW3I4kb}VE63NIVusf-itPT*bBj^wE5)izb zqJ}{|K|#YeS+Ptw1D$X@r}ds{RDTzy7C;X&lbFQyH$Iu#vJf?qK6)i^`3F|NDBfOb z`pk=;m+1L^gL{I%B(1XooVP1;$5jF&>Ei9WOouM0f_pje)3bcpzVQ4-!k8IPcpz}# zR?0ml1wQpq@MBk5qWJl>lxzvsG;IxF)=JlJ?M;I(&#!!CF59}izC~VAGT9ExjGyY5 zyufL;qU$8#X|$*Orh&(9#}A1E>hnHMd{CY!qg|4}NOtm)fZzfl z2*PlLMJnQ>T|58?DfB4NPOz#c0)L}cB1X_0pSBg7O`tF*I^|m2Wsb$Kot--t0NXQb zb@MTGrKYiZK$Oj>Ks5j3OLTa!ZnpGzKq6DN5F2hW8Z7?ccLy_a2;K~&`huLmd4Nf; zANRlt;9$95dDtBL{bPFAd6_)caWY6zmnb*48O^8rDhkRHE_+At97iBtV1Q*r-p`Rh$!v3IvcAzOvM0FY2m=^bue(_SA zJgbN99qfOl^Aw#A}39JY>Tsu8-K(L931VdL0D#B;9#iqSgQ__|Gcu_ynaW4HZ851GznW#h(>euSq+ zT*HAvz0Jt@$-AbckfDDI72^n3zd^SsU*xB#(Dwt_gDOO*MwFs63ONb9+?(I_Pyw!> ztKbJ>tZM+qDSK4z5i2Gp$Djg2o_;Rb`2$JFE5oxVRaj)+my1AKO!Vy+zOW7k!KsUv zDe}*nai+$uiT$*)2ZA(OQgu}O8T8rtVevT?n0zN_A>Dti?g6@+JzKr}B=WE&wc@zl zOMX5_!_6416zr|f3#`ThJ)O~+_Jm9?UsZVSya08<=G=^-kwT`R-=Y^Pw(}8kQ}&V> z0d97XO|v!Kz}JGZV&%fr#QU(#^5mqleR^6;>Az+=+RD>vAy*eY-P3? zG&YI90^K83a?zmUnP6n4sQoH@Uo3O-73VIOe*lCUzL+6;=;xHxY-V#M0LMpeQ+qqQ zJs)hJ?iCv?Ko>s@pZeA98vw|2Hs3cFSSRI z%oz8W(-!_?Puu>V=d5htB6tskmsU1nJ40pVa#v#cJG6jEqzm!>1^5WsQuS!<+p7`Q z7YtjPqeN`tI>4bNZ169{Jv3Gg!hQ-l<(a&=MeCjhcAKy)7rYiw7I%S>g$KVHhiKbh zq86Yi=F$T^?Y zLm1_KJ9;X{ny|gbVUj|4s79qZC-k&ntXNHJWtOG#PfDRq}1p|0+l(i-r zpXK4NL*^?cz>KY66BPVCXJ51Jmg^WVub}wzk)la~hY!BEwcqyxE)Ffqq7R!&a`@x0 zq7M5BQmKis+)}|;#cLNR0msId#>WI>`+juiiI$30{}yO8@@UEV6w1uvu-eEk$GfIW z{h=xeRX0x~^l81w$u}7+af(346k=r!#aX$wXEC)J+W_)+Bu*~_WYi*`1E9#((G|^O z?Lj0g&dJq`=W&eF)|<7)bwXIfnSR>U0seu6)YpQB3tMM`#3f&s7u5Z0FSVKr52OI` zPV9mz$j;5OOtk{j`j(#;LN*{Lg}daAhtGdf-1dlts5~oWQa8KgxR2qLFGA6#Jn;>z z^POFdcab~~J@M@@7cTrDQXvkP%voP{F|rs`a&Cr_Pv9EcBmFJ;Avpycq|MR6iM*l1 zdPE$ft&V3IMK`snGJ)uT;dtKeE7YOQ?i;jyQz0!LzLwDJD3{mb9p0B*?5+Eyw$IEj+j==i(jz|67J z?&%dcRg9p-MLsx;Z= z#@#c~{>DvX9~A!8nC*Q2uF@xu-BV?ke`n{{=<`#j?lpgAN3I ze~XLYOoT~l!Va0?KBwc$Oksej zE{GW8?Ebra>V6Ch3tqEe$;Ei`CV8p*|BcJ7`N_WCF+(Y8LCMi$$kI|#fJ+ZrzJ?WU zmP32tlk@Pw)xxOtb`g(j4P$a(mt9L^f>mCHT7e9apMsG+N(`6)yw-6+*w>NsGf#5B zrv>-XUs0_5YiKsFhU|{UD|b}zyb52OQ`;M9<{ht2zepxtiTH^HJ&E^uDKmPr?zh8* z?w<<+KF`c9|6*IMN;az}#G24%sr zfxDR))%x3xqr^7ZSG6fS+`egc#b$#~qZt14-0-%R{nBmiDcpSisSKw=L3%Jj<=_ec@U5Jz-x()lVOT?_jfuN0xr1m{X`D*o zwn1p8@2hq5*Co?2KZvsZhUTjx-75xV!iUmHj0I-^$%GwX&;p|--T=30ka$Ug9J#6( ze-n40=SD=#CwtXF28q19G=9hxa{1~khU0Oc$4_NVMKmeRCT zn|qwXI6vblMzV}IC5rD5aK>qcmuoae1ngYBaBY~mBew#ieZ?#lzF!mIi^1H!>fn)u zjDvsL3mSnO$Rn^vUifPOOH=JMoDB;jy{=Q1@;FP3D--AyVu-toATHkVM?J7Bkoh;m z#u?$itA4^8wVb?>g!8}16tSZ~v1t$x2Mb+1Xo2{}=}3m@&0LphNPtTnTsv{LaE#tW zn<-x7-AokE(qF&y#|ThC%)%{>sXtxXy&NnzP|FurieSE0=7<4$HHspYBHJ#q;A`CBwCFkxp@K9jtC$pj#%^tr3`mU+FF@I_IiIP}b9IOTWigb{9MNyAl zUxwYVeNdp6V|J$i4feOMIzA8m>s?PpYj)pv=`6#P8fenvPA6&6&CjRPUCY~ssJ@+@act8TZmxgV`xWmA# zO3S&6o9Q@AO-hJ7OqBWG(m%LFU>vg&Rx{>mAgF5@G=Ht?J-Z(qb3pU&gHzhxQn^7r zfD;G^I_V}nwauAOlsTR^z23C_P`LQ)$Qb&|fi0*jx>Y(>4sSgJp31Ty>0?X|L$9Kv zMTRm^p0U=N%XH_p(wKl+-Vi$FB%95(Va-3U#mp^>Zv>dD>lWEjIJX`7wBvA8OK8zhz-sF}WN>TWloT}m>Vw8br6DRU#i!HuRn3g$ zkhbL9D~|N=;?S_qk46$=0Z-JfD9+&_b^@~2>X3eXIMb~|L`tH#x0;dD`%BmlcU>sV zoRWBuGLgZ9Wv)49?LIR;yBKQ0C|>5J{%pyE48OniI`7AT8EAb{8^!eF;lVRlxGG19 zGzfSKuY;P+Va^SpH`=3~q2XHndd~p1A) zdXQxG?=}8(7u6CuHV)MvmH$ab7f;l~mV+X?&4ai)a31ETu2TxvczA?+0;SZPBxz$GlGAf)Wq-R1 zXydhn_GG#Q+6>mh8M{u-d5_Kus}QUZeu(dNpVHi(^uvRq@t3%!E5DU$MM^nY%mKd&b15}mqN904gKZKk$RtoyOVBMru zK#rh*$D@vmSjHU6P25X6>azt!Y@U6}?ZUn50#l%F-MzcKtGKlDo8My{m%bHAt#?A#IW4W? zgVE%b`7hNf>QDuuSuDdYtH@WVHCI6;eWg16&b*bxtYrLDJ|bqq1Brr)ceOSA!K+Z5 ztH#~>wMV_IkP<+O_;uw?S8!vLB%W*L8S+_LN&f98?AuW(`2~yYW=<{|ov{s}W`Iw| z?Hxr&rr`hu27<;>fzUR)7Mm_@BF37!$P4Ty6!gb>mDPJjcTlW5U1z;{qyVLX^gQCy zR%JHK#YUQ`)1=xnnU!0UJa&5)DiuJ+BTiCiyo@T@1=C#`?E%)36;c-)(!V_9G0wZ_m?ny^JO zK`k0{a}x*ZTtXi?s|w?`NhY#H(*K+hC`rksW#1bg?U=9#a!PzvNvi^!H%`7X z%mZHeKQ136%-6~=T>GWqb2vc@jh7v)Sd3v zC{$p%52TM%J}m0tm>N?G(GySl00}bI`JA1Z@?u9~?!24@1f!5bD_ecK610)Yi$n=T z7Smspccnnb-%Xq?t~+eME!b${CQfBaxD>KnX+Ljrqmk~OZKsVJ8Np0Z;OI?n@=UwMlqKl4HTS=c+MEMT(%MtYMm6WGN zn8;+wz70K!6zT^{@ zy}f{vP?GsOlDlrm(ZfSp;pY=Fjs`ccC(96Gdi^H!I>DY`?%-Y!V?$v8+&*Uoy8h8h zS75hEHel&fMI9g?aceXMd_27+m$CTWzOC}J%YsoEfQ2M{iw0A$1-h$`S;@1u^5Yk> z29h{TA&MZ-M$2sm)bt{O!|yrwD?pYpt5?Qt&={WChDWBb$2W7;X$>)2a1_6 zZtCMaE|=qg!ePbRjZmqRjtn<2`ajiNL{BpYW&Bh5eO{#;xFYfMHXXlnDkx~-Mf&>kQtj318Vlz;t!g@-Q?;K=9 z;^GCjHx+i2yGTPQ037L!#3#md5=&48!iey*8(I-wq#t%T=*@{+icvj~ESX1pvX*;) zljo(-O}z)nZ$o%=FJbjbM(z|f(ANllG%!v0+?;RIr&)qCF|^C~ipP0;mW>;|j2F7u ze^=%?CqSI^HqsSQMk@j&noY_e8494R!!Gzyl{s}lzgZWj&pJVC1+dQXr%F)~PWsIr zqCRT-xwg26j#i;J?XM!Mi`V@5Upyc6@FZ_--WEyvaWV|L=@3Jk{60gn#0ezstfT%( zZX*Q2nI4F*mT*#@F?y%T8B9oT++QGsw*+K@z&Yo#X!~Qqj)f7$dhY-&K+?ZC_94Yb zoFK6tC9Sd^W6)X7nlv)CGgMg}tfY^v*$3C2Y^yCh@M*z=ANjbcF7~Q4J7DCR6u0}~ zg`7bMo`UZFhQ(I|ehI~vvDl?CME5Ft16)wr`yjUAWN zq}|PXY?vKL6&_C|RlbRb`PA{Z_55y^bF;zyv=obLk9gwMVSlSJIM$BrpIrHDeJnrd zDave=t*ceAD{Szxma;qje&7o!Ey0{xxwFM3N3c~#8#7>v>aHsDl#xE(Xz>>{t9yOz zshoWTHneyPPrFBpq1=RDN-;uI7W|(QCVjF^`RKax$tDAGb>7>KR{1~tY)Z^KMqMj7 zp(Z}FZPV?QC)2H$h9M9RPlI#kNS|WgYPz0=?&vB)yWP!^_5gtEqqX{7kI0wZ8F?^N6%)r!h! z$kzijOnd}VH2&y8m^%*`o40YWaaY7tk$VI3!agT(e9~trnh7D8@_Dbg^O*zX3PZsP zBOr6eqza#EaH$8SEqQ;))Ne1F%z6u;!M(_OdK~n4bmz${)C_hoPs-@c8@HN_ z*6@8$+_X{aJ>5!Efd>dfg7{%5=`V~8;N{t)Qo4UF+SY#Qkv)ZC(-{ZatnOfCY)293 z-TLcAe}UDPTV9`ZBj-rR&2Z0$kF>f~2`5o+Z@4{8bHqTJ;_XhFeu3VuEsqL}pYJDW!Nd_B4<+KzQ^=z-5^fKAP~Hu!a0&Y<2F7z!R~uSgDE zH4V9Z(vQf}+Pt3_LZ{MtSuI4l5#g=0Eyz+8 z2>Y8N{_se~Cp6CM!`dV|Uq&uexJlPZrC`|tBBa5{*6I5h?xvh2mkw#7 zAHb@H)s`xE4{15w%V~hUOb+*P&An-h#L_=B?|lp~tf9SwkABE54TUrUZ5YCg#g6K9W^iBKCh)vxrIPvXSZG^aN<;`9K2}%g zcTiHw`;yY;(JtkRu^R@62Ga4bT==fJt`RdW!x3>xkv5%g#aGhn&hhues2Y79Q2tDR z>T3HS$#I_OUE)W5PnIPN+j)mjym|$fBoTOxWrKDkfws|#@kEkP(99;k_zzC zq&I?ci3RG*K`wfs1{5B7S{voLs~3+{FonUUCPj{DC-o34fa`bRBG$8e{Qj+dSs>D9 ztDptE9CYF)Sz88RipJO-J$yGQZu+w^Q8*s~7F)*#Cs-|{V~i)gyp@Jw@|RkaN&+#i z>wB(j&ojrR#?nYt3B!2w_&V|_J-OEqkWnP*>;O%rO)~E+CC1-eQBx0(WB33Ps8Agj z%op`$GK6hqv*n)R+s}EC=E;oK19BfL6KG+H5x?w>vOZ|of@FkdH`EY4&w_EV@QqV3 zUoaLT*73;niMil!n;ZUnO}9+v#e%WXZsbfhKE~zV`unhy#CJgQxq8d^dZ$CFO+{b- zRou|rE3heJ2`dy0v2Bj_EoG95jt_#ZlpZwfbG0W)2E_#%)mpmP^y~2RNvqhfNctgy z!{5Gamp3>Tbc@oE)t!#I=Li6T*n>8Bb|m5f zHnXN)c{mf0EC2hOp;ls!9iePlDv|C@xBGU6ht2svJTpxU@QsIb%7KLNJi;$EDMoQn z*Y^+^$a8rYDH=gPeKA*1J)3QI2%~0UkyC(Bpz%F$Adr6^-pZ4O&w!>YxiioAd}CLr zd;93E-*6;e?89;ktP!xGQBnYASQ)vw?OYwEuiq=2O4w#!D;HS9Dsf}Y;FqqtI<-i2 z%iV3)DapVt$6JF$3QY!A<3g4g*^1W2`g0?io^akakFROI93lHd`Te!{|LGJ;J+On$ zemV~P_$zT)cqf2NRPl#Z^NnlScN&hyQfL^3C}!~8*r}p2#v3d`_a|DQ4n2rl1ht-5S zb&IxD?w5wX!kah0A5%vQi7dCbl&;bpyxhw zn^+y3?_p7U$E(=lHLZQVIZGjEAA1+qZ`*M4{&D?=LWKw^B?xD3LzyB19Z zy3Y{-t5NkDT8|=0+B`sOEJCwmt`HE8+JlUOJh!WsYhot0;s$>ea3e)#AOyt`?XZc3 zwY8m=S{35L z&@8E>^lOO`Bn`PaFqTrJc2_WY=n*xuU!cW|tV6xNVHJE534Z6U{C8LL1UXuK=d90# z`O|Clr5;o%zuhP_r`}XZNY|LEWDQc29VvO(1Pu@l0dW8Yp9+SF2Fm=9OchH zs_=K9e;a;Rvf=XWo9$snQN_KSPx>3t@4C7`6{{?`XTa#2o8dd?*o<`edD*Ze=Gz4y zV-DZKJ}H$2I*-?Lk6z6w1p(3A>aHKe%;4fwY2>d2(1bwPNA}_xaTt5nK<-&zzw_(wBamji|!mgxp$`sGH6LHS4ifthMd5*3j9z8lTo| z=!qY+;eom^h+b zYS>0LWaI|+4Es&+_yWWcD6?q~;x_rTp}>h<*Y7XD5b*l1b39(tC0Z6$&$TE~>t~Tl z#C<$Agn`ruR_p)-QnwhLh?1TmP1Lp#yyJ?v6}SzJF4d27j~T0p;EE2PSYV!e5bMZ0 zuEL$4tH?Gro?Z8DD}m?j({*7{y_$#aN1=aL-1qt!YSJNkUXv*jchKg6! zh*p>^RtH8*v22L^{Ltcoqy)9U!^`HARUg&bS=_HmOl#4ChoSFp+;H_=gyoqLKH1k5VaM6YS*`FlV9T`J>t*uI0+z~2Ok46M2mRON|?{p9dm zyg;9rd+}NtZi&ftUJlGBy&@)OLTw_p3FY1R8tDM0Wd`k4&*~1>TY004ShqL5C1>+mUxBp@xNE~Q9By(?` zc$wjh=o~gvfl)E!gsN&woJKMwu1;BJo;vbvoUz7&RZ!fCPlMO5#h*{TLP-)qSF1%X zo|F|Pu}dkSx-*&4uo&%2=L(O6*q|~LSV6)M*Gs(e9;*OrW(W%0wX^h`2vc{eFkp{X z-dlW&l2_c#B0g8#XW9sk%khEZJmmeA;tY=$nZior27rMZ?7?1uFaQkCVU9H}N9Ko4 zWUq_aDNSMCt(CmT64U5vh9Am~qmgR`cKB^Gy`Ly4=Gc0|B_4a$Jj?I4jc}(rYC|55 zx%FxuR9F{Tq`#!(hOdi+4Sa72{ix6&HE7U*#GBue41&Exdy-;@{;2a=gVh zw|HVZ3m1e9f3l9PA`;wZR9LUa(#@>pSQ*2HbcHs>nhMpqJ%PV8Qx&Ri!9r)8`T7or@W6i@wz~GoBEy!>E z7q@oz7DP!N%6jQO^Sqz!7Re$6;j(JXboA24$jE=Bn+aMSY~fPiB24FQxIX?V2QRA= z*I=J}@EWe`z+B+^s}bPf-GrML1xy*`5QxaW+eV3#yfJ`ku*P*dyfB4F;^lB&$h6~b zd07pgJSPeJ^F9E2iTxk_w7xsvo~xRhDmB3fp{DjgwVFC!l!)FRa&k*#YQVutcWfo-Bnjjq}ShIHAvOzpT0RZ6E8dggV>NN2De zN-mibEXRI^m9u4XHWnYDQ2+^~{K#1y9w~_7Ox@tO-a!+ARkEhc8t+MhWhXo4DdQbO zdYzPWln+~YruXc7WW^jJiixg3@0Jk9mMIQHflp`7Npi*3H5j`izSIK3@ne_dDlyUR z$u8cfvr2lViw(;EzLl`79_n5myH2csb0d{ zIkHNH?s(0K)Vl^bAd>adBm1j~@mF|kO&*NCDa`n8VpRK;_{b9Y>K;>-Qe`>{^0BWL zkkF2jv}opI%l+n>R*CMYF&SJb5)8Kz()A7vR*8z;6LvAQ z9JiBEJj;46Gw5C}ib{0==zN!l_zDt<_O_+MRM)992MK|+hYwxO98g|R@|aqV8Bh7* zY}@JG9CGk6EHCO;_i@fAteqU24*cQnaslqNM;?+|Zp91tgL#i8JZc9{Gc;CkDWnO# zGoc#7wu_|vq7s=0fc*lhhn>=4-qp|!l|IoBt%cv0?N_mV754#MnO&_PhVA3f%t;{rG)i{MapzcZSO!Dadgzu24d zO|&Fr2eHS`_Znj!*_#e*GzNi7?`ts*SSqHyZs!V~t;qkPFZh%=ZN{lgi5w-6E`*~8 z^%~~GY@ztUNqub-T#T9-&gd-XH3n^&y1b%tHPiOl%$>~yqoyKfcqR;;no7}WJWG(V zUr2m)w*Fm2Dz3FBgedE{Sv5L z2z_ll+E==fof%p5CVJdf$gE%&ep4&Ica3Q(9~&10+sHi1`~k}nw?0N?(Kh%9{5j%P#mQLOWh zr^~F7+Lw1qBBkB1nOr<}?c&hoY+jEFurQETQ4*&$qa*Bh7i+Ansi0TE3?j!Tl2^ zw+$Yq6-bW+ezOOIHH!2jmP_J#nX$C zDJfFrgr4MRmpuFtG<}Njz|0;Rm9SF@f)QdG4mzaG^B_`1F-Y(!r5aD6AmN+0bn^rk zcFC4XD>5!PyiT$(3?aX#LY;r=ZF&oJ&P%}Zi5T{%uCHKK?FFVxAlu=-VdHx!cr$!E zdx=T6+{Y!>Ut2KE^mZ13kd!*U1I(Nm#uz$&W*DaOcP-u~fa=pQb*ou?hm05zl7k(; z{s<^V9M1n0rB{JjYJ)*XYl}m)g$Zs`)CJz}_TnkCa==1eMS?(QuX>E{`2$T9u+4y` z@UnOy-q7-YzI$Hj6n^E|;}x-(cY+_=a~RSVs>@`b*&$xGe9cyGZT%Di$jNm8(ss6| z-E_8*Y!M!MoALfIhIS>bhU^!Z6I@VST12rTuNkN9XBqYw&irC*)RfePEk{M@$DqH& z8D=QDlkQerl(;;Qq=eNn?$0n2|ACw#q(^TOB(krGjrqGVWAaqLa0Q{2fuZpN3zcmG zip&3_*zZMK4dd5S#6?zmK**QUKBGEMpSj76?bhcLz1Sj>TyQNyy@}2QIcD8s=0?E& zXX=nv*=Tkqk& zl?m-aH(Nj%!6BTqkIfz-;sKR6^y}GNHeGWI@Wj@&5BB`FTSm4c* z5Fey6H0&?cy|NFDURGTYz#)RvL>(S(J>sLbDS*C97qt%#C$ChU1Ky}YFHQP_A%icq z7V!agkSGG#TG#BSYkjq`f9loTG*&`W6)eAiUgMUBihvh;#rtKjl*o{HlA2&hy(6!Q ze6MNjms4(|83?oz>UK|sAHJVXpxor`#+`Xx(6?!u85VlhJY=n;!W*079Z&0M7XMcN zPcC7%o0F0EZrz)3M?^>>3A~O;ZCe2iaR<&h#jK+f*t<~OF!~+UVMnH$xEp)oU1c2Q zQcnqRE&mgjN81=7Tn39+(b!k2uLlAt-e;U+ftMu^A@f^Vi7Au1m0&1F_RSO_cY)Wt zu4y)V**u?xXuxrl%txTX_kxM`q0e9A-^six)a8E79s zbjK{_{4TtDp~UQUr#_k4`(@EwXVWj^^X4sQRxJ+y@BmXlv8!xw+aR%`+gl;gCITg# zB3x7iqlc=Y6fI>h{@E8V=_39;_%(QPX*}Yh-J9^c2!1t8w?hO+iXQqCC3Mh zRnLF1vqOVUCx*`IoqIE;0s1}fjC>iwZ$duS!eTi|5zyiiTwR%g*)^dLTiZ87WUECQ z9@$l$U$<8PI4%=IO2$Z*e`wx%yMC4J7qC2F?mMJYudsFlW425Glu&Lx| zc;95qMcDryDEHZhz=ESw6(vRnH{jZmaGP>yGvJx6R`f1CC3^1eshD;gyE%K|-pSM7 z>yua>g2^~Jg5b>QU(8nLW+eKdT8ES&Wwdp5h-;oYMj<{J1AP&c;ThAPH3V#haz~KV z^xx&*a0+#hbOf0bZ?ZA9>XfyWvhe?0q%A)QrX=h8(V7oyBEAx}>V0V6Eub&MheVUh zP4;R|aYGJRO1ES?9}-iNAWEkp1;43d%of2@6!iJk2E^khhJ3`ym9tQfyau7UXkg$yRZA?Orekha+i5}``0CiWZNE@?rhnGR4JOLFj z>pmZUq5Dhhp?_U<)`R1b1ud$teh%zOTr&B()HRKG^%yW>DyVu_sCXuc zgLRfb%aG9B!mg89F#09n#^8dyKm=^(83a;mG+ztl8XF zLP_n9N@hYYwt+4T0bB)suNbsmhQa+2pkM(N7wbr=EKS&A zEfif}=yf=iLCR~d_c?Ub5B$nlYy!)@iLOLa<>7cP^;0IrfhM4hO?6+&30=Le;Yz~r z=#WOq&5MMrgspV%ei9$+hjER~;pm;!ZpCdQswj6UYCj_fbkmiN%lv61vimvSPE(Kd zV0fnhbX)HQjXdpqllB)t(E1{a?PqtyC$zpU4TybE!tu{HlWeTC+yk>X!xcmai2>BP9zwdGOSg6@;vpRpj=}1GKyaa`hdX9mT0w@>G4G9yP*H&iyXc0%2OD5L17aEh>_t*+#Km!6^Yg(!Zh z4ov0Ys}qrp(srn^#CGS6w^c1oN0uF{~4sS@pv7=*B$-K{C zpu#1J<=?PLXgakjA*wy;R@M!dck7F(SVz$pJDljKsC8F5Xog1ILKyxX!p&WTj!qt`JF(X!|)Z> z{9Qh<0*2&bnSeSSQy3~#H>wOL!BgkzS&H#0O>Ze1ntOD}7O&p>=>1QSb{k%5afnt9 z&?^K@Y;_y;9@6?Y5|8wP!sI}bRWuLMG;oL-i{=mh>jnzl$#snwpw<@(Y`AK37F`EN zD9>58MzQIGnr^Y>lIP?w*gb~}cLQg1^iu1~2W{nQSt9!ahU!;i?xct161#m6rVP(Q z(Tl6}%<$^5K4i7y;TnvUfMq`rD0;)Niv)Kub|l(g3vdf$YWbGqFIZ}N?l=;tTL9`D ziJ=I|v0JJr!t}*-k>jYP8dsaWwzX&S3^gKPB0)W^($t98U@ypuAmEbVkdN9hnp4kW ztS7I53G$oto0CFQ;|tHn;F+vyXiVX^4IaE^ufA@88PdTto)L!icSbLU;yN%pnfS3%SmP^Kd|(c_ICh?v-P{0MC!E|CBj~l>iuxmn4K`z)``aEVJGQ-WXP&~Cz2)D=M3Q)1N z3SQj=0IUMd>kq!Xf0TTy=rQaHd0jX{7SAyUu=DEaU#MFczkPTeP>B9gx>Y^BJR9O+ zaY9~xG)2GbVXJ`n0tf7l{#q2$eWq#~!V(OSt}P;&GbNU(-sYV7E#gN6#mYn-AGZO_ zJ{hHt*g@K0pzx>sD!fq=RKFYXWL-Ch!H@xi+pnk*Y`H~{&!56xSbK>ch#HTmv~KFM zE;->Oas9(G9uY^f2*%b@eAM`Xjbewe;ox4!@$Xt~mEnQ+Gb#nMq?()DQyV7_5T!L@ zX>-(SHt#HqO?$MH2eqtqWLXFm{}cSL?&!J; z?dDKXvXw=&+AevOxL?CdOX_bq+Y^HQh|D@8g?1W68ID?DXVdHQd$lVLYhR1;sF6pg zf*ZV_8O*S$m-3NhJTyi{iLWDE;J#h)G*Vtx_dBW^o<8pSRNM!=gs;+l$s?*f%b=R$ z&IE7Ls`BAL^$3QQ8qF1`VwFi;axF)$-_hl^)2%bjM=*D0&=$%MW(Z}pgO7&mn@qtQ;N|N zH~>+MzOX@j-69dR_HAo379jt|FBzj~q)_wxiD9mi2iFp-rH|oulkbQ(HRhTRgqziy zo>GS@h!-Kze0g{!0U|MMpu_6AN-R}TnSjmQikr}~T*U|O;Y+&v9`*ME9uas`I8?f# z0$%6*vs#P_(#HHl{LDN9Ij=&rBOFHQ@<;TKENEqf__@x^YkG3Qs-6UTG;+X&8^1N2 zH=!V7guJNpN8hOJl1O*N-2Se$8*VIBq^-{dY(P2q)I^?W9h4#Wd>Nq{C49rJORP0S zqQG`*Q>qWIh6eU}TRggGV?8!a%%~GUtM@7$`rEs|-Dxx_(ixKbVSpo9vltmGqOZxN z1G%4xQNDl?&Mac3XBToi-J`i5nEd+Dpd{2O;XX84!L5!sV5yP;|-f=;)Gplx6P zLKZeEHg{-x&FZoq7Y>ON&v452p4d+@HFrZDt?XJs@)+4qs15wK3|+ktr5}q^qtkI= zp-5>DmTqX0n}&|qn6?HOT;uqmj&6{v(ra)lY4A8^xWetXL86;kzW6m*d#v2WHDjFd z%0lcDU;;=F_fzV!dhE(1NCo>#5?E;gK#_5t0}ko}4hnyWML?J_?6s0L5sb9c9e8_k zv_5dCGZm>83&qs@qbq@En4Je{30)wJpA1?crR?H0sgIc>m= zuvNND)IT#{6XFMr*g6`Ji=jMiZ~dMDch~ZjTc5om&N*O84popvO^OQa%mG`&AvI5_ zV<*-w-MQ<+X#dim**m#BNU+mNt)LLIhnTFE-+H|cu0EsP8S}j=MMADQP%*SBR7L6j zPE=35SbWcH8&){NpF(F|LfSf?$|tZ!FOqqM$Kx`-mM3wah`5 zlOe8)WCbpfSSH}-TF1HbSaJ$hp;2x%qDexXu<1l)ce8^edCqn}(d#emFOC@qMH~Xd z&Tn>OV;rr8C0L}D5I3);K!-xY=Z_D>dOt~>>wW>{$)ZMHkr!6dGN zRmIoa;=fn$b{l?N?|k~PTUHyFn~q%u>cCZ^acaM--<7+OwHaxm)2=0((S5U1JhVX$ zHOZeFL$DgyKWu_l@OCp~+|0m~9BsR|2!ep}kH@Sj*FdNjE=T3i3yel7Gqk7~|_L4t2#&Tdd&bo_%wi1e;_`w^*03 z2nMHEy3sr>LsbU(4CTct>Xe6$iUre&`T9@t5GJJa4^Uk6o&=S3=^M3-2HuuEO$csx zUg~kN&P6+={obL1!F}B?anoK6MN~lY7ERZh*K~Xed!#}CV^xWrxgO>ZZ4o;J(W@wb zwX1>Gr;=(PsRh{m#hGjobE9?;k+a}-BdQs_-y&6V9f;t;w@y(8^zw%b#ND9GwUE@E zU)T)jmJC4i3B{{92&%Eui{E9lmT=yX~ z^Ty%?z6b`S!vZboluTWUm1N?a+@&C-CUDHJthp=rCQ4~xQyAKX=MrBy;fPxy)X?oK zCEZ5m-RB?w@?SBf8eT~)NMr!wXmSx&|C@xUbi@r)KZbeNpW4AC>$>0w!*O{#}{%YNUheZf#yfUp zhX(WO;DKr8VX8WgmC*cteg5Do=;1G^C_*@!xDvn{Vr43S^Eri#Tru|)s@^7T8rNY9 zG9!C0fw6yZX@RS9c-bRPE2AY3;7`mwPh+~Ob$qxWBvr-b@7O;Fwr; zTFz6j6u0g6E%mvNIMCfWl9gJDe>1rEE_NXE;hJ@5q~j_NLEY(ii&ijw>HCk|X7nLa z*yxIt@&h46{{e5RuIA-_*7DAsqCy!P3yWx7)v83eeRWrpV2F~wj!xkiYceQKby5lr z!uS@~G=>&b^|{Dv%LFfxrWJ>Y**87At7E9U9}w5>VVa2rYWG)^^!c0UU_1iVPY}8; zrda_VFb~tQ>U(4IM(kdq$f_+Py9nq;_yS?2{j`YrNfwG3nTM>4>S91$FBz7~UJOtU ze#@mAp?gFV{70Jgw7%R22V_0CV$gESCcCY=$J55tLM;2{fY>HgW`LkS%_)5kC^uO8 zGv5FBV@lk!wPFoE5z^!A!h$9UiEp4Vz^!;WqkU%L-d^Tv=s3}Ovx>q{gSK8(&hLpX z1~Co-Y4W(F)LFRZ^cJ}@qlghCVY=VH-4`8#DD^xnwclZglSv1&XhbFcft-tOtXey!0BoHM#A2w{l?r9CoD zZ8FG`?gm5mrLji&GabEpA{7B6um4_b!TnrWP%smFHXF^M416pxr>ZyDSRBH9eLGQI z=}4dCi{C?EuqEbeA&3ysgrw_+wdP}-cfqO z1`-0hBMZ#s?u-jgR^fs94npkupudUgzBtx-(8=ejG1I|n^H+6Ub1KjHnRDb}w0iqZ z`b?d~F4T>8E~_afl~Z>^%(6gIpM{VV%nEjB#Bc($ygQ*9@E-*h9TAuSz>l*8)KbGv&y>5`>T0q*nvIUiH%0Da>_S%$)f2 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²?as8ujj#o63#y=MxkO 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 literal 0 HcmV?d00001 diff --git a/test/sharness/t0054-dag-car-import-export-data/test_dataset_car_v0.tar.xz b/test/sharness/t0054-dag-car-import-export-data/test_dataset_car_v0.tar.xz deleted file mode 100644 index 34eb36dd1ca05c430c269e2df2c7179f6a2c2b48..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 379056 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%0D!~Py* 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
    ;miXYF0 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

    *E%0;c5IUTNlCw>Z4|7Iwu~*@3s` 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 diff --git a/test/sharness/t0054-dag-car-import-export.sh b/test/sharness/t0054-dag-car-import-export.sh index d795c151d8e..6f32cf27775 100755 --- a/test/sharness/t0054-dag-car-import-export.sh +++ b/test/sharness/t0054-dag-car-import-export.sh @@ -8,7 +8,7 @@ export -f ipfsi set -o pipefail -tar -C ../t0054-dag-car-import-export-data/ --strip-components=1 -Jxf ../t0054-dag-car-import-export-data/test_dataset_car_v0.tar.xz +tar -C ../t0054-dag-car-import-export-data/ --strip-components=1 -Jxf ../t0054-dag-car-import-export-data/test_dataset_car.tar.xz tab=$'\t' test_cmp_sorted() { @@ -246,4 +246,21 @@ test_expect_success "ipfs dag import --allow-big-block works" ' test_expect_code 0 ipfs dag import --allow-big-block 2-MB-block.car ' +cat > version_2_import_expected << EOE +{"Root":{"Cid":{"/":"bafy2bzaceaxm23epjsmh75yvzcecsrbavlmkcxnva66bkdebdcnyw3bjrc74u"},"PinErrorMsg":""}} +{"Root":{"Cid":{"/":"bafy2bzaced4ueelaegfs5fqu4tzsh6ywbbpfk3cxppupmxfdhbpbhzawfw5oy"},"PinErrorMsg":""}} +{"Stats":{"BlockCount":1198,"BlockBytesCount":468513}} +EOE + +test_expect_success "version 2 import" ' + ipfs dag import --stats --enc=json \ + ../t0054-dag-car-import-export-data/lotus_testnet_export_128_v2.car \ + ../t0054-dag-car-import-export-data/lotus_devnet_genesis_v2.car \ + > version_2_import_actual +' + +test_expect_success "version 2 import output as expected" ' + test_cmp_sorted version_2_import_expected version_2_import_actual +' + test_done From 514411bedbd7d22d277d31f13d8ad312224c3ad4 Mon Sep 17 00:00:00 2001 From: Marten Seemann Date: Fri, 8 Apr 2022 02:06:35 +0100 Subject: [PATCH 343/414] feat: opt-in Swarm.ResourceMgr (go-libp2p v0.18) (#8680) * update go-libp2p to v0.18.0 * initialize the resource manager * add resource manager stats/limit commands * load limit file when building resource manager * log absent limit file * write rcmgr to file when IPFS_DEBUG_RCMGR is set * fix: mark swarm limit|stats as experimental * feat(cfg): opt-in Swarm.ResourceMgr This ensures we can safely test the resource manager without impacting default behavior. - Resource manager is disabled by default - Default for Swarm.ResourceMgr.Enabled is false for now - Swarm.ResourceMgr.Limits allows user to tweak limits per specific scope in a way that is persisted across restarts - 'ipfs swarm limit system' outputs human-readable json - 'ipfs swarm limit system new-limits.json' sets new runtime limits (but does not change Swarm.ResourceMgr.Limits in the config) Conventions to make libp2p devs life easier: - 'IPFS_RCMGR=1 ipfs daemon' overrides the config and enables resource manager - 'limit.json' overrides implicit defaults from libp2p (if present) * docs(config): small tweaks * fix: skip libp2p.ResourceManager if disabled This ensures 'ipfs swarm limit|stats' work only when enabled. * fix: use NullResourceManager when disabled This reverts commit b19f7c9eca4cee4187f8cba3389dc2c930258512. after clarification feedback from https://github.com/ipfs/go-ipfs/pull/8680#discussion_r841680182 * style: rename IPFS_RCMGR to LIBP2P_RCMGR preexisting libp2p toggles use LIBP2P_ prefix * test: Swarm.ResourceMgr * fix: location of opt-in limit.json and rcmgr.json.gz Places these files inside of IPFS_PATH * Update docs/config.md * feat: expose rcmgr metrics when enabled (#8785) * add metrics for the resource manager * export protocol and service name in Prometheus metrics * fix: expose rcmgr metrics only when enabled Co-authored-by: Marcin Rataj * refactor: rcmgr_metrics.go * refactor: rcmgr_defaults.go This file defines implicit limit defaults used when Swarm.ResourceMgr.Enabled We keep vendored copy to ensure go-ipfs is not impacted when go-libp2p decides to change defaults in any of the future releases. * refactor: adjustedDefaultLimits Cleans up the way we initialize defaults and adds a fix for case when connection manager runs with high limits. It also hides `Swarm.ResourceMgr.Limits` until we have a better understanding what syntax makes sense. * chore: cleanup after a review * fix: restore go-ipld-prime v0.14.2 * fix: restore go-ds-flatfs v0.5.1 Co-authored-by: Lucas Molas Co-authored-by: Marcin Rataj --- config/swarm.go | 59 ++++ core/commands/commands_test.go | 2 + core/commands/config.go | 20 +- core/commands/swarm.go | 145 +++++++- core/core.go | 24 +- core/coreapi/test/api_test.go | 4 +- core/mock/mock.go | 6 +- core/node/groups.go | 10 +- core/node/libp2p/libp2p.go | 7 +- core/node/libp2p/rcmgr.go | 368 ++++++++++++++++++++ core/node/libp2p/rcmgr_defaults.go | 313 +++++++++++++++++ core/node/libp2p/rcmgr_metrics.go | 239 +++++++++++++ core/node/libp2p/smux.go | 4 +- docs/config.md | 64 ++++ docs/environment-variables.md | 38 +- go.mod | 25 +- go.sum | 116 ++++-- peering/peering_test.go | 16 +- test/integration/addcat_test.go | 6 +- test/integration/bench_cat_test.go | 4 +- test/integration/bitswap_wo_routing_test.go | 2 +- test/integration/three_legged_cat_test.go | 4 +- test/integration/wan_lan_dht_test.go | 6 +- test/sharness/t0139-swarm-rcmgr.sh | 66 ++++ 24 files changed, 1439 insertions(+), 109 deletions(-) create mode 100644 core/node/libp2p/rcmgr.go create mode 100644 core/node/libp2p/rcmgr_defaults.go create mode 100644 core/node/libp2p/rcmgr_metrics.go create mode 100755 test/sharness/t0139-swarm-rcmgr.sh diff --git a/config/swarm.go b/config/swarm.go index ba7b2255fd5..be420298497 100644 --- a/config/swarm.go +++ b/config/swarm.go @@ -49,6 +49,9 @@ type SwarmConfig struct { // ConnMgr configures the connection manager. ConnMgr ConnMgr + + // ResourceMgr configures the libp2p Network Resource Manager + ResourceMgr ResourceMgr } type RelayClient struct { @@ -129,3 +132,59 @@ type ConnMgr struct { HighWater int GracePeriod string } + +// ResourceMgr defines configuration options for the libp2p Network Resource Manager +// +type ResourceMgr struct { + // Enables the Network Resource Manager feature + Enabled Flag `json:",omitempty"` + + /* TODO: decide if and how we want to expose limits in our config + Limits *ResourceMgrScopeConfig `json:",omitempty"` */ +} + +const ( + ResourceMgrSystemScope = "system" + ResourceMgrTransientScope = "transient" + ResourceMgrServiceScopePrefix = "svc:" + ResourceMgrProtocolScopePrefix = "proto:" + ResourceMgrPeerScopePrefix = "peer:" +) + +/* TODO: decide if and how we want to expose limits in our config +type ResourceMgrLimitsConfig struct { + System *ResourceMgrScopeConfig `json:",omitempty"` + Transient *ResourceMgrScopeConfig `json:",omitempty"` + + ServiceDefault *ResourceMgrScopeConfig `json:",omitempty"` + ServicePeerDefault *ResourceMgrScopeConfig `json:",omitempty"` + Service map[string]ResourceMgrScopeConfig `json:",omitempty"` + ServicePeer map[string]ResourceMgrScopeConfig `json:",omitempty"` + + ProtocolDefault *ResourceMgrScopeConfig `json:",omitempty"` + ProtocolPeerDefault *ResourceMgrScopeConfig `json:",omitempty"` + Protocol map[string]ResourceMgrScopeConfig `json:",omitempty"` + ProtocolPeer map[string]ResourceMgrScopeConfig `json:",omitempty"` + + PeerDefault *ResourceMgrScopeConfig `json:",omitempty"` + Peer map[string]ResourceMgrScopeConfig `json:",omitempty"` + + Conn *ResourceMgrScopeConfig `json:",omitempty"` + Stream *ResourceMgrScopeConfig `json:",omitempty"` +} +*/ + +// libp2p Network Resource Manager config for a scope +type ResourceMgrScopeConfig struct { + Dynamic bool `json:",omitempty"` + // set if Dynamic is false + Memory int64 `json:",omitempty"` + // set if Dynamic is true + MemoryFraction float64 `json:",omitempty"` + MinMemory int64 `json:",omitempty"` + MaxMemory int64 `json:",omitempty"` + + Streams, StreamsInbound, StreamsOutbound int + Conns, ConnsInbound, ConnsOutbound int + FD int +} diff --git a/core/commands/commands_test.go b/core/commands/commands_test.go index 964baad9299..b0980f13126 100644 --- a/core/commands/commands_test.go +++ b/core/commands/commands_test.go @@ -237,11 +237,13 @@ func TestCommands(t *testing.T) { "/swarm/filters", "/swarm/filters/add", "/swarm/filters/rm", + "/swarm/limit", "/swarm/peers", "/swarm/peering", "/swarm/peering/add", "/swarm/peering/ls", "/swarm/peering/rm", + "/swarm/stats", "/tar", "/tar/add", "/tar/cat", diff --git a/core/commands/config.go b/core/commands/config.go index 7a6e5abaf07..3f009de9a0d 100644 --- a/core/commands/config.go +++ b/core/commands/config.go @@ -215,18 +215,20 @@ NOTE: For security reasons, this command will omit your private key and remote s return cmds.EmitOnce(res, &cfg) }, Encoders: cmds.EncoderMap{ - cmds.Text: cmds.MakeTypedEncoder(func(req *cmds.Request, w io.Writer, out *map[string]interface{}) error { - buf, err := config.HumanOutput(out) - if err != nil { - return err - } - buf = append(buf, byte('\n')) - _, err = w.Write(buf) - return err - }), + cmds.Text: HumanJSONEncoder, }, } +var HumanJSONEncoder = cmds.MakeTypedEncoder(func(req *cmds.Request, w io.Writer, out *map[string]interface{}) error { + buf, err := config.HumanOutput(out) + if err != nil { + return err + } + buf = append(buf, byte('\n')) + _, err = w.Write(buf) + return err +}) + // Scrubs value and returns error if missing func scrubValue(m map[string]interface{}, key []string) (map[string]interface{}, error) { return scrubMapInternal(m, key, false) diff --git a/core/commands/swarm.go b/core/commands/swarm.go index 00899eacbed..61f40e456aa 100644 --- a/core/commands/swarm.go +++ b/core/commands/swarm.go @@ -1,7 +1,9 @@ package commands import ( + "bytes" "context" + "encoding/json" "errors" "fmt" "io" @@ -10,15 +12,17 @@ import ( "sync" "time" - commands "github.com/ipfs/go-ipfs/commands" - cmdenv "github.com/ipfs/go-ipfs/core/commands/cmdenv" - repo "github.com/ipfs/go-ipfs/repo" - fsrepo "github.com/ipfs/go-ipfs/repo/fsrepo" + files "github.com/ipfs/go-ipfs-files" + "github.com/ipfs/go-ipfs/commands" + "github.com/ipfs/go-ipfs/config" + "github.com/ipfs/go-ipfs/core/commands/cmdenv" + "github.com/ipfs/go-ipfs/core/node/libp2p" + "github.com/ipfs/go-ipfs/repo" + "github.com/ipfs/go-ipfs/repo/fsrepo" cmds "github.com/ipfs/go-ipfs-cmds" - config "github.com/ipfs/go-ipfs/config" inet "github.com/libp2p/go-libp2p-core/network" - peer "github.com/libp2p/go-libp2p-core/peer" + "github.com/libp2p/go-libp2p-core/peer" ma "github.com/multiformats/go-multiaddr" madns "github.com/multiformats/go-multiaddr-dns" mamask "github.com/whyrusleeping/multiaddr-filter" @@ -52,6 +56,8 @@ ipfs peers in the internet. "filters": swarmFiltersCmd, "peers": swarmPeersCmd, "peering": swarmPeeringCmd, + "stats": swarmStatsCmd, // libp2p Network Resource Manager + "limit": swarmLimitCmd, // libp2p Network Resource Manager }, } @@ -304,6 +310,133 @@ var swarmPeersCmd = &cmds.Command{ Type: connInfos{}, } +var swarmStatsCmd = &cmds.Command{ + Status: cmds.Experimental, + Helptext: cmds.HelpText{ + Tagline: "Report resource usage for a scope.", + LongDescription: `Report resource usage for a scope. +The scope can be one of the following: +- system -- reports the system aggregate resource usage. +- transient -- reports the transient resource usage. +- svc: -- reports the resource usage of a specific service. +- proto: -- reports the resource usage of a specific protocol. +- peer: -- reports the resource usage of a specific peer. +- all -- reports the resource usage for all currently active scopes. + +The output of this command is JSON. +`}, + Arguments: []cmds.Argument{ + cmds.StringArg("scope", true, false, "scope of the stat report"), + }, + Run: func(req *cmds.Request, res cmds.ResponseEmitter, env cmds.Environment) error { + node, err := cmdenv.GetNode(env) + if err != nil { + return err + } + + if node.ResourceManager == nil { + return libp2p.NoResourceMgrError + } + + if len(req.Arguments) != 1 { + return fmt.Errorf("must specify exactly one scope") + } + scope := req.Arguments[0] + result, err := libp2p.NetStat(node.ResourceManager, scope) + if err != nil { + return err + } + + b := new(bytes.Buffer) + enc := json.NewEncoder(b) + err = enc.Encode(result) + if err != nil { + return err + } + return cmds.EmitOnce(res, b) + }, + Encoders: cmds.EncoderMap{ + cmds.Text: HumanJSONEncoder, + }, +} + +var swarmLimitCmd = &cmds.Command{ + Status: cmds.Experimental, + Helptext: cmds.HelpText{ + Tagline: "Get or set resource limits for a scope.", + LongDescription: `Get or set resource limits for a scope. +The scope can be one of the following: +- system -- limits for the system aggregate resource usage. +- transient -- limits for the transient resource usage. +- svc: -- limits for the resource usage of a specific service. +- proto: -- limits for the resource usage of a specific protocol. +- peer: -- limits for the resource usage of a specific peer. + +The output of this command is JSON. + +It is possible to use this command to inspect and tweak limits at runtime: + + $ ipfs swarm limit system > limit.json + $ vi limit.json + $ ipfs swarm limit system limit.json + +Changes made via command line are discarded on node shutdown. +For permanent limits set Swarm.ResourceMgr.Limits in the $IPFS_PATH/config file. +`}, + Arguments: []cmds.Argument{ + cmds.StringArg("scope", true, false, "scope of the limit"), + cmds.FileArg("limit.json", false, false, "limits to be set").EnableStdin(), + }, + Run: func(req *cmds.Request, res cmds.ResponseEmitter, env cmds.Environment) error { + node, err := cmdenv.GetNode(env) + if err != nil { + return err + } + + if node.ResourceManager == nil { + return libp2p.NoResourceMgrError + } + + scope := req.Arguments[0] + + // set scope limit to new values (when limit.json is passed as a second arg) + if req.Files != nil { + var newLimit config.ResourceMgrScopeConfig + it := req.Files.Entries() + if it.Next() { + file := files.FileFromEntry(it) + if file == nil { + return errors.New("expected a JSON file") + } + if err := json.NewDecoder(file).Decode(&newLimit); err != nil { + return errors.New("failed to decode JSON as ResourceMgrScopeConfig") + } + return libp2p.NetSetLimit(node.ResourceManager, scope, newLimit) + } + if err := it.Err(); err != nil { + return fmt.Errorf("error opening limit JSON file: %w", err) + } + } + + // get scope limit + result, err := libp2p.NetLimit(node.ResourceManager, scope) + if err != nil { + return err + } + + b := new(bytes.Buffer) + enc := json.NewEncoder(b) + err = enc.Encode(result) + if err != nil { + return err + } + return cmds.EmitOnce(res, b) + }, + Encoders: cmds.EncoderMap{ + cmds.Text: HumanJSONEncoder, + }, +} + type streamInfo struct { Protocol string } diff --git a/core/core.go b/core/core.go index 888d3d78013..1a09b85e83f 100644 --- a/core/core.go +++ b/core/core.go @@ -30,6 +30,7 @@ import ( ic "github.com/libp2p/go-libp2p-core/crypto" p2phost "github.com/libp2p/go-libp2p-core/host" metrics "github.com/libp2p/go-libp2p-core/metrics" + "github.com/libp2p/go-libp2p-core/network" peer "github.com/libp2p/go-libp2p-core/peer" pstore "github.com/libp2p/go-libp2p-core/peerstore" routing "github.com/libp2p/go-libp2p-core/routing" @@ -85,17 +86,18 @@ type IpfsNode struct { RecordValidator record.Validator // Online - PeerHost p2phost.Host `optional:"true"` // the network host (server+client) - Peering *peering.PeeringService `optional:"true"` - Filters *ma.Filters `optional:"true"` - Bootstrapper io.Closer `optional:"true"` // the periodic bootstrapper - Routing routing.Routing `optional:"true"` // the routing system. recommend ipfs-dht - DNSResolver *madns.Resolver // the DNS resolver - Exchange exchange.Interface // the block exchange + strategy (bitswap) - Namesys namesys.NameSystem // the name system, resolves paths to hashes - Provider provider.System // the value provider system - IpnsRepub *ipnsrp.Republisher `optional:"true"` - GraphExchange graphsync.GraphExchange `optional:"true"` + PeerHost p2phost.Host `optional:"true"` // the network host (server+client) + Peering *peering.PeeringService `optional:"true"` + Filters *ma.Filters `optional:"true"` + Bootstrapper io.Closer `optional:"true"` // the periodic bootstrapper + Routing routing.Routing `optional:"true"` // the routing system. recommend ipfs-dht + DNSResolver *madns.Resolver // the DNS resolver + Exchange exchange.Interface // the block exchange + strategy (bitswap) + Namesys namesys.NameSystem // the name system, resolves paths to hashes + Provider provider.System // the value provider system + IpnsRepub *ipnsrp.Republisher `optional:"true"` + GraphExchange graphsync.GraphExchange `optional:"true"` + ResourceManager network.ResourceManager `optional:"true"` PubSub *pubsub.PubSub `optional:"true"` PSRouter *psrouter.PubsubValueStore `optional:"true"` diff --git a/core/coreapi/test/api_test.go b/core/coreapi/test/api_test.go index 5c078558b7f..b8eed6102d9 100644 --- a/core/coreapi/test/api_test.go +++ b/core/coreapi/test/api_test.go @@ -23,7 +23,7 @@ import ( coreiface "github.com/ipfs/interface-go-ipfs-core" "github.com/ipfs/interface-go-ipfs-core/tests" "github.com/libp2p/go-libp2p-core/crypto" - peer "github.com/libp2p/go-libp2p-core/peer" + "github.com/libp2p/go-libp2p-core/peer" mocknet "github.com/libp2p/go-libp2p/p2p/net/mock" ) @@ -32,7 +32,7 @@ const testPeerID = "QmTFauExutTsy4XP6JbMFcw2Wa9645HJt2bTqL6qYDCKfe" type NodeProvider struct{} func (NodeProvider) MakeAPISwarm(ctx context.Context, fullIdentity bool, n int) ([]coreiface.CoreAPI, error) { - mn := mocknet.New(ctx) + mn := mocknet.New() nodes := make([]*core.IpfsNode, n) apis := make([]coreiface.CoreAPI, n) diff --git a/core/mock/mock.go b/core/mock/mock.go index 154917ab45a..0b34857f2b6 100644 --- a/core/mock/mock.go +++ b/core/mock/mock.go @@ -26,12 +26,10 @@ import ( // NewMockNode constructs an IpfsNode for use in tests. func NewMockNode() (*core.IpfsNode, error) { - ctx := context.Background() - // effectively offline, only peer in its network - return core.NewNode(ctx, &core.BuildCfg{ + return core.NewNode(context.Background(), &core.BuildCfg{ Online: true, - Host: MockHostOption(mocknet.New(ctx)), + Host: MockHostOption(mocknet.New()), }) } diff --git a/core/node/groups.go b/core/node/groups.go index 26b2fae8475..7f4cd8b97a2 100644 --- a/core/node/groups.go +++ b/core/node/groups.go @@ -112,10 +112,10 @@ func LibP2P(bcfg *BuildCfg, cfg *config.Config) fx.Option { } // If `cfg.Swarm.DisableRelay` is set and `Network.RelayTransport` isn't, use the former. - enableRelayTransport := cfg.Swarm.Transports.Network.Relay.WithDefault(!cfg.Swarm.DisableRelay) //nolint + enableRelayTransport := cfg.Swarm.Transports.Network.Relay.WithDefault(!cfg.Swarm.DisableRelay) // nolint // Warn about a deprecated option. - //nolint + // nolint if cfg.Swarm.DisableRelay { logger.Error("The 'Swarm.DisableRelay' config field is deprecated.") if enableRelayTransport { @@ -124,7 +124,7 @@ func LibP2P(bcfg *BuildCfg, cfg *config.Config) fx.Option { logger.Error("Use the 'Swarm.Transports.Network.Relay' config field instead") } } - //nolint + // nolint if cfg.Swarm.EnableAutoRelay { logger.Error("The 'Swarm.EnableAutoRelay' config field is deprecated.") if cfg.Swarm.RelayClient.Enabled == config.Default { @@ -133,7 +133,7 @@ func LibP2P(bcfg *BuildCfg, cfg *config.Config) fx.Option { logger.Error("'Swarm.EnableAutoRelay' has been overridden by 'Swarm.AutoRelay.Enabled'") } } - //nolint + // nolint if cfg.Swarm.EnableRelayHop { logger.Fatal("The `Swarm.EnableRelayHop` config field is ignored.\n" + "Use `Swarm.RelayService` to configure the circuit v2 relay.\n" + @@ -144,6 +144,8 @@ func LibP2P(bcfg *BuildCfg, cfg *config.Config) fx.Option { opts := fx.Options( BaseLibP2P, + // Services (resource management) + fx.Provide(libp2p.ResourceManager(cfg.Swarm)), fx.Provide(libp2p.AddrFilters(cfg.Swarm.AddrFilters)), fx.Provide(libp2p.AddrsFactory(cfg.Addresses.Announce, cfg.Addresses.AppendAnnounce, cfg.Addresses.NoAnnounce)), fx.Provide(libp2p.SmuxTransport(cfg.Swarm.Transports)), diff --git a/core/node/libp2p/libp2p.go b/core/node/libp2p/libp2p.go index 9d864ad467b..59e9a37d4df 100644 --- a/core/node/libp2p/libp2p.go +++ b/core/node/libp2p/libp2p.go @@ -10,10 +10,10 @@ import ( logging "github.com/ipfs/go-log" "github.com/libp2p/go-libp2p" - connmgr "github.com/libp2p/go-libp2p-connmgr" "github.com/libp2p/go-libp2p-core/crypto" "github.com/libp2p/go-libp2p-core/peer" "github.com/libp2p/go-libp2p-core/peerstore" + "github.com/libp2p/go-libp2p/p2p/net/connmgr" "go.uber.org/fx" ) @@ -30,7 +30,10 @@ var UserAgent = simpleOpt(libp2p.UserAgent(version.GetUserAgentVersion())) func ConnectionManager(low, high int, grace time.Duration) func() (opts Libp2pOpts, err error) { return func() (opts Libp2pOpts, err error) { - cm := connmgr.NewConnManager(low, high, grace) + cm, err := connmgr.NewConnManager(low, high, connmgr.WithGracePeriod(grace)) + if err != nil { + return opts, err + } opts.Opts = append(opts.Opts, libp2p.ConnectionManager(cm)) return } diff --git a/core/node/libp2p/rcmgr.go b/core/node/libp2p/rcmgr.go new file mode 100644 index 00000000000..d0bccd277fe --- /dev/null +++ b/core/node/libp2p/rcmgr.go @@ -0,0 +1,368 @@ +package libp2p + +import ( + "context" + "errors" + "fmt" + "os" + "path/filepath" + "strings" + + config "github.com/ipfs/go-ipfs/config" + "github.com/ipfs/go-ipfs/repo" + + "github.com/libp2p/go-libp2p" + "github.com/libp2p/go-libp2p-core/network" + "github.com/libp2p/go-libp2p-core/peer" + "github.com/libp2p/go-libp2p-core/protocol" + rcmgr "github.com/libp2p/go-libp2p-resource-manager" + + "go.uber.org/fx" +) + +const NetLimitDefaultFilename = "limit.json" +const NetLimitTraceFilename = "rcmgr.json.gz" + +var NoResourceMgrError = fmt.Errorf("missing ResourceMgr: make sure the daemon is running with Swarm.ResourceMgr.Enabled") + +func ResourceManager(cfg config.SwarmConfig) func(fx.Lifecycle, repo.Repo) (network.ResourceManager, Libp2pOpts, error) { + return func(lc fx.Lifecycle, repo repo.Repo) (network.ResourceManager, Libp2pOpts, error) { + var limiter *rcmgr.BasicLimiter + var manager network.ResourceManager + var opts Libp2pOpts + + // Config Swarm.ResourceMgr.Enabled decides if we run a real manager + enabled := cfg.ResourceMgr.Enabled.WithDefault(false) + + /// ENV overrides Config (if present) + switch os.Getenv("LIBP2P_RCMGR") { + case "0", "false": + enabled = false + case "1", "true": + enabled = true + } + + if enabled { + log.Debug("libp2p resource manager is enabled") + + repoPath, err := config.PathRoot() + if err != nil { + return nil, opts, fmt.Errorf("error opening IPFS_PATH: %w", err) + } + + // Create limiter: + // - parse $IPFS_PATH/limits.json if exists + // - use defaultLimits from rcmgr_defaults.go + defaultLimits := adjustedDefaultLimits(cfg) + limitFilePath := filepath.Join(repoPath, NetLimitDefaultFilename) + limitFile, err := os.Open(limitFilePath) + switch { + case err == nil: + defer limitFile.Close() + limiter, err = rcmgr.NewLimiterFromJSON(limitFile, defaultLimits) + if err != nil { + return nil, opts, fmt.Errorf("error parsing libp2p limit file: %w", err) + } + case errors.Is(err, os.ErrNotExist): + limiter = rcmgr.NewStaticLimiter(defaultLimits) + default: + return nil, opts, err + } + + setDefaultServiceLimits(limiter) // see rcmgr_defaults.go + + ropts := []rcmgr.Option{rcmgr.WithMetrics(createRcmgrMetrics())} + + if os.Getenv("LIBP2P_DEBUG_RCMGR") != "" { + traceFilePath := filepath.Join(repoPath, NetLimitTraceFilename) + ropts = append(ropts, rcmgr.WithTrace(traceFilePath)) + } + + manager, err = rcmgr.NewResourceManager(limiter, ropts...) + if err != nil { + return nil, opts, fmt.Errorf("error creating libp2p resource manager: %w", err) + } + + } else { + log.Debug("libp2p resource manager is disabled") + manager = network.NullResourceManager + } + + opts.Opts = append(opts.Opts, libp2p.ResourceManager(manager)) + + lc.Append(fx.Hook{ + OnStop: func(_ context.Context) error { + return manager.Close() + }}) + + return manager, opts, nil + } +} + +type NetStatOut struct { + System *network.ScopeStat `json:",omitempty"` + Transient *network.ScopeStat `json:",omitempty"` + Services map[string]network.ScopeStat `json:",omitempty"` + Protocols map[string]network.ScopeStat `json:",omitempty"` + Peers map[string]network.ScopeStat `json:",omitempty"` +} + +func NetStat(mgr network.ResourceManager, scope string) (NetStatOut, error) { + var err error + var result NetStatOut + switch { + case scope == "all": + rapi, ok := mgr.(rcmgr.ResourceManagerState) + if !ok { // NullResourceManager + return result, NoResourceMgrError + } + + stat := rapi.Stat() + result.System = &stat.System + result.Transient = &stat.Transient + if len(stat.Services) > 0 { + result.Services = stat.Services + } + if len(stat.Protocols) > 0 { + result.Protocols = make(map[string]network.ScopeStat, len(stat.Protocols)) + for proto, stat := range stat.Protocols { + result.Protocols[string(proto)] = stat + } + } + if len(stat.Peers) > 0 { + result.Peers = make(map[string]network.ScopeStat, len(stat.Peers)) + for p, stat := range stat.Peers { + result.Peers[p.Pretty()] = stat + } + } + + return result, nil + + case scope == config.ResourceMgrSystemScope: + err = mgr.ViewSystem(func(s network.ResourceScope) error { + stat := s.Stat() + result.System = &stat + return nil + }) + return result, err + + case scope == config.ResourceMgrTransientScope: + err = mgr.ViewTransient(func(s network.ResourceScope) error { + stat := s.Stat() + result.Transient = &stat + return nil + }) + return result, err + + case strings.HasPrefix(scope, config.ResourceMgrServiceScopePrefix): + svc := strings.TrimPrefix(scope, config.ResourceMgrServiceScopePrefix) + err = mgr.ViewService(svc, func(s network.ServiceScope) error { + stat := s.Stat() + result.Services = map[string]network.ScopeStat{ + svc: stat, + } + return nil + }) + return result, err + + case strings.HasPrefix(scope, config.ResourceMgrProtocolScopePrefix): + proto := strings.TrimPrefix(scope, config.ResourceMgrProtocolScopePrefix) + err = mgr.ViewProtocol(protocol.ID(proto), func(s network.ProtocolScope) error { + stat := s.Stat() + result.Protocols = map[string]network.ScopeStat{ + proto: stat, + } + return nil + }) + return result, err + + case strings.HasPrefix(scope, config.ResourceMgrPeerScopePrefix): + p := strings.TrimPrefix(scope, config.ResourceMgrPeerScopePrefix) + pid, err := peer.Decode(p) + if err != nil { + return result, fmt.Errorf("invalid peer ID: %q: %w", p, err) + } + err = mgr.ViewPeer(pid, func(s network.PeerScope) error { + stat := s.Stat() + result.Peers = map[string]network.ScopeStat{ + p: stat, + } + return nil + }) + return result, err + + default: + return result, fmt.Errorf("invalid scope %q", scope) + } +} + +func NetLimit(mgr network.ResourceManager, scope string) (config.ResourceMgrScopeConfig, error) { + var result config.ResourceMgrScopeConfig + getLimit := func(s network.ResourceScope) error { + limiter, ok := s.(rcmgr.ResourceScopeLimiter) + if !ok { // NullResourceManager + return NoResourceMgrError + } + + limit := limiter.Limit() + switch l := limit.(type) { + case *rcmgr.StaticLimit: + result.Dynamic = false + result.Memory = l.Memory + result.Streams = l.BaseLimit.Streams + result.StreamsInbound = l.BaseLimit.StreamsInbound + result.StreamsOutbound = l.BaseLimit.StreamsOutbound + result.Conns = l.BaseLimit.Conns + result.ConnsInbound = l.BaseLimit.ConnsInbound + result.ConnsOutbound = l.BaseLimit.ConnsOutbound + result.FD = l.BaseLimit.FD + + case *rcmgr.DynamicLimit: + result.Dynamic = true + result.MemoryFraction = l.MemoryLimit.MemoryFraction + result.MinMemory = l.MemoryLimit.MinMemory + result.MaxMemory = l.MemoryLimit.MaxMemory + result.Streams = l.BaseLimit.Streams + result.StreamsInbound = l.BaseLimit.StreamsInbound + result.StreamsOutbound = l.BaseLimit.StreamsOutbound + result.Conns = l.BaseLimit.Conns + result.ConnsInbound = l.BaseLimit.ConnsInbound + result.ConnsOutbound = l.BaseLimit.ConnsOutbound + result.FD = l.BaseLimit.FD + + default: + return fmt.Errorf("unknown limit type %T", limit) + } + + return nil + } + + switch { + case scope == config.ResourceMgrSystemScope: + err := mgr.ViewSystem(func(s network.ResourceScope) error { + return getLimit(s) + }) + return result, err + + case scope == config.ResourceMgrTransientScope: + err := mgr.ViewTransient(func(s network.ResourceScope) error { + return getLimit(s) + }) + return result, err + + case strings.HasPrefix(scope, config.ResourceMgrServiceScopePrefix): + svc := strings.TrimPrefix(scope, config.ResourceMgrServiceScopePrefix) + err := mgr.ViewService(svc, func(s network.ServiceScope) error { + return getLimit(s) + }) + return result, err + + case strings.HasPrefix(scope, config.ResourceMgrProtocolScopePrefix): + proto := strings.TrimPrefix(scope, config.ResourceMgrProtocolScopePrefix) + err := mgr.ViewProtocol(protocol.ID(proto), func(s network.ProtocolScope) error { + return getLimit(s) + }) + return result, err + + case strings.HasPrefix(scope, config.ResourceMgrPeerScopePrefix): + p := strings.TrimPrefix(scope, config.ResourceMgrPeerScopePrefix) + pid, err := peer.Decode(p) + if err != nil { + return result, fmt.Errorf("invalid peer ID: %q: %w", p, err) + } + err = mgr.ViewPeer(pid, func(s network.PeerScope) error { + return getLimit(s) + }) + return result, err + + default: + return result, fmt.Errorf("invalid scope %q", scope) + } +} + +func NetSetLimit(mgr network.ResourceManager, scope string, limit config.ResourceMgrScopeConfig) error { + setLimit := func(s network.ResourceScope) error { + limiter, ok := s.(rcmgr.ResourceScopeLimiter) + if !ok { // NullResourceManager + return NoResourceMgrError + } + + var newLimit rcmgr.Limit + if limit.Dynamic { + newLimit = &rcmgr.DynamicLimit{ + MemoryLimit: rcmgr.MemoryLimit{ + MemoryFraction: limit.MemoryFraction, + MinMemory: limit.MinMemory, + MaxMemory: limit.MaxMemory, + }, + BaseLimit: rcmgr.BaseLimit{ + Streams: limit.Streams, + StreamsInbound: limit.StreamsInbound, + StreamsOutbound: limit.StreamsOutbound, + Conns: limit.Conns, + ConnsInbound: limit.ConnsInbound, + ConnsOutbound: limit.ConnsOutbound, + FD: limit.FD, + }, + } + } else { + newLimit = &rcmgr.StaticLimit{ + Memory: limit.Memory, + BaseLimit: rcmgr.BaseLimit{ + Streams: limit.Streams, + StreamsInbound: limit.StreamsInbound, + StreamsOutbound: limit.StreamsOutbound, + Conns: limit.Conns, + ConnsInbound: limit.ConnsInbound, + ConnsOutbound: limit.ConnsOutbound, + FD: limit.FD, + }, + } + } + + limiter.SetLimit(newLimit) + return nil + } + + switch { + case scope == config.ResourceMgrSystemScope: + err := mgr.ViewSystem(func(s network.ResourceScope) error { + return setLimit(s) + }) + return err + + case scope == config.ResourceMgrTransientScope: + err := mgr.ViewTransient(func(s network.ResourceScope) error { + return setLimit(s) + }) + return err + + case strings.HasPrefix(scope, config.ResourceMgrServiceScopePrefix): + svc := scope[4:] + err := mgr.ViewService(svc, func(s network.ServiceScope) error { + return setLimit(s) + }) + return err + + case strings.HasPrefix(scope, config.ResourceMgrProtocolScopePrefix): + proto := scope[6:] + err := mgr.ViewProtocol(protocol.ID(proto), func(s network.ProtocolScope) error { + return setLimit(s) + }) + return err + + case strings.HasPrefix(scope, config.ResourceMgrPeerScopePrefix): + p := scope[5:] + pid, err := peer.Decode(p) + if err != nil { + return fmt.Errorf("invalid peer ID: %q: %w", p, err) + } + err = mgr.ViewPeer(pid, func(s network.PeerScope) error { + return setLimit(s) + }) + return err + + default: + return fmt.Errorf("invalid scope %q", scope) + } +} diff --git a/core/node/libp2p/rcmgr_defaults.go b/core/node/libp2p/rcmgr_defaults.go new file mode 100644 index 00000000000..dddc2b32411 --- /dev/null +++ b/core/node/libp2p/rcmgr_defaults.go @@ -0,0 +1,313 @@ +package libp2p + +import ( + "math/bits" + + config "github.com/ipfs/go-ipfs/config" + "github.com/libp2p/go-libp2p-core/protocol" + rcmgr "github.com/libp2p/go-libp2p-resource-manager" + "github.com/libp2p/go-libp2p/p2p/host/autonat" + relayv1 "github.com/libp2p/go-libp2p/p2p/protocol/circuitv1/relay" + circuit "github.com/libp2p/go-libp2p/p2p/protocol/circuitv2/proto" + relayv2 "github.com/libp2p/go-libp2p/p2p/protocol/circuitv2/relay" + "github.com/libp2p/go-libp2p/p2p/protocol/holepunch" + "github.com/libp2p/go-libp2p/p2p/protocol/identify" + "github.com/libp2p/go-libp2p/p2p/protocol/ping" +) + +// This file defines implicit limit defaults used when Swarm.ResourceMgr.Enabled +// We keep vendored copy to ensure go-ipfs is not impacted when go-libp2p decides +// to change defaults in any of the future releases. + +// adjustedDefaultLimits allows for tweaking defaults based on external factors, +// such as values in Swarm.ConnMgr.HiWater config. +func adjustedDefaultLimits(cfg config.SwarmConfig) rcmgr.DefaultLimitConfig { + + // Return to use unmodified static limits based on values from go-libp2p 0.18 + // return defaultLimits + + // Adjust limits + // (based on https://github.com/filecoin-project/lotus/pull/8318/files) + // - give it more memory, up to 4G, min of 1G + // - if Swarm.ConnMgr.HighWater is too high, adjust Conn/FD/Stream limits + defaultLimits := staticDefaultLimits.WithSystemMemory(.125, 1<<30, 4<<30) + + // Do we need to adjust due to Swarm.ConnMgr.HighWater? + if cfg.ConnMgr.Type == "basic" { + maxconns := cfg.ConnMgr.HighWater + if 2*maxconns > defaultLimits.SystemBaseLimit.ConnsInbound { + // adjust conns to 2x to allow for two conns per peer (TCP+QUIC) + defaultLimits.SystemBaseLimit.ConnsInbound = logScale(2 * maxconns) + defaultLimits.SystemBaseLimit.ConnsOutbound = logScale(2 * maxconns) + defaultLimits.SystemBaseLimit.Conns = logScale(4 * maxconns) + + defaultLimits.SystemBaseLimit.StreamsInbound = logScale(16 * maxconns) + defaultLimits.SystemBaseLimit.StreamsOutbound = logScale(64 * maxconns) + defaultLimits.SystemBaseLimit.Streams = logScale(64 * maxconns) + + if 2*maxconns > defaultLimits.SystemBaseLimit.FD { + defaultLimits.SystemBaseLimit.FD = logScale(2 * maxconns) + } + + defaultLimits.ServiceBaseLimit.StreamsInbound = logScale(8 * maxconns) + defaultLimits.ServiceBaseLimit.StreamsOutbound = logScale(32 * maxconns) + defaultLimits.ServiceBaseLimit.Streams = logScale(32 * maxconns) + + defaultLimits.ProtocolBaseLimit.StreamsInbound = logScale(8 * maxconns) + defaultLimits.ProtocolBaseLimit.StreamsOutbound = logScale(32 * maxconns) + defaultLimits.ProtocolBaseLimit.Streams = logScale(32 * maxconns) + } + } + + return defaultLimits +} + +func logScale(val int) int { + bitlen := bits.Len(uint(val)) + return 1 << bitlen +} + +// defaultLimits are the limits used by the default rcmgr limiter constructors. +// This is a vendored copy of +// https://github.com/libp2p/go-libp2p-resource-manager/blob/v0.1.5/limit_defaults.go#L49 +var staticDefaultLimits = rcmgr.DefaultLimitConfig{ + SystemBaseLimit: rcmgr.BaseLimit{ + StreamsInbound: 4096, + StreamsOutbound: 16384, + Streams: 16384, + ConnsInbound: 256, + ConnsOutbound: 1024, + Conns: 1024, + FD: 512, + }, + + SystemMemory: rcmgr.MemoryLimit{ + MemoryFraction: 0.125, + MinMemory: 128 << 20, + MaxMemory: 1 << 30, + }, + + TransientBaseLimit: rcmgr.BaseLimit{ + StreamsInbound: 128, + StreamsOutbound: 512, + Streams: 512, + ConnsInbound: 32, + ConnsOutbound: 128, + Conns: 128, + FD: 128, + }, + + TransientMemory: rcmgr.MemoryLimit{ + MemoryFraction: 1, + MinMemory: 64 << 20, + MaxMemory: 64 << 20, + }, + + ServiceBaseLimit: rcmgr.BaseLimit{ + StreamsInbound: 2048, + StreamsOutbound: 8192, + Streams: 8192, + }, + + ServiceMemory: rcmgr.MemoryLimit{ + MemoryFraction: 0.125 / 4, + MinMemory: 64 << 20, + MaxMemory: 256 << 20, + }, + + ServicePeerBaseLimit: rcmgr.BaseLimit{ + StreamsInbound: 256, + StreamsOutbound: 512, + Streams: 512, + }, + + ServicePeerMemory: rcmgr.MemoryLimit{ + MemoryFraction: 0.125 / 16, + MinMemory: 16 << 20, + MaxMemory: 64 << 20, + }, + + ProtocolBaseLimit: rcmgr.BaseLimit{ + StreamsInbound: 1024, + StreamsOutbound: 4096, + Streams: 4096, + }, + + ProtocolMemory: rcmgr.MemoryLimit{ + MemoryFraction: 0.125 / 8, + MinMemory: 64 << 20, + MaxMemory: 128 << 20, + }, + + ProtocolPeerBaseLimit: rcmgr.BaseLimit{ + StreamsInbound: 128, + StreamsOutbound: 256, + Streams: 512, + }, + + ProtocolPeerMemory: rcmgr.MemoryLimit{ + MemoryFraction: 0.125 / 16, + MinMemory: 16 << 20, + MaxMemory: 64 << 20, + }, + + PeerBaseLimit: rcmgr.BaseLimit{ + StreamsInbound: 512, + StreamsOutbound: 1024, + Streams: 1024, + ConnsInbound: 8, + ConnsOutbound: 16, + Conns: 16, + FD: 8, + }, + + PeerMemory: rcmgr.MemoryLimit{ + MemoryFraction: 0.125 / 16, + MinMemory: 64 << 20, + MaxMemory: 128 << 20, + }, + + ConnBaseLimit: rcmgr.BaseLimit{ + ConnsInbound: 1, + ConnsOutbound: 1, + Conns: 1, + FD: 1, + }, + + ConnMemory: 1 << 20, + + StreamBaseLimit: rcmgr.BaseLimit{ + StreamsInbound: 1, + StreamsOutbound: 1, + Streams: 1, + }, + + StreamMemory: 16 << 20, +} + +// setDefaultServiceLimits sets the default limits for bundled libp2p services. +// This is a vendored copy of +// https://github.com/libp2p/go-libp2p/blob/v0.18.0/limits.go +func setDefaultServiceLimits(limiter *rcmgr.BasicLimiter) { + if limiter.ServiceLimits == nil { + limiter.ServiceLimits = make(map[string]rcmgr.Limit) + } + if limiter.ServicePeerLimits == nil { + limiter.ServicePeerLimits = make(map[string]rcmgr.Limit) + } + if limiter.ProtocolLimits == nil { + limiter.ProtocolLimits = make(map[protocol.ID]rcmgr.Limit) + } + if limiter.ProtocolPeerLimits == nil { + limiter.ProtocolPeerLimits = make(map[protocol.ID]rcmgr.Limit) + } + + // identify + setServiceLimits(limiter, identify.ServiceName, + limiter.DefaultServiceLimits. + WithMemoryLimit(1, 4<<20, 64<<20). // max 64MB service memory + WithStreamLimit(128, 128, 256), // max 256 streams -- symmetric + peerLimit(16, 16, 32)) + + setProtocolLimits(limiter, identify.ID, + limiter.DefaultProtocolLimits.WithMemoryLimit(1, 4<<20, 32<<20), + peerLimit(16, 16, 32)) + setProtocolLimits(limiter, identify.IDPush, + limiter.DefaultProtocolLimits.WithMemoryLimit(1, 4<<20, 32<<20), + peerLimit(16, 16, 32)) + setProtocolLimits(limiter, identify.IDDelta, + limiter.DefaultProtocolLimits.WithMemoryLimit(1, 4<<20, 32<<20), + peerLimit(16, 16, 32)) + + // ping + setServiceLimits(limiter, ping.ServiceName, + limiter.DefaultServiceLimits. + WithMemoryLimit(1, 4<<20, 64<<20). // max 64MB service memory + WithStreamLimit(128, 128, 128), // max 128 streams - asymmetric + peerLimit(2, 3, 4)) + setProtocolLimits(limiter, ping.ID, + limiter.DefaultProtocolLimits.WithMemoryLimit(1, 4<<20, 64<<20), + peerLimit(2, 3, 4)) + + // autonat + setServiceLimits(limiter, autonat.ServiceName, + limiter.DefaultServiceLimits. + WithMemoryLimit(1, 4<<20, 64<<20). // max 64MB service memory + WithStreamLimit(128, 128, 128), // max 128 streams - asymmetric + peerLimit(2, 2, 2)) + setProtocolLimits(limiter, autonat.AutoNATProto, + limiter.DefaultProtocolLimits.WithMemoryLimit(1, 4<<20, 64<<20), + peerLimit(2, 2, 2)) + + // holepunch + setServiceLimits(limiter, holepunch.ServiceName, + limiter.DefaultServiceLimits. + WithMemoryLimit(1, 4<<20, 64<<20). // max 64MB service memory + WithStreamLimit(128, 128, 256), // max 256 streams - symmetric + peerLimit(2, 2, 2)) + setProtocolLimits(limiter, holepunch.Protocol, + limiter.DefaultProtocolLimits.WithMemoryLimit(1, 4<<20, 64<<20), + peerLimit(2, 2, 2)) + + // relay/v1 + setServiceLimits(limiter, relayv1.ServiceName, + limiter.DefaultServiceLimits. + WithMemoryLimit(1, 4<<20, 64<<20). // max 64MB service memory + WithStreamLimit(1024, 1024, 1024), // max 1024 streams - asymmetric + peerLimit(64, 64, 64)) + + // relay/v2 + setServiceLimits(limiter, relayv2.ServiceName, + limiter.DefaultServiceLimits. + WithMemoryLimit(1, 4<<20, 64<<20). // max 64MB service memory + WithStreamLimit(1024, 1024, 1024), // max 1024 streams - asymmetric + peerLimit(64, 64, 64)) + + // circuit protocols, both client and service + setProtocolLimits(limiter, circuit.ProtoIDv1, + limiter.DefaultProtocolLimits. + WithMemoryLimit(1, 4<<20, 64<<20). + WithStreamLimit(1280, 1280, 1280), + peerLimit(128, 128, 128)) + setProtocolLimits(limiter, circuit.ProtoIDv2Hop, + limiter.DefaultProtocolLimits. + WithMemoryLimit(1, 4<<20, 64<<20). + WithStreamLimit(1280, 1280, 1280), + peerLimit(128, 128, 128)) + setProtocolLimits(limiter, circuit.ProtoIDv2Stop, + limiter.DefaultProtocolLimits. + WithMemoryLimit(1, 4<<20, 64<<20). + WithStreamLimit(1280, 1280, 1280), + peerLimit(128, 128, 128)) + +} + +func setServiceLimits(limiter *rcmgr.BasicLimiter, svc string, limit rcmgr.Limit, peerLimit rcmgr.Limit) { + if _, ok := limiter.ServiceLimits[svc]; !ok { + limiter.ServiceLimits[svc] = limit + } + if _, ok := limiter.ServicePeerLimits[svc]; !ok { + limiter.ServicePeerLimits[svc] = peerLimit + } +} + +func setProtocolLimits(limiter *rcmgr.BasicLimiter, proto protocol.ID, limit rcmgr.Limit, peerLimit rcmgr.Limit) { + if _, ok := limiter.ProtocolLimits[proto]; !ok { + limiter.ProtocolLimits[proto] = limit + } + if _, ok := limiter.ProtocolPeerLimits[proto]; !ok { + limiter.ProtocolPeerLimits[proto] = peerLimit + } +} + +func peerLimit(numStreamsIn, numStreamsOut, numStreamsTotal int) rcmgr.Limit { + return &rcmgr.StaticLimit{ + // memory: 256kb for window buffers plus some change for message buffers per stream + Memory: int64(numStreamsTotal * (256<<10 + 16384)), + BaseLimit: rcmgr.BaseLimit{ + StreamsInbound: numStreamsIn, + StreamsOutbound: numStreamsOut, + Streams: numStreamsTotal, + }, + } +} diff --git a/core/node/libp2p/rcmgr_metrics.go b/core/node/libp2p/rcmgr_metrics.go new file mode 100644 index 00000000000..56ccfa9d62d --- /dev/null +++ b/core/node/libp2p/rcmgr_metrics.go @@ -0,0 +1,239 @@ +package libp2p + +import ( + "strconv" + + "github.com/libp2p/go-libp2p-core/network" + "github.com/libp2p/go-libp2p-core/peer" + "github.com/libp2p/go-libp2p-core/protocol" + rcmgr "github.com/libp2p/go-libp2p-resource-manager" + + "github.com/prometheus/client_golang/prometheus" +) + +func createRcmgrMetrics() rcmgr.MetricsReporter { + const ( + direction = "direction" + usesFD = "usesFD" + protocol = "protocol" + service = "service" + ) + + connAllowed := prometheus.NewCounterVec( + prometheus.CounterOpts{ + Name: "libp2p_rcmgr_conns_allowed_total", + Help: "allowed connections", + }, + []string{direction, usesFD}, + ) + prometheus.MustRegister(connAllowed) + + connBlocked := prometheus.NewCounterVec( + prometheus.CounterOpts{ + Name: "libp2p_rcmgr_conns_blocked_total", + Help: "blocked connections", + }, + []string{direction, usesFD}, + ) + prometheus.MustRegister(connBlocked) + + streamAllowed := prometheus.NewCounterVec( + prometheus.CounterOpts{ + Name: "libp2p_rcmgr_streams_allowed_total", + Help: "allowed streams", + }, + []string{direction}, + ) + prometheus.MustRegister(streamAllowed) + + streamBlocked := prometheus.NewCounterVec( + prometheus.CounterOpts{ + Name: "libp2p_rcmgr_streams_blocked_total", + Help: "blocked streams", + }, + []string{direction}, + ) + prometheus.MustRegister(streamBlocked) + + peerAllowed := prometheus.NewCounter(prometheus.CounterOpts{ + Name: "libp2p_rcmgr_peers_allowed_total", + Help: "allowed peers", + }) + prometheus.MustRegister(peerAllowed) + + peerBlocked := prometheus.NewCounter(prometheus.CounterOpts{ + Name: "libp2p_rcmgr_peer_blocked_total", + Help: "blocked peers", + }) + prometheus.MustRegister(peerBlocked) + + protocolAllowed := prometheus.NewCounterVec( + prometheus.CounterOpts{ + Name: "libp2p_rcmgr_protocols_allowed_total", + Help: "allowed streams attached to a protocol", + }, + []string{protocol}, + ) + prometheus.MustRegister(protocolAllowed) + + protocolBlocked := prometheus.NewCounterVec( + prometheus.CounterOpts{ + Name: "libp2p_rcmgr_protocols_blocked_total", + Help: "blocked streams attached to a protocol", + }, + []string{protocol}, + ) + prometheus.MustRegister(protocolBlocked) + + protocolPeerBlocked := prometheus.NewCounterVec( + prometheus.CounterOpts{ + Name: "libp2p_rcmgr_protocols_for_peer_blocked_total", + Help: "blocked streams attached to a protocol for a specific peer", + }, + []string{protocol}, + ) + prometheus.MustRegister(protocolPeerBlocked) + + serviceAllowed := prometheus.NewCounterVec( + prometheus.CounterOpts{ + Name: "libp2p_rcmgr_services_allowed_total", + Help: "allowed streams attached to a service", + }, + []string{service}, + ) + prometheus.MustRegister(serviceAllowed) + + serviceBlocked := prometheus.NewCounterVec( + prometheus.CounterOpts{ + Name: "libp2p_rcmgr_services_blocked_total", + Help: "blocked streams attached to a service", + }, + []string{service}, + ) + prometheus.MustRegister(serviceBlocked) + + servicePeerBlocked := prometheus.NewCounterVec( + prometheus.CounterOpts{ + Name: "libp2p_rcmgr_service_for_peer_blocked_total", + Help: "blocked streams attached to a service for a specific peer", + }, + []string{service}, + ) + prometheus.MustRegister(servicePeerBlocked) + + memoryAllowed := prometheus.NewCounter(prometheus.CounterOpts{ + Name: "libp2p_rcmgr_memory_allocations_allowed_total", + Help: "allowed memory allocations", + }) + prometheus.MustRegister(memoryAllowed) + + memoryBlocked := prometheus.NewCounter(prometheus.CounterOpts{ + Name: "libp2p_rcmgr_memory_allocations_blocked_total", + Help: "blocked memory allocations", + }) + prometheus.MustRegister(memoryBlocked) + + return rcmgrMetrics{ + connAllowed, + connBlocked, + streamAllowed, + streamBlocked, + peerAllowed, + peerBlocked, + protocolAllowed, + protocolBlocked, + protocolPeerBlocked, + serviceAllowed, + serviceBlocked, + servicePeerBlocked, + memoryAllowed, + memoryBlocked, + } +} + +// Failsafe to ensure interface from go-libp2p-resource-manager is implemented +var _ rcmgr.MetricsReporter = rcmgrMetrics{} + +type rcmgrMetrics struct { + connAllowed *prometheus.CounterVec + connBlocked *prometheus.CounterVec + streamAllowed *prometheus.CounterVec + streamBlocked *prometheus.CounterVec + peerAllowed prometheus.Counter + peerBlocked prometheus.Counter + protocolAllowed *prometheus.CounterVec + protocolBlocked *prometheus.CounterVec + protocolPeerBlocked *prometheus.CounterVec + serviceAllowed *prometheus.CounterVec + serviceBlocked *prometheus.CounterVec + servicePeerBlocked *prometheus.CounterVec + memoryAllowed prometheus.Counter + memoryBlocked prometheus.Counter +} + +func getDirection(d network.Direction) string { + switch d { + default: + return "" + case network.DirInbound: + return "inbound" + case network.DirOutbound: + return "outbound" + } +} + +func (r rcmgrMetrics) AllowConn(dir network.Direction, usefd bool) { + r.connAllowed.WithLabelValues(getDirection(dir), strconv.FormatBool(usefd)).Inc() +} + +func (r rcmgrMetrics) BlockConn(dir network.Direction, usefd bool) { + r.connBlocked.WithLabelValues(getDirection(dir), strconv.FormatBool(usefd)).Inc() +} + +func (r rcmgrMetrics) AllowStream(_ peer.ID, dir network.Direction) { + r.streamAllowed.WithLabelValues(getDirection(dir)).Inc() +} + +func (r rcmgrMetrics) BlockStream(_ peer.ID, dir network.Direction) { + r.streamBlocked.WithLabelValues(getDirection(dir)).Inc() +} + +func (r rcmgrMetrics) AllowPeer(_ peer.ID) { + r.peerAllowed.Inc() +} + +func (r rcmgrMetrics) BlockPeer(_ peer.ID) { + r.peerBlocked.Inc() +} + +func (r rcmgrMetrics) AllowProtocol(proto protocol.ID) { + r.protocolAllowed.WithLabelValues(string(proto)).Inc() +} + +func (r rcmgrMetrics) BlockProtocol(proto protocol.ID) { + r.protocolBlocked.WithLabelValues(string(proto)).Inc() +} + +func (r rcmgrMetrics) BlockProtocolPeer(proto protocol.ID, _ peer.ID) { + r.protocolPeerBlocked.WithLabelValues(string(proto)).Inc() +} + +func (r rcmgrMetrics) AllowService(svc string) { + r.serviceAllowed.WithLabelValues(svc).Inc() +} + +func (r rcmgrMetrics) BlockService(svc string) { + r.serviceBlocked.WithLabelValues(svc).Inc() +} + +func (r rcmgrMetrics) BlockServicePeer(svc string, _ peer.ID) { + r.servicePeerBlocked.WithLabelValues(svc).Inc() +} + +func (r rcmgrMetrics) AllowMemory(_ int) { + r.memoryAllowed.Inc() +} + +func (r rcmgrMetrics) BlockMemory(_ int) { + r.memoryBlocked.Inc() +} diff --git a/core/node/libp2p/smux.go b/core/node/libp2p/smux.go index a405e5a3274..539cad30788 100644 --- a/core/node/libp2p/smux.go +++ b/core/node/libp2p/smux.go @@ -7,12 +7,12 @@ import ( config "github.com/ipfs/go-ipfs/config" "github.com/libp2p/go-libp2p" - smux "github.com/libp2p/go-libp2p-core/mux" + "github.com/libp2p/go-libp2p-core/network" mplex "github.com/libp2p/go-libp2p-mplex" yamux "github.com/libp2p/go-libp2p-yamux" ) -func yamuxTransport() smux.Multiplexer { +func yamuxTransport() network.Multiplexer { tpt := *yamux.DefaultTransport tpt.AcceptBacklog = 512 if os.Getenv("YAMUX_DEBUG") != "" { diff --git a/docs/config.md b/docs/config.md index 2c935190923..519a7c10546 100644 --- a/docs/config.md +++ b/docs/config.md @@ -130,6 +130,8 @@ config file at runtime. - [`Swarm.ConnMgr.LowWater`](#swarmconnmgrlowwater) - [`Swarm.ConnMgr.HighWater`](#swarmconnmgrhighwater) - [`Swarm.ConnMgr.GracePeriod`](#swarmconnmgrgraceperiod) + - [`Swarm.ResourceMgr`](#swarmresourcemgr) + - [`Swarm.ResourceMgr.Enabled`](#swarmresourcemgrenabled) - [`Swarm.Transports`](#swarmtransports) - [`Swarm.Transports.Network`](#swarmtransportsnetwork) - [`Swarm.Transports.Network.TCP`](#swarmtransportsnetworktcp) @@ -1628,6 +1630,68 @@ Default: `"20s"` Type: `duration` +### `Swarm.ResourceMgr` + +The [libp2p Network Resource Manager](https://github.com/libp2p/go-libp2p-resource-manager#readme) allows setting limits per a scope, +and tracking recource usage over time. + +#### `Swarm.ResourceMgr.Enabled` + +**EXPERIMENTAL**: this feature is disabled by default, use with caution. + +Enables the libp2p Network Resource Manager and auguments the default limits +using user-defined ones in `Swarm.ResourceMgr.Limits` (if present). + +Default: `false` + +Type: `flag` + + + ### `Swarm.Transports` Configuration section for libp2p transports. An empty configuration will apply diff --git a/docs/environment-variables.md b/docs/environment-variables.md index fd57b819264..aa87438eb46 100644 --- a/docs/environment-variables.md +++ b/docs/environment-variables.md @@ -1,13 +1,5 @@ # go-ipfs environment variables -## `LIBP2P_TCP_REUSEPORT` - -go-ipfs tries to reuse the same source port for all connections to improve NAT -traversal. If this is an issue, you can disable it by setting -`LIBP2P_TCP_REUSEPORT` to false. - -Default: true - ## `IPFS_PATH` Sets the location of the IPFS repo (where the config, blocks, etc. @@ -122,6 +114,14 @@ $ ipfs resolve -r /ipns/dnslink-test2.example.com /ipfs/bafkreicysg23kiwv34eg2d7qweipxwosdo2py4ldv42nbauguluen5v6am ``` +## `LIBP2P_TCP_REUSEPORT` + +go-ipfs tries to reuse the same source port for all connections to improve NAT +traversal. If this is an issue, you can disable it by setting +`LIBP2P_TCP_REUSEPORT` to false. + +Default: true + ## `LIBP2P_MUX_PREFS` Deprecated: Use the `Swarm.Transports.Multiplexers` config field. @@ -130,12 +130,29 @@ Tells go-ipfs which multiplexers to use in which order. Default: "/yamux/1.0.0 /mplex/6.7.0" +## `LIBP2P_RCMGR` + +Forces [libp2p Network Resource Manager](https://github.com/libp2p/go-libp2p-resource-manager#readme) +to be enabled (`1`) or disabled (`0`). +When set, overrides [`Swarm.ResourceMgr.Enabled`](https://github.com/ipfs/go-ipfs/blob/master/docs/config.md#swarmresourcemgrenabled) from the config. + +Default: use config (not set) + +## `LIBP2P_DEBUG_RCMGR` + +Enables tracing of [libp2p Network Resource Manager](https://github.com/libp2p/go-libp2p-resource-manager#readme) +and outputs it to `rcmgr.json.gz` + + +Default: disabled (not set) + # Tracing -**NOTE** Tracing support is experimental--releases may contain tracing-related breaking changes. ## `IPFS_TRACING` Enables OpenTelemetry tracing. +**NOTE** Tracing support is experimental: releases may contain tracing-related breaking changes. + Default: false ## `IPFS_TRACING_JAEGER` @@ -197,5 +214,4 @@ Default: "" (disabled) ## `IPFS_TRACING_RATIO` The ratio of traces to export, as a floating point value in the interval [0, 1]. -Deault: 1.0 (export all traces) - +Default: 1.0 (export all traces) diff --git a/go.mod b/go.mod index d89921df144..e4b4f903bbf 100644 --- a/go.mod +++ b/go.mod @@ -67,32 +67,33 @@ require ( github.com/jbenet/go-temp-err-catcher v0.1.0 github.com/jbenet/goprocess v0.1.4 github.com/libp2p/go-doh-resolver v0.4.0 - github.com/libp2p/go-libp2p v0.16.0 - github.com/libp2p/go-libp2p-connmgr v0.2.4 - github.com/libp2p/go-libp2p-core v0.11.0 + github.com/libp2p/go-libp2p v0.18.0 + github.com/libp2p/go-libp2p-connmgr v0.3.2-0.20220115145817-a7820a5879c7 // indirect + github.com/libp2p/go-libp2p-core v0.14.0 github.com/libp2p/go-libp2p-discovery v0.6.0 github.com/libp2p/go-libp2p-http v0.2.1 github.com/libp2p/go-libp2p-kad-dht v0.15.0 github.com/libp2p/go-libp2p-kbucket v0.4.7 github.com/libp2p/go-libp2p-loggables v0.1.0 - github.com/libp2p/go-libp2p-mplex v0.4.1 + github.com/libp2p/go-libp2p-mplex v0.6.0 github.com/libp2p/go-libp2p-noise v0.3.0 - github.com/libp2p/go-libp2p-peerstore v0.4.0 + github.com/libp2p/go-libp2p-peerstore v0.6.0 github.com/libp2p/go-libp2p-pubsub v0.6.0 github.com/libp2p/go-libp2p-pubsub-router v0.5.0 - github.com/libp2p/go-libp2p-quic-transport v0.15.0 + github.com/libp2p/go-libp2p-quic-transport v0.16.1 github.com/libp2p/go-libp2p-record v0.1.3 + github.com/libp2p/go-libp2p-resource-manager v0.1.5 github.com/libp2p/go-libp2p-routing-helpers v0.2.3 - github.com/libp2p/go-libp2p-swarm v0.8.0 - github.com/libp2p/go-libp2p-testing v0.5.0 + github.com/libp2p/go-libp2p-swarm v0.10.2 + github.com/libp2p/go-libp2p-testing v0.8.0 github.com/libp2p/go-libp2p-tls v0.3.1 - github.com/libp2p/go-libp2p-yamux v0.6.0 + github.com/libp2p/go-libp2p-yamux v0.8.2 github.com/libp2p/go-socket-activation v0.1.0 - github.com/libp2p/go-tcp-transport v0.4.0 - github.com/libp2p/go-ws-transport v0.5.0 + github.com/libp2p/go-tcp-transport v0.5.1 + github.com/libp2p/go-ws-transport v0.6.0 github.com/miekg/dns v1.1.43 github.com/mitchellh/go-homedir v1.1.0 - github.com/multiformats/go-multiaddr v0.4.1 + github.com/multiformats/go-multiaddr v0.5.0 github.com/multiformats/go-multiaddr-dns v0.3.1 github.com/multiformats/go-multibase v0.0.3 github.com/multiformats/go-multicodec v0.4.0 diff --git a/go.sum b/go.sum index 5163daaa5b3..be5a76d8952 100644 --- a/go.sum +++ b/go.sum @@ -135,6 +135,7 @@ github.com/cheggaaa/pb v1.0.29/go.mod h1:W40334L7FMC5JKWldsTWbdGjLo0RxUKK73K+TuP github.com/chzyer/logex v1.1.10/go.mod h1:+Ywpsq7O8HXn0nuIou7OrIPyXbp3wmkHB+jjWRnGsAI= github.com/chzyer/readline v0.0.0-20180603132655-2972be24d48e/go.mod h1:nSuG5e5PlCu98SY8svDHJxuZscDgtXS6KTTbou5AhLI= github.com/chzyer/test v0.0.0-20180213035817-a1ea475d72b1/go.mod h1:Q3SI9o4m/ZMnBNeIyt5eFwwo7qiLfzFZmjNmxjkiQlU= +github.com/cilium/ebpf v0.2.0/go.mod h1:To2CFviqOWL/M0gIMsvSMlqe7em/l1ALkX1PyjrX2Qs= github.com/clbanning/x2j v0.0.0-20191024224557-825249438eec/go.mod h1:jMjuTZXRI4dUb/I5gc9Hdhagfvm9+RyrPryS/auMzxE= github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw= github.com/cncf/udpa/go v0.0.0-20191209042840-269d4d468f6f/go.mod h1:M8M6+tZqaGXZJjfX53e64911xZQV5JYwmTeXPW+k8Sc= @@ -146,6 +147,8 @@ github.com/cncf/xds/go v0.0.0-20210922020428-25de7278fc84/go.mod h1:eXthEFrGJvWH github.com/cncf/xds/go v0.0.0-20211011173535-cb28da3451f1/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs= github.com/cockroachdb/datadriven v0.0.0-20190809214429-80d97fb3cbaa/go.mod h1:zn76sxSg3SzpJ0PPJaLDCu+Bu0Lg3sKTORVIj19EIF8= github.com/codahale/hdrhistogram v0.0.0-20161010025455-3a0bb77429bd/go.mod h1:sE/e/2PUdi/liOCUjSTXgM1o87ZssimdTWN964YiIeI= +github.com/containerd/cgroups v0.0.0-20201119153540-4cbc285b3327 h1:7grrpcfCtbZLsjtB0DgMuzs1umsJmpzaHMZ6cO6iAWw= +github.com/containerd/cgroups v0.0.0-20201119153540-4cbc285b3327/go.mod h1:ZJeTFisyysqgcCdecO57Dj79RfL0LNeGiFUqLYQRYLE= github.com/coreos/etcd v3.3.10+incompatible/go.mod h1:uF7uidLiAD3TWHmW31ZFd/JWoc32PjwdhPthX9715RE= github.com/coreos/go-etcd v2.0.0+incompatible/go.mod h1:Jez6KQU2B/sWsbdaef3ED8NzMklzPG4d5KIOhIy30Tk= github.com/coreos/go-semver v0.2.0/go.mod h1:nnelYz7RCh+5ahJtPPxZlU+153eP4D4r3EedlOD2RNk= @@ -157,11 +160,13 @@ github.com/coreos/go-systemd v0.0.0-20181012123002-c6f51f82210d/go.mod h1:F5haX7 github.com/coreos/go-systemd v0.0.0-20190321100706-95778dfbb74e h1:Wf6HqHfScWJN9/ZjdUKyjop4mf3Qdd+1TvvltAvM3m8= github.com/coreos/go-systemd v0.0.0-20190321100706-95778dfbb74e/go.mod h1:F5haX7vjVVG0kc13fIWeqUViNPyEJxv/OmvnBo0Yme4= github.com/coreos/go-systemd/v22 v22.0.0/go.mod h1:xO0FLkIi5MaZafQlIrOotqXZ90ih+1atmu1JpKERPPk= +github.com/coreos/go-systemd/v22 v22.1.0/go.mod h1:xO0FLkIi5MaZafQlIrOotqXZ90ih+1atmu1JpKERPPk= github.com/coreos/go-systemd/v22 v22.3.2 h1:D9/bQk5vlXQFZ6Kwuu6zaiXJ9oTPe68++AzAJc1DzSI= github.com/coreos/go-systemd/v22 v22.3.2/go.mod h1:Y58oyj3AT4RCenI/lSvhwexgC+NSVTIJ3seZv2GcEnc= github.com/coreos/pkg v0.0.0-20160727233714-3ac0863d7acf/go.mod h1:E3G3o1h8I7cfcXa63jLwjI0eiQQMgzzUDFVpN/nH/eA= github.com/cpuguy83/go-md2man v1.0.10/go.mod h1:SmD6nW6nTyfqj6ABTjUi3V3JVMnlJmwcJI5acqYI6dE= github.com/cpuguy83/go-md2man/v2 v2.0.0-20190314233015-f79a8a8ca69d/go.mod h1:maD7wRr/U5Z6m/iR4s+kqSMx2CaBsrgA7czyZG/E6dU= +github.com/cpuguy83/go-md2man/v2 v2.0.0/go.mod h1:maD7wRr/U5Z6m/iR4s+kqSMx2CaBsrgA7czyZG/E6dU= github.com/crackcomm/go-gitignore v0.0.0-20170627025303-887ab5e44cc3 h1:HVTnpeuvF6Owjd5mniCL8DEXo7uYXdQEmOP4FJbV5tg= github.com/crackcomm/go-gitignore v0.0.0-20170627025303-887ab5e44cc3/go.mod h1:p1d6YEZWvFzEh4KLyvBcVSnrfNDDvK2zfK/4x2v/4pE= github.com/creack/pty v1.1.7/go.mod h1:lj5s0c3V2DBrqTV7llrYr5NG6My20zk30Fl46Y7DoTY= @@ -188,6 +193,8 @@ github.com/dgrijalva/jwt-go v3.2.0+incompatible/go.mod h1:E3ru+11k8xSBh+hMPgOLZm github.com/dgryski/go-farm v0.0.0-20190104051053-3adb47b1fb0f/go.mod h1:SqUrOPUnsFjfmXRMNPybcSiG0BgUW2AuFH8PAnS2iTw= github.com/dgryski/go-farm v0.0.0-20190423205320-6a90982ecee2 h1:tdlZCpZ/P9DhczCTSixgIKmwPv6+wP5DGjqLYw5SUiA= github.com/dgryski/go-farm v0.0.0-20190423205320-6a90982ecee2/go.mod h1:SqUrOPUnsFjfmXRMNPybcSiG0BgUW2AuFH8PAnS2iTw= +github.com/docker/go-units v0.4.0 h1:3uh0PgVws3nIA0Q+MwDC8yjEPf9zjRfZZWXZYDct3Tw= +github.com/docker/go-units v0.4.0/go.mod h1:fgPhTUdO+D/Jk86RDLlptpiXQzgHJF7gydDDbaIK4Dk= github.com/dustin/go-humanize v0.0.0-20171111073723-bb3d318650d4/go.mod h1:HtrtbFcZ19U5GC7JDqmcUSB87Iq5E25KnS6fMYU6eOk= github.com/dustin/go-humanize v1.0.0 h1:VSnTsYCnlFHaM2/igO1h6X3HA71jcobQuxemgkq4zYo= github.com/dustin/go-humanize v1.0.0/go.mod h1:HtrtbFcZ19U5GC7JDqmcUSB87Iq5E25KnS6fMYU6eOk= @@ -195,6 +202,8 @@ github.com/eapache/go-resiliency v1.1.0/go.mod h1:kFI+JgMyC7bLPUVY133qvEBtVayf5m github.com/eapache/go-xerial-snappy v0.0.0-20180814174437-776d5712da21/go.mod h1:+020luEh2TKB4/GOp8oxxtq0Daoen/Cii55CzbTV6DU= github.com/eapache/queue v1.1.0/go.mod h1:6eCeP0CKFpHLu8blIFXhExK/dRa7WDZfr6jVFPTqq+I= github.com/edsrzf/mmap-go v1.0.0/go.mod h1:YO35OhQPt3KJa3ryjFM5Bs14WD66h8eGKpfaBNrHW5M= +github.com/elastic/gosigar v0.12.0 h1:AsdhYCJlTudhfOYQyFNgx+fIVTfrDO0V1ST0vHgiapU= +github.com/elastic/gosigar v0.12.0/go.mod h1:iXRIGg2tLnu7LBdpqzyQfGDEidKCfWcCMS0WKyPWoMs= github.com/elgris/jsondiff v0.0.0-20160530203242-765b5c24c302 h1:QV0ZrfBLpFc2KDk+a4LJefDczXnonRwrYrQJY/9L4dA= github.com/elgris/jsondiff v0.0.0-20160530203242-765b5c24c302/go.mod h1:qBlWZqWeVx9BjvqBsnC/8RUlAYpIFmPvgROcw0n1scE= github.com/envoyproxy/go-control-plane v0.6.9/go.mod h1:SBwIajubJHhxtWwsL9s8ss4safvEdbitLhGGK48rN6g= @@ -254,6 +263,7 @@ github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/me github.com/go-task/slim-sprig v0.0.0-20210107165309-348f09dbbbc0 h1:p104kn46Q8WdvHunIJ9dAyjPVtrBPhSr3KT2yUst43I= github.com/go-task/slim-sprig v0.0.0-20210107165309-348f09dbbbc0/go.mod h1:fyg7847qk6SyHyPtNmDHnmrv/HOrqktSC+C9fM+CJOE= github.com/godbus/dbus/v5 v5.0.3/go.mod h1:xhWf0FNVPg57R7Z0UbKHbJfkEywrmjJnf7w5xrFpKfA= +github.com/godbus/dbus/v5 v5.0.4 h1:9349emZab16e7zQvpmsbtjc18ykshndd8y2PG3sgJbA= github.com/godbus/dbus/v5 v5.0.4/go.mod h1:xhWf0FNVPg57R7Z0UbKHbJfkEywrmjJnf7w5xrFpKfA= github.com/gogo/googleapis v1.1.0/go.mod h1:gf4bu3Q80BeJ6H1S1vYPm8/ELATdvryBaNFGgqEef3s= github.com/gogo/protobuf v1.1.1/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ= @@ -310,6 +320,7 @@ github.com/google/go-cmp v0.4.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/ github.com/google/go-cmp v0.4.1/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/go-cmp v0.5.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/go-cmp v0.5.1/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= +github.com/google/go-cmp v0.5.2/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/go-cmp v0.5.3/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/go-cmp v0.5.4/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= @@ -553,8 +564,10 @@ github.com/ipfs/go-log/v2 v2.0.3/go.mod h1:O7P1lJt27vWHhOwQmcFEvlmo49ry2VY2+JfBW github.com/ipfs/go-log/v2 v2.0.5/go.mod h1:eZs4Xt4ZUJQFM3DlanGhy7TkwwawCZcSByscwkWG+dw= github.com/ipfs/go-log/v2 v2.1.1/go.mod h1:2v2nsGfZsvvAJz13SyFzf9ObaqwHiHxsPLEHntrv9KM= github.com/ipfs/go-log/v2 v2.1.3/go.mod h1:/8d0SH3Su5Ooc31QlL1WysJhvyOTDCjcCZ9Axpmri6g= -github.com/ipfs/go-log/v2 v2.3.0 h1:31Re/cPqFHpsRHgyVwjWADPoF0otB1WrjTy8ZFYwEZU= github.com/ipfs/go-log/v2 v2.3.0/go.mod h1:QqGoj30OTpnKaG/LKTGTxoP2mmQtjVMEnK72gynbe/g= +github.com/ipfs/go-log/v2 v2.4.0/go.mod h1:nPZnh7Cj7lwS3LpRU5Mwr2ol1c2gXIEXuF6aywqrtmo= +github.com/ipfs/go-log/v2 v2.5.0 h1:+MhAooFd9XZNvR0i9FriKW6HB0ql7HNXUuflWtc0dd4= +github.com/ipfs/go-log/v2 v2.5.0/go.mod h1:prSpmC1Gpllc9UYWxDiZDreBYw7zp4Iqp1kOLU9U5UI= github.com/ipfs/go-merkledag v0.0.6/go.mod h1:QYPdnlvkOg7GnQRofu9XZimC5ZW5Wi3bKys/4GQQfto= github.com/ipfs/go-merkledag v0.2.3/go.mod h1:SQiXrtSts3KGNmgOzMICy5c0POOpUNQLvB3ClKnBAlk= github.com/ipfs/go-merkledag v0.3.2/go.mod h1:fvkZNNZixVW6cKSZ/JfLlON5OlgTXNdRLz0p6QG/I2M= @@ -655,8 +668,9 @@ github.com/kisielk/errcheck v1.5.0 h1:e8esj/e4R+SAOwFwN+n3zr0nYeCyeweozKfO23MvHz github.com/kisielk/errcheck v1.5.0/go.mod h1:pFxgyoBC7bSaBwPgfKdkLd5X25qrDl4LWUI2bnpBCr8= github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck= github.com/kkdai/bstream v0.0.0-20161212061736-f391b8402d23/go.mod h1:J+Gs4SYgM6CZQHDETBtE9HaSEkGmuNXF86RwHhHUvq4= -github.com/klauspost/compress v1.11.7 h1:0hzRabrMN4tSTvMfnL3SCv1ZGeAP23ynzodBgaHeMeg= github.com/klauspost/compress v1.11.7/go.mod h1:aoV0uJVorq1K+umq18yTdKaF57EivdYsUV+/s2qKfXs= +github.com/klauspost/compress v1.13.6 h1:P76CopJELS0TiO2mebmnzgWaajssP/EszplttgQxcgc= +github.com/klauspost/compress v1.13.6/go.mod h1:/3/Vjq9QcHkK5uEr5lBEmyoZ1iFhe47etQ6QUkpK6sk= github.com/klauspost/cpuid/v2 v2.0.4/go.mod h1:FInQzS24/EEf25PyTYn52gqo7WaD8xa0213Md/qVLRg= github.com/klauspost/cpuid/v2 v2.0.6/go.mod h1:FInQzS24/EEf25PyTYn52gqo7WaD8xa0213Md/qVLRg= github.com/klauspost/cpuid/v2 v2.0.9 h1:lgaqFMSdTdQYdZ04uHyN2d/eKdOMyi2YLSvlQIBFYa4= @@ -680,7 +694,6 @@ github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY= github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE= github.com/libp2p/go-addr-util v0.0.1/go.mod h1:4ac6O7n9rIAKB1dnd+s8IbbMXkt+oBpzX4/+RACcnlQ= github.com/libp2p/go-addr-util v0.0.2/go.mod h1:Ecd6Fb3yIuLzq4bD7VcywcVSBtefcAwnUISBM3WG15E= -github.com/libp2p/go-addr-util v0.1.0 h1:acKsntI33w2bTU7tC9a0SaPimJGfSI0bFKC18ChxeVI= github.com/libp2p/go-addr-util v0.1.0/go.mod h1:6I3ZYuFr2O/9D+SoyM0zEw0EF3YkldtTX406BpdQMqw= github.com/libp2p/go-buffer-pool v0.0.1/go.mod h1:xtyIz9PMobb13WaxR6Zo1Pd1zXJKYg0a8KiIvDp3TzQ= github.com/libp2p/go-buffer-pool v0.0.2 h1:QNK2iAFa8gjAe1SPz6mHSMuCcjs+X1wlHzeOSqcmlfs= @@ -714,8 +727,9 @@ github.com/libp2p/go-libp2p v0.12.0/go.mod h1:FpHZrfC1q7nA8jitvdjKBDF31hguaC676g github.com/libp2p/go-libp2p v0.13.0/go.mod h1:pM0beYdACRfHO1WcJlp65WXyG2A6NqYM+t2DTVAJxMo= github.com/libp2p/go-libp2p v0.14.3/go.mod h1:d12V4PdKbpL0T1/gsUNN8DfgMuRPDX8bS2QxCZlwRH0= github.com/libp2p/go-libp2p v0.14.4/go.mod h1:EIRU0Of4J5S8rkockZM7eJp2S0UrCyi55m2kJVru3rM= -github.com/libp2p/go-libp2p v0.16.0 h1:aTxzQPllnW+nyC9mY8xaS20BbcrSYMt1HCkjZRHvdGY= github.com/libp2p/go-libp2p v0.16.0/go.mod h1:ump42BsirwAWxKzsCiFnTtN1Yc+DuPu76fyMX364/O4= +github.com/libp2p/go-libp2p v0.18.0 h1:moKKKG875KNGsCjZxTIFB75ihHiVjFeWg5I4aR1pDLk= +github.com/libp2p/go-libp2p v0.18.0/go.mod h1:+veaZ9z1SZQhmc5PW78jvnnxZ89Mgvmh4cggO11ETmw= github.com/libp2p/go-libp2p-asn-util v0.0.0-20200825225859-85005c6cf052/go.mod h1:nRMRTab+kZuk0LnKZpxhOVH/ndsdr2Nr//Zltc/vwgo= github.com/libp2p/go-libp2p-asn-util v0.1.0 h1:rABPCO77SjdbJ/eJ/ynIo8vWICy1VEnL5JAxJbQLo1E= github.com/libp2p/go-libp2p-asn-util v0.1.0/go.mod h1:wu+AnM9Ii2KgO5jMmS1rz9dvzTdj8BXqsPR9HR0XB7I= @@ -727,21 +741,23 @@ github.com/libp2p/go-libp2p-autonat v0.2.1/go.mod h1:MWtAhV5Ko1l6QBsHQNSuM6b1sRk github.com/libp2p/go-libp2p-autonat v0.2.2/go.mod h1:HsM62HkqZmHR2k1xgX34WuWDzk/nBwNHoeyyT4IWV6A= github.com/libp2p/go-libp2p-autonat v0.4.0/go.mod h1:YxaJlpr81FhdOv3W3BTconZPfhaYivRdf53g+S2wobk= github.com/libp2p/go-libp2p-autonat v0.4.2/go.mod h1:YxaJlpr81FhdOv3W3BTconZPfhaYivRdf53g+S2wobk= -github.com/libp2p/go-libp2p-autonat v0.6.0 h1:+vbQ1pMzMGjE/RJopiQKK2FRjdCKHPNPrkPm8u+luQU= github.com/libp2p/go-libp2p-autonat v0.6.0/go.mod h1:bFC6kY8jwzNNWoqc8iGE57vsfwyJ/lP4O4DOV1e0B2o= github.com/libp2p/go-libp2p-blankhost v0.0.1/go.mod h1:Ibpbw/7cPPYwFb7PACIWdvxxv0t0XCCI10t7czjAjTc= github.com/libp2p/go-libp2p-blankhost v0.1.1/go.mod h1:pf2fvdLJPsC1FsVrNP3DUUvMzUts2dsLLBEpo1vW1ro= github.com/libp2p/go-libp2p-blankhost v0.1.4/go.mod h1:oJF0saYsAXQCSfDq254GMNmLNz6ZTHTOvtF4ZydUvwU= -github.com/libp2p/go-libp2p-blankhost v0.2.0 h1:3EsGAi0CBGcZ33GwRuXEYJLLPoVWyXJ1bcJzAJjINkk= github.com/libp2p/go-libp2p-blankhost v0.2.0/go.mod h1:eduNKXGTioTuQAUcZ5epXi9vMl+t4d8ugUBRQ4SqaNQ= +github.com/libp2p/go-libp2p-blankhost v0.3.0 h1:kTnLArltMabZlzY63pgGDA4kkUcLkBFSM98zBssn/IY= +github.com/libp2p/go-libp2p-blankhost v0.3.0/go.mod h1:urPC+7U01nCGgJ3ZsV8jdwTp6Ji9ID0dMTvq+aJ+nZU= github.com/libp2p/go-libp2p-circuit v0.0.9/go.mod h1:uU+IBvEQzCu953/ps7bYzC/D/R0Ho2A9LfKVVCatlqU= github.com/libp2p/go-libp2p-circuit v0.1.0/go.mod h1:Ahq4cY3V9VJcHcn1SBXjr78AbFkZeIRmfunbA7pmFh8= github.com/libp2p/go-libp2p-circuit v0.1.4/go.mod h1:CY67BrEjKNDhdTk8UgBX1Y/H5c3xkAcs3gnksxY7osU= github.com/libp2p/go-libp2p-circuit v0.2.1/go.mod h1:BXPwYDN5A8z4OEY9sOfr2DUQMLQvKt/6oku45YUmjIo= -github.com/libp2p/go-libp2p-circuit v0.4.0 h1:eqQ3sEYkGTtybWgr6JLqJY6QLtPWRErvFjFDfAOO1wc= github.com/libp2p/go-libp2p-circuit v0.4.0/go.mod h1:t/ktoFIUzM6uLQ+o1G6NuBl2ANhBKN9Bc8jRIk31MoA= -github.com/libp2p/go-libp2p-connmgr v0.2.4 h1:TMS0vc0TCBomtQJyWr7fYxcVYYhx+q/2gF++G5Jkl/w= +github.com/libp2p/go-libp2p-circuit v0.6.0 h1:rw/HlhmUB3OktS/Ygz6+2XABOmHKzZpPUuMNUMosj8w= +github.com/libp2p/go-libp2p-circuit v0.6.0/go.mod h1:kB8hY+zCpMeScyvFrKrGicRdid6vNXbunKE4rXATZ0M= github.com/libp2p/go-libp2p-connmgr v0.2.4/go.mod h1:YV0b/RIm8NGPnnNWM7hG9Q38OeQiQfKhHCCs1++ufn0= +github.com/libp2p/go-libp2p-connmgr v0.3.2-0.20220115145817-a7820a5879c7 h1:74g7rKhKikoMDKNtpeSjttE5ELgpmk2gD7U1nqDgoPw= +github.com/libp2p/go-libp2p-connmgr v0.3.2-0.20220115145817-a7820a5879c7/go.mod h1:RVoyPjJm0J9Vd1m6qUN2Tn7kJm4rL1Ml20pFsFgPGik= github.com/libp2p/go-libp2p-core v0.0.1/go.mod h1:g/VxnTZ/1ygHxH3dKok7Vno1VfpvGcGip57wjTU4fco= github.com/libp2p/go-libp2p-core v0.0.2/go.mod h1:9dAcntw/n46XycV4RnlBq3BpgrmyUi9LuoTNdPrbUco= github.com/libp2p/go-libp2p-core v0.0.3/go.mod h1:j+YQMNz9WNSkNezXOsahp9kwZBKBvxLpKD316QWSJXE= @@ -770,8 +786,11 @@ github.com/libp2p/go-libp2p-core v0.8.5/go.mod h1:FfewUH/YpvWbEB+ZY9AQRQ4TAD8sJB github.com/libp2p/go-libp2p-core v0.8.6/go.mod h1:dgHr0l0hIKfWpGpqAMbpo19pen9wJfdCGv51mTmdpmM= github.com/libp2p/go-libp2p-core v0.9.0/go.mod h1:ESsbz31oC3C1AvMJoGx26RTuCkNhmkSRCqZ0kQtJ2/8= github.com/libp2p/go-libp2p-core v0.10.0/go.mod h1:ECdxehoYosLYHgDDFa2N4yE8Y7aQRAMf0sX9mf2sbGg= -github.com/libp2p/go-libp2p-core v0.11.0 h1:75jAgdA+IChNa+/mZXogfmrGkgwxkVvxmIC7pV+F6sI= github.com/libp2p/go-libp2p-core v0.11.0/go.mod h1:ECdxehoYosLYHgDDFa2N4yE8Y7aQRAMf0sX9mf2sbGg= +github.com/libp2p/go-libp2p-core v0.12.0/go.mod h1:ECdxehoYosLYHgDDFa2N4yE8Y7aQRAMf0sX9mf2sbGg= +github.com/libp2p/go-libp2p-core v0.13.0/go.mod h1:ECdxehoYosLYHgDDFa2N4yE8Y7aQRAMf0sX9mf2sbGg= +github.com/libp2p/go-libp2p-core v0.14.0 h1:0kYSgiK/D7Eo28GTuRXo5YHsWwAisVpFCqCVPUd/vJs= +github.com/libp2p/go-libp2p-core v0.14.0/go.mod h1:tLasfcVdTXnixsLB0QYaT1syJOhsbrhG7q6pGrHtBg8= github.com/libp2p/go-libp2p-crypto v0.0.1/go.mod h1:yJkNyDmO341d5wwXxDUGO0LykUVT72ImHNUqh5D/dBE= github.com/libp2p/go-libp2p-crypto v0.0.2/go.mod h1:eETI5OUfBnvARGOHrJz2eWNyTUxEGZnBxMcbUjfIj4I= github.com/libp2p/go-libp2p-crypto v0.1.0/go.mod h1:sPUokVISZiy+nNuTTH/TY+leRSxnFj/2GLjtOTW90hI= @@ -808,8 +827,10 @@ github.com/libp2p/go-libp2p-mplex v0.2.2/go.mod h1:74S9eum0tVQdAfFiKxAyKzNdSuLqw github.com/libp2p/go-libp2p-mplex v0.2.3/go.mod h1:CK3p2+9qH9x+7ER/gWWDYJ3QW5ZxWDkm+dVvjfuG3ek= github.com/libp2p/go-libp2p-mplex v0.3.0/go.mod h1:l9QWxRbbb5/hQMECEb908GbS9Sm2UAR2KFZKUJEynEs= github.com/libp2p/go-libp2p-mplex v0.4.0/go.mod h1:yCyWJE2sc6TBTnFpjvLuEJgTSw/u+MamvzILKdX7asw= -github.com/libp2p/go-libp2p-mplex v0.4.1 h1:/pyhkP1nLwjG3OM+VuaNJkQT/Pqq73WzB3aDN3Fx1sc= github.com/libp2p/go-libp2p-mplex v0.4.1/go.mod h1:cmy+3GfqfM1PceHTLL7zQzAAYaryDu6iPSC+CIb094g= +github.com/libp2p/go-libp2p-mplex v0.5.0/go.mod h1:eLImPJLkj3iG5t5lq68w3Vm5NAQ5BcKwrrb2VmOYb3M= +github.com/libp2p/go-libp2p-mplex v0.6.0 h1:5ubK4/vLE2JkogKlJ2JLeXcSfA6qY6mE2HMJV9ve/Sk= +github.com/libp2p/go-libp2p-mplex v0.6.0/go.mod h1:i3usuPrBbh9FD2fLZjGpotyNkwr42KStYZQY7BeTiu4= github.com/libp2p/go-libp2p-nat v0.0.4/go.mod h1:N9Js/zVtAXqaeT99cXgTV9e75KpnWCvVOiGzlcHmBbY= github.com/libp2p/go-libp2p-nat v0.0.5/go.mod h1:1qubaE5bTZMJE+E/uu2URroMbzdubFz1ChgiN79yKPE= github.com/libp2p/go-libp2p-nat v0.0.6/go.mod h1:iV59LVhB3IkFvS6S6sauVTSOrNEANnINbI/fkaLimiw= @@ -838,8 +859,9 @@ github.com/libp2p/go-libp2p-peerstore v0.2.2/go.mod h1:NQxhNjWxf1d4w6PihR8btWIRj github.com/libp2p/go-libp2p-peerstore v0.2.6/go.mod h1:ss/TWTgHZTMpsU/oKVVPQCGuDHItOpf2W8RxAi50P2s= github.com/libp2p/go-libp2p-peerstore v0.2.7/go.mod h1:ss/TWTgHZTMpsU/oKVVPQCGuDHItOpf2W8RxAi50P2s= github.com/libp2p/go-libp2p-peerstore v0.2.8/go.mod h1:gGiPlXdz7mIHd2vfAsHzBNAMqSDkt2UBFwgcITgw1lA= -github.com/libp2p/go-libp2p-peerstore v0.4.0 h1:DOhRJLnM9Dc9lIXi3rPDZBf789LXy1BrzwIs7Tj0cKA= github.com/libp2p/go-libp2p-peerstore v0.4.0/go.mod h1:rDJUFyzEWPpXpEwywkcTYYzDHlwza8riYMaUzaN6hX0= +github.com/libp2p/go-libp2p-peerstore v0.6.0 h1:HJminhQSGISBIRb93N6WK3t6Fa8OOTnHd/VBjL4mY5A= +github.com/libp2p/go-libp2p-peerstore v0.6.0/go.mod h1:DGEmKdXrcYpK9Jha3sS7MhqYdInxJy84bIPtSu65bKc= github.com/libp2p/go-libp2p-pnet v0.2.0 h1:J6htxttBipJujEjz1y0a5+eYoiPcFHhSYHH6na5f0/k= github.com/libp2p/go-libp2p-pnet v0.2.0/go.mod h1:Qqvq6JH/oMZGwqs3N1Fqhv8NVhrdYcO0BW4wssv21LA= github.com/libp2p/go-libp2p-protocol v0.0.1/go.mod h1:Af9n4PiruirSDjHycM1QuiMi/1VZNHYcK8cLgFJLZ4s= @@ -851,13 +873,17 @@ github.com/libp2p/go-libp2p-pubsub-router v0.5.0/go.mod h1:TRJKskSem3C0aSb3CmRgP github.com/libp2p/go-libp2p-quic-transport v0.10.0/go.mod h1:RfJbZ8IqXIhxBRm5hqUEJqjiiY8xmEuq3HUDS993MkA= github.com/libp2p/go-libp2p-quic-transport v0.11.2/go.mod h1:wlanzKtIh6pHrq+0U3p3DY9PJfGqxMgPaGKaK5LifwQ= github.com/libp2p/go-libp2p-quic-transport v0.13.0/go.mod h1:39/ZWJ1TW/jx1iFkKzzUg00W6tDJh73FC0xYudjr7Hc= -github.com/libp2p/go-libp2p-quic-transport v0.15.0 h1:DR0mP6kcieowikBprWkcNtbquRKOPWb5dLZ4ahDZujk= github.com/libp2p/go-libp2p-quic-transport v0.15.0/go.mod h1:wv4uGwjcqe8Mhjj7N/Ic0aKjA+/10UnMlSzLO0yRpYQ= +github.com/libp2p/go-libp2p-quic-transport v0.16.0/go.mod h1:1BXjVMzr+w7EkPfiHkKnwsWjPjtfaNT0q8RS3tGDvEQ= +github.com/libp2p/go-libp2p-quic-transport v0.16.1 h1:N/XqYXHurphPLDfXYhll8NyqzdZYQqAF4GIr7+SmLV8= +github.com/libp2p/go-libp2p-quic-transport v0.16.1/go.mod h1:1BXjVMzr+w7EkPfiHkKnwsWjPjtfaNT0q8RS3tGDvEQ= github.com/libp2p/go-libp2p-record v0.0.1/go.mod h1:grzqg263Rug/sRex85QrDOLntdFAymLDLm7lxMgU79Q= github.com/libp2p/go-libp2p-record v0.1.0/go.mod h1:ujNc8iuE5dlKWVy6wuL6dd58t0n7xI4hAIl8pE6wu5Q= github.com/libp2p/go-libp2p-record v0.1.2/go.mod h1:pal0eNcT5nqZaTV7UGhqeGqxFgGdsU/9W//C8dqjQDk= github.com/libp2p/go-libp2p-record v0.1.3 h1:R27hoScIhQf/A8XJZ8lYpnqh9LatJ5YbHs28kCIfql0= github.com/libp2p/go-libp2p-record v0.1.3/go.mod h1:yNUff/adKIfPnYQXgp6FQmNu3gLJ6EMg7+/vv2+9pY4= +github.com/libp2p/go-libp2p-resource-manager v0.1.5 h1:7J6t9KLFS0MxXDTfqA6rwfVCZl/yLQnXW5LpZjHAANI= +github.com/libp2p/go-libp2p-resource-manager v0.1.5/go.mod h1:wJPNjeE4XQlxeidwqVY5G6DLOKqFK33u2n8blpl0I6Y= github.com/libp2p/go-libp2p-routing v0.0.1/go.mod h1:N51q3yTr4Zdr7V8Jt2JIktVU+3xBBylx1MZeVA6t1Ys= github.com/libp2p/go-libp2p-routing-helpers v0.2.3 h1:xY61alxJ6PurSi+MXbywZpelvuU4U4p/gPTxjqCqTzY= github.com/libp2p/go-libp2p-routing-helpers v0.2.3/go.mod h1:795bh+9YeoFl99rMASoiVgHdi5bjack0N1+AFAdbvBw= @@ -876,8 +902,10 @@ github.com/libp2p/go-libp2p-swarm v0.3.1/go.mod h1:hdv95GWCTmzkgeJpP+GK/9D9puJeg github.com/libp2p/go-libp2p-swarm v0.4.0/go.mod h1:XVFcO52VoLoo0eitSxNQWYq4D6sydGOweTOAjJNraCw= github.com/libp2p/go-libp2p-swarm v0.5.0/go.mod h1:sU9i6BoHE0Ve5SKz3y9WfKrh8dUat6JknzUehFx8xW4= github.com/libp2p/go-libp2p-swarm v0.5.3/go.mod h1:NBn7eNW2lu568L7Ns9wdFrOhgRlkRnIDg0FLKbuu3i8= -github.com/libp2p/go-libp2p-swarm v0.8.0 h1:nRHNRhi86L7jhka02N4MoV+PSFFPoJFkHNQwCTFxNhw= github.com/libp2p/go-libp2p-swarm v0.8.0/go.mod h1:sOMp6dPuqco0r0GHTzfVheVBh6UEL0L1lXUZ5ot2Fvc= +github.com/libp2p/go-libp2p-swarm v0.10.0/go.mod h1:71ceMcV6Rg/0rIQ97rsZWMzto1l9LnNquef+efcRbmA= +github.com/libp2p/go-libp2p-swarm v0.10.2 h1:UaXf+CTq6Ns1N2V1EgqJ9Q3xaRsiN7ImVlDMpirMAWw= +github.com/libp2p/go-libp2p-swarm v0.10.2/go.mod h1:Pdkq0QU5a+qu+oyqIV3bknMsnzk9lnNyKvB9acJ5aZs= github.com/libp2p/go-libp2p-testing v0.0.1/go.mod h1:gvchhf3FQOtBdr+eFUABet5a4MBLK8jM3V4Zghvmi+E= github.com/libp2p/go-libp2p-testing v0.0.2/go.mod h1:gvchhf3FQOtBdr+eFUABet5a4MBLK8jM3V4Zghvmi+E= github.com/libp2p/go-libp2p-testing v0.0.3/go.mod h1:gvchhf3FQOtBdr+eFUABet5a4MBLK8jM3V4Zghvmi+E= @@ -888,8 +916,10 @@ github.com/libp2p/go-libp2p-testing v0.1.2-0.20200422005655-8775583591d8/go.mod github.com/libp2p/go-libp2p-testing v0.3.0/go.mod h1:efZkql4UZ7OVsEfaxNHZPzIehtsBXMrXnCfJIgDti5g= github.com/libp2p/go-libp2p-testing v0.4.0/go.mod h1:Q+PFXYoiYFN5CAEG2w3gLPEzotlKsNSbKQ/lImlOWF0= github.com/libp2p/go-libp2p-testing v0.4.2/go.mod h1:Q+PFXYoiYFN5CAEG2w3gLPEzotlKsNSbKQ/lImlOWF0= -github.com/libp2p/go-libp2p-testing v0.5.0 h1:bTjC29TTQ/ODq0ld3+0KLq3irdA5cAH3OMbRi0/QsvE= github.com/libp2p/go-libp2p-testing v0.5.0/go.mod h1:QBk8fqIL1XNcno/l3/hhaIEn4aLRijpYOR+zVjjlh+A= +github.com/libp2p/go-libp2p-testing v0.7.0/go.mod h1:OLbdn9DbgdMwv00v+tlp1l3oe2Cl+FAjoWIA2pa0X6E= +github.com/libp2p/go-libp2p-testing v0.8.0 h1:/te8SOIyj5sGH5Jr1Uoo+qYB00aK8O4+yHGzLgfE3kc= +github.com/libp2p/go-libp2p-testing v0.8.0/go.mod h1:gRdsNxQSxAZowTgcLY7CC33xPmleZzoBpqSYbWenqPc= github.com/libp2p/go-libp2p-tls v0.1.3/go.mod h1:wZfuewxOndz5RTnCAxFliGjvYSDA40sKitV4c50uI1M= github.com/libp2p/go-libp2p-tls v0.3.0/go.mod h1:fwF5X6PWGxm6IDRwF3V8AVCCj/hOd5oFlg+wo2FxJDY= github.com/libp2p/go-libp2p-tls v0.3.1 h1:lsE2zYte+rZCEOHF72J1Fg3XK3dGQyKvI6i5ehJfEp0= @@ -904,8 +934,10 @@ github.com/libp2p/go-libp2p-transport-upgrader v0.4.0/go.mod h1:J4ko0ObtZSmgn5BX github.com/libp2p/go-libp2p-transport-upgrader v0.4.2/go.mod h1:NR8ne1VwfreD5VIWIU62Agt/J18ekORFU/j1i2y8zvk= github.com/libp2p/go-libp2p-transport-upgrader v0.4.3/go.mod h1:bpkldbOWXMrXhpZbSV1mQxTrefOg2Fi+k1ClDSA4ppw= github.com/libp2p/go-libp2p-transport-upgrader v0.4.6/go.mod h1:JE0WQuQdy+uLZ5zOaI3Nw9dWGYJIA7mywEtP2lMvnyk= -github.com/libp2p/go-libp2p-transport-upgrader v0.5.0 h1:7SDl3O2+AYOgfE40Mis83ClpfGNkNA6m4FwhbOHs+iI= github.com/libp2p/go-libp2p-transport-upgrader v0.5.0/go.mod h1:Rc+XODlB3yce7dvFV4q/RmyJGsFcCZRkeZMu/Zdg0mo= +github.com/libp2p/go-libp2p-transport-upgrader v0.7.0/go.mod h1:GIR2aTRp1J5yjVlkUoFqMkdobfob6RnAwYg/RZPhrzg= +github.com/libp2p/go-libp2p-transport-upgrader v0.7.1 h1:MSMe+tUfxpC9GArTz7a4G5zQKQgGh00Vio87d3j3xIg= +github.com/libp2p/go-libp2p-transport-upgrader v0.7.1/go.mod h1:GIR2aTRp1J5yjVlkUoFqMkdobfob6RnAwYg/RZPhrzg= github.com/libp2p/go-libp2p-xor v0.0.0-20210714161855-5c005aca55db h1:EDoDKW8ZAHd6SIDeo+thU51PyQppqLYkBxx0ObvFj/w= github.com/libp2p/go-libp2p-xor v0.0.0-20210714161855-5c005aca55db/go.mod h1:LSTM5yRnjGZbWNTA/hRwq2gGFrvRIbQJscoIL/u6InY= github.com/libp2p/go-libp2p-yamux v0.1.2/go.mod h1:xUoV/RmYkg6BW/qGxA9XJyg+HzXFYkeXbnhjmnYzKp8= @@ -920,12 +952,14 @@ github.com/libp2p/go-libp2p-yamux v0.4.0/go.mod h1:+DWDjtFMzoAwYLVkNZftoucn7PelN github.com/libp2p/go-libp2p-yamux v0.5.0/go.mod h1:AyR8k5EzyM2QN9Bbdg6X1SkVVuqLwTGf0L4DFq9g6po= github.com/libp2p/go-libp2p-yamux v0.5.1/go.mod h1:dowuvDu8CRWmr0iqySMiSxK+W0iL5cMVO9S94Y6gkv4= github.com/libp2p/go-libp2p-yamux v0.5.4/go.mod h1:tfrXbyaTqqSU654GTvK3ocnSZL3BuHoeTSqhcel1wsE= -github.com/libp2p/go-libp2p-yamux v0.6.0 h1:TKayW983n92JhCGdCo7ej7eEb+DQ0VYfKNOxlN/1kNQ= github.com/libp2p/go-libp2p-yamux v0.6.0/go.mod h1:MRhd6mAYnFRnSISp4M8i0ClV/j+mWHo2mYLifWGw33k= +github.com/libp2p/go-libp2p-yamux v0.8.0/go.mod h1:yTkPgN2ib8FHyU1ZcVD7aelzyAqXXwEPbyx+aSKm9h8= +github.com/libp2p/go-libp2p-yamux v0.8.1/go.mod h1:rUozF8Jah2dL9LLGyBaBeTQeARdwhefMCTQVQt6QobE= +github.com/libp2p/go-libp2p-yamux v0.8.2 h1:6GKWntresp0TFxMP/oSoH96nV8XKJRdynXsdp43dn0Y= +github.com/libp2p/go-libp2p-yamux v0.8.2/go.mod h1:rUozF8Jah2dL9LLGyBaBeTQeARdwhefMCTQVQt6QobE= github.com/libp2p/go-maddr-filter v0.0.1/go.mod h1:6eT12kSQMA9x2pvFQa+xesMKUBlj9VImZbj3B9FBH/Q= github.com/libp2p/go-maddr-filter v0.0.4/go.mod h1:6eT12kSQMA9x2pvFQa+xesMKUBlj9VImZbj3B9FBH/Q= github.com/libp2p/go-maddr-filter v0.0.5/go.mod h1:Jk+36PMfIqCJhAnaASRH83bdAvfDRp/w6ENFaC9bG+M= -github.com/libp2p/go-maddr-filter v0.1.0 h1:4ACqZKw8AqiuJfwFGq1CYDFugfXTOos+qQ3DETkhtCE= github.com/libp2p/go-maddr-filter v0.1.0/go.mod h1:VzZhTXkMucEGGEOSKddrwGiOv0tUhgnKqNEmIAz/bPU= github.com/libp2p/go-mplex v0.0.3/go.mod h1:pK5yMLmOoBR1pNCqDlA2GQrdAVTMkqFalaTWe7l4Yd0= github.com/libp2p/go-mplex v0.0.4/go.mod h1:pK5yMLmOoBR1pNCqDlA2GQrdAVTMkqFalaTWe7l4Yd0= @@ -933,8 +967,10 @@ github.com/libp2p/go-mplex v0.1.0/go.mod h1:SXgmdki2kwCUlCCbfGLEgHjC4pFqhTp0ZoV6 github.com/libp2p/go-mplex v0.1.1/go.mod h1:Xgz2RDCi3co0LeZfgjm4OgUF15+sVR8SRcu3SFXI1lk= github.com/libp2p/go-mplex v0.1.2/go.mod h1:Xgz2RDCi3co0LeZfgjm4OgUF15+sVR8SRcu3SFXI1lk= github.com/libp2p/go-mplex v0.2.0/go.mod h1:0Oy/A9PQlwBytDRp4wSkFnzHYDKcpLot35JQ6msjvYQ= -github.com/libp2p/go-mplex v0.3.0 h1:U1T+vmCYJaEoDJPV1aq31N56hS+lJgb397GsylNSgrU= github.com/libp2p/go-mplex v0.3.0/go.mod h1:0Oy/A9PQlwBytDRp4wSkFnzHYDKcpLot35JQ6msjvYQ= +github.com/libp2p/go-mplex v0.4.0/go.mod h1:y26Lx+wNVtMYMaPu300Cbot5LkEZ4tJaNYeHeT9dh6E= +github.com/libp2p/go-mplex v0.6.0 h1:5kKp029zrsLVJT5q6ASt4LwuZFxj3B13wXXaGmFrWg0= +github.com/libp2p/go-mplex v0.6.0/go.mod h1:y26Lx+wNVtMYMaPu300Cbot5LkEZ4tJaNYeHeT9dh6E= github.com/libp2p/go-msgio v0.0.2/go.mod h1:63lBBgOTDKQL6EWazRMCwXsEeEeK9O2Cd+0+6OOuipQ= github.com/libp2p/go-msgio v0.0.3/go.mod h1:63lBBgOTDKQL6EWazRMCwXsEeEeK9O2Cd+0+6OOuipQ= github.com/libp2p/go-msgio v0.0.4/go.mod h1:63lBBgOTDKQL6EWazRMCwXsEeEeK9O2Cd+0+6OOuipQ= @@ -949,8 +985,9 @@ github.com/libp2p/go-nat v0.1.0/go.mod h1:X7teVkwRHNInVNWQiO/tAiAVRwSr5zoRz4YSTC github.com/libp2p/go-netroute v0.1.2/go.mod h1:jZLDV+1PE8y5XxBySEBgbuVAXbhtuHSdmLPL2n9MKbk= github.com/libp2p/go-netroute v0.1.3/go.mod h1:jZLDV+1PE8y5XxBySEBgbuVAXbhtuHSdmLPL2n9MKbk= github.com/libp2p/go-netroute v0.1.5/go.mod h1:V1SR3AaECRkEQCoFFzYwVYWvYIEtlxx89+O3qcpCl4A= -github.com/libp2p/go-netroute v0.1.6 h1:ruPJStbYyXVYGQ81uzEDzuvbYRLKRrLvTYd33yomC38= github.com/libp2p/go-netroute v0.1.6/go.mod h1:AqhkMh0VuWmfgtxKPp3Oc1LdU5QSWS7wl0QLhSZqXxQ= +github.com/libp2p/go-netroute v0.2.0 h1:0FpsbsvuSnAhXFnCY0VLFbJOzaK0VnP0r1QT/o4nWRE= +github.com/libp2p/go-netroute v0.2.0/go.mod h1:Vio7LTzZ+6hoT4CMZi5/6CpY3Snzh2vgZhWgxMNwlQI= github.com/libp2p/go-openssl v0.0.2/go.mod h1:v8Zw2ijCSWBQi8Pq5GAixw6DbFfa9u6VIYDXnvOXkc0= github.com/libp2p/go-openssl v0.0.3/go.mod h1:unDrJpgy3oFr+rqXsarWifmJuNnJR4chtO1HmaZjggc= github.com/libp2p/go-openssl v0.0.4/go.mod h1:unDrJpgy3oFr+rqXsarWifmJuNnJR4chtO1HmaZjggc= @@ -969,7 +1006,6 @@ github.com/libp2p/go-reuseport-transport v0.1.0 h1:C3PHeHjmnz8m6f0uydObj02tMEoi7 github.com/libp2p/go-reuseport-transport v0.1.0/go.mod h1:vev0C0uMkzriDY59yFHD9v+ujJvYmDQVLowvAjEOmfw= github.com/libp2p/go-sockaddr v0.0.2/go.mod h1:syPvOmNs24S3dFVGJA1/mrqdeijPxLV2Le3BRLKd68k= github.com/libp2p/go-sockaddr v0.1.0/go.mod h1:syPvOmNs24S3dFVGJA1/mrqdeijPxLV2Le3BRLKd68k= -github.com/libp2p/go-sockaddr v0.1.1 h1:yD80l2ZOdGksnOyHrhxDdTDFrf7Oy+v3FMVArIRgZxQ= github.com/libp2p/go-sockaddr v0.1.1/go.mod h1:syPvOmNs24S3dFVGJA1/mrqdeijPxLV2Le3BRLKd68k= github.com/libp2p/go-socket-activation v0.1.0 h1:OImQPhtbGlCNaF/KSTl6pBBy+chA5eBt5i9uMJNtEdY= github.com/libp2p/go-socket-activation v0.1.0/go.mod h1:gzda2dNkMG5Ti2OfWNNwW0FDIbj0g/aJJU320FcLfhk= @@ -977,8 +1013,9 @@ github.com/libp2p/go-stream-muxer v0.0.1/go.mod h1:bAo8x7YkSpadMTbtTaxGVHWUQsR/l github.com/libp2p/go-stream-muxer v0.1.0/go.mod h1:8JAVsjeRBCWwPoZeH0W1imLOcriqXJyFvB0mR4A04sQ= github.com/libp2p/go-stream-muxer-multistream v0.1.1/go.mod h1:zmGdfkQ1AzOECIAcccoL8L//laqawOsO03zX8Sa+eGw= github.com/libp2p/go-stream-muxer-multistream v0.2.0/go.mod h1:j9eyPol/LLRqT+GPLSxvimPhNph4sfYfMoDPd7HkzIc= -github.com/libp2p/go-stream-muxer-multistream v0.3.0 h1:TqnSHPJEIqDEO7h1wZZ0p3DXdvDSiLHQidKKUGZtiOY= github.com/libp2p/go-stream-muxer-multistream v0.3.0/go.mod h1:yDh8abSIzmZtqtOt64gFJUXEryejzNb0lisTt+fAMJA= +github.com/libp2p/go-stream-muxer-multistream v0.4.0 h1:HsM/9OdtqnIzjVXcxTXjmqKrj3gJ8kacaOJwJS1ipaY= +github.com/libp2p/go-stream-muxer-multistream v0.4.0/go.mod h1:nb+dGViZleRP4XcyHuZSVrJCBl55nRBOMmiSL/dyziw= github.com/libp2p/go-tcp-transport v0.0.4/go.mod h1:+E8HvC8ezEVOxIo3V5vCK9l1y/19K427vCzQ+xHKH/o= github.com/libp2p/go-tcp-transport v0.1.0/go.mod h1:oJ8I5VXryj493DEJ7OsBieu8fcg2nHGctwtInJVpipc= github.com/libp2p/go-tcp-transport v0.1.1/go.mod h1:3HzGvLbx6etZjnFlERyakbaYPdfjg2pWP97dFZworkY= @@ -987,8 +1024,10 @@ github.com/libp2p/go-tcp-transport v0.2.1/go.mod h1:zskiJ70MEfWz2MKxvFB/Pv+tPIB1 github.com/libp2p/go-tcp-transport v0.2.3/go.mod h1:9dvr03yqrPyYGIEN6Dy5UvdJZjyPFvl1S/igQ5QD1SU= github.com/libp2p/go-tcp-transport v0.2.4/go.mod h1:9dvr03yqrPyYGIEN6Dy5UvdJZjyPFvl1S/igQ5QD1SU= github.com/libp2p/go-tcp-transport v0.2.7/go.mod h1:lue9p1b3VmZj1MhhEGB/etmvF/nBQ0X9CW2DutBT3MM= -github.com/libp2p/go-tcp-transport v0.4.0 h1:VDyg4j6en3OuXf90gfDQh5Sy9KowO9udnd0OU8PP6zg= github.com/libp2p/go-tcp-transport v0.4.0/go.mod h1:0y52Rwrn4076xdJYu/51/qJIdxz+EWDAOG2S45sV3VI= +github.com/libp2p/go-tcp-transport v0.5.0/go.mod h1:UPPL0DIjQqiWRwVAb+CEQlaAG0rp/mCqJfIhFcLHc4Y= +github.com/libp2p/go-tcp-transport v0.5.1 h1:edOOs688VLZAozWC7Kj5/6HHXKNwi9M6wgRmmLa8M6Q= +github.com/libp2p/go-tcp-transport v0.5.1/go.mod h1:UPPL0DIjQqiWRwVAb+CEQlaAG0rp/mCqJfIhFcLHc4Y= github.com/libp2p/go-testutil v0.0.1/go.mod h1:iAcJc/DKJQanJ5ws2V+u5ywdL2n12X1WbbEG+Jjy69I= github.com/libp2p/go-testutil v0.1.0/go.mod h1:81b2n5HypcVyrCg/MJx4Wgfp/VHojytjVe/gLzZ2Ehc= github.com/libp2p/go-ws-transport v0.0.5/go.mod h1:Qbl4BxPfXXhhd/o0wcrgoaItHqA9tnZjoFZnxykuaXU= @@ -997,8 +1036,9 @@ github.com/libp2p/go-ws-transport v0.2.0/go.mod h1:9BHJz/4Q5A9ludYWKoGCFC5gUElzl github.com/libp2p/go-ws-transport v0.3.0/go.mod h1:bpgTJmRZAvVHrgHybCVyqoBmyLQ1fiZuEaBYusP5zsk= github.com/libp2p/go-ws-transport v0.3.1/go.mod h1:bpgTJmRZAvVHrgHybCVyqoBmyLQ1fiZuEaBYusP5zsk= github.com/libp2p/go-ws-transport v0.4.0/go.mod h1:EcIEKqf/7GDjth6ksuS/6p7R49V4CBY6/E7R/iyhYUA= -github.com/libp2p/go-ws-transport v0.5.0 h1:cO6x4P0v6PfxbKnxmf5cY2Ny4OPDGYkUqNvZzp/zdlo= github.com/libp2p/go-ws-transport v0.5.0/go.mod h1:I2juo1dNTbl8BKSBYo98XY85kU2xds1iamArLvl8kNg= +github.com/libp2p/go-ws-transport v0.6.0 h1:326XBL6Q+5CQ2KtjXz32+eGu02W/Kz2+Fm4SpXdr0q4= +github.com/libp2p/go-ws-transport v0.6.0/go.mod h1:dXqtI9e2JV9FtF1NOtWVZSKXh5zXvnuwPXfj8GPBbYU= github.com/libp2p/go-yamux v1.2.1/go.mod h1:FGTiPvoV/3DVdgWpX+tM0OW3tsM+W5bSE3gZwqQTcow= github.com/libp2p/go-yamux v1.2.2/go.mod h1:FGTiPvoV/3DVdgWpX+tM0OW3tsM+W5bSE3gZwqQTcow= github.com/libp2p/go-yamux v1.2.3/go.mod h1:FGTiPvoV/3DVdgWpX+tM0OW3tsM+W5bSE3gZwqQTcow= @@ -1011,8 +1051,10 @@ github.com/libp2p/go-yamux v1.4.1 h1:P1Fe9vF4th5JOxxgQvfbOHkrGqIZniTLf+ddhZp8YTI github.com/libp2p/go-yamux v1.4.1/go.mod h1:fr7aVgmdNGJK+N1g+b6DW6VxzbRCjCOejR/hkmpooHE= github.com/libp2p/go-yamux/v2 v2.0.0/go.mod h1:NVWira5+sVUIU6tu1JWvaRn1dRnG+cawOJiflsAM+7U= github.com/libp2p/go-yamux/v2 v2.2.0/go.mod h1:3So6P6TV6r75R9jiBpiIKgU/66lOarCZjqROGxzPpPQ= -github.com/libp2p/go-yamux/v2 v2.3.0 h1:luRV68GS1vqqr6EFUjtu1kr51d+IbW0gSowu8emYWAI= github.com/libp2p/go-yamux/v2 v2.3.0/go.mod h1:iTU+lOIn/2h0AgKcL49clNTwfEw+WSfDYrXe05EyKIs= +github.com/libp2p/go-yamux/v3 v3.0.1/go.mod h1:s2LsDhHbh+RfCsQoICSYt58U2f8ijtPANFD8BmE74Bo= +github.com/libp2p/go-yamux/v3 v3.0.2 h1:LW0q5+A1Wy0npEsPJP9wmare2NH4ohNluN5EWVwv2mE= +github.com/libp2p/go-yamux/v3 v3.0.2/go.mod h1:s2LsDhHbh+RfCsQoICSYt58U2f8ijtPANFD8BmE74Bo= github.com/libp2p/zeroconf/v2 v2.1.1 h1:XAuSczA96MYkVwH+LqqqCUZb2yH3krobMJ1YE+0hG2s= github.com/libp2p/zeroconf/v2 v2.1.1/go.mod h1:fuJqLnUwZTshS3U/bMRJ3+ow/v9oid1n0DmyYyNO1Xs= github.com/lightstep/lightstep-tracer-common/golang/gogo v0.0.0-20190605223551-bc2310a04743/go.mod h1:qklhhLq1aX+mtWk9cPHPzaBjWImj5ULL6C7HFJtXQMM= @@ -1020,8 +1062,9 @@ github.com/lightstep/lightstep-tracer-go v0.18.1/go.mod h1:jlF1pusYV4pidLvZ+XD0U github.com/lucas-clemente/quic-go v0.19.3/go.mod h1:ADXpNbTQjq1hIzCpB+y/k5iz4n4z4IwqoLb94Kh5Hu8= github.com/lucas-clemente/quic-go v0.21.2/go.mod h1:vF5M1XqhBAHgbjKcJOXY3JZz3GP0T3FQhz/uyOUS38Q= github.com/lucas-clemente/quic-go v0.23.0/go.mod h1:paZuzjXCE5mj6sikVLMvqXk8lJV2AsqtJ6bDhjEfxx0= -github.com/lucas-clemente/quic-go v0.24.0 h1:ToR7SIIEdrgOhgVTHvPgdVRJfgVy+N0wQAagH7L4d5g= github.com/lucas-clemente/quic-go v0.24.0/go.mod h1:paZuzjXCE5mj6sikVLMvqXk8lJV2AsqtJ6bDhjEfxx0= +github.com/lucas-clemente/quic-go v0.25.0 h1:K+X9Gvd7JXsOHtU0N2icZ2Nw3rx82uBej3mP4CLgibc= +github.com/lucas-clemente/quic-go v0.25.0/go.mod h1:YtzP8bxRVCBlO77yRanE264+fY/T2U9ZlW1AaHOsMOg= github.com/lunixbochs/vtclean v1.0.0/go.mod h1:pHhQNgMf3btfWnGBVipUOjRYhoOsdGqdm/+2c2E2WMI= github.com/lyft/protoc-gen-validate v0.0.13/go.mod h1:XbGvPuh87YZc5TdIa2/I4pLk0QoUACkjt2znoq26NVQ= github.com/magiconair/properties v1.8.0/go.mod h1:PppfXfuXeibc/6YijjN8zIbojt8czPbwD3XqdrwzmxQ= @@ -1037,6 +1080,8 @@ github.com/marten-seemann/qtls-go1-16 v0.1.4/go.mod h1:gNpI2Ol+lRS3WwSOtIUUtRwZE github.com/marten-seemann/qtls-go1-17 v0.1.0-rc.1/go.mod h1:fz4HIxByo+LlWcreM4CZOYNuz3taBQ8rN2X6FqvaWo8= github.com/marten-seemann/qtls-go1-17 v0.1.0 h1:P9ggrs5xtwiqXv/FHNwntmuLMNq3KaSIG93AtAZ48xk= github.com/marten-seemann/qtls-go1-17 v0.1.0/go.mod h1:fz4HIxByo+LlWcreM4CZOYNuz3taBQ8rN2X6FqvaWo8= +github.com/marten-seemann/qtls-go1-18 v0.1.0-beta.1 h1:EnzzN9fPUkUck/1CuY1FlzBaIYMoiBsdwTNmNGkwUUM= +github.com/marten-seemann/qtls-go1-18 v0.1.0-beta.1/go.mod h1:PUhIQk19LoFt2174H4+an8TYvWOGjb/hHwphBeaDHwI= github.com/marten-seemann/tcp v0.0.0-20210406111302-dfbc87cc63fd h1:br0buuQ854V8u83wA0rVZ8ttrq5CpaPZdvrK0LP2lOk= github.com/marten-seemann/tcp v0.0.0-20210406111302-dfbc87cc63fd/go.mod h1:QuCEs1Nt24+FYQEqAAncTDPJIuGs+LxK1MCiFL25pMU= github.com/mattn/go-colorable v0.0.9/go.mod h1:9vuHe8Xs5qXnSaW/c/ABM9alt+Vo+STaOChaDxuIBZU= @@ -1049,8 +1094,9 @@ github.com/mattn/go-isatty v0.0.4/go.mod h1:M+lRXTBqGeGNdLjl/ufCoiOlB5xdOkqRJdNx github.com/mattn/go-isatty v0.0.5/go.mod h1:Iq45c/XA43vh69/j3iqttzPXn0bhXyGjM0Hdxcsrc5s= github.com/mattn/go-isatty v0.0.8/go.mod h1:Iq45c/XA43vh69/j3iqttzPXn0bhXyGjM0Hdxcsrc5s= github.com/mattn/go-isatty v0.0.11/go.mod h1:PhnuNfih5lzO57/f3n+odYbM4JtupLOxQOAqxQCu2WE= -github.com/mattn/go-isatty v0.0.13 h1:qdl+GuBjcsKKDco5BsxPJlId98mSWNKqYA+Co0SC1yA= github.com/mattn/go-isatty v0.0.13/go.mod h1:cbi8OIDigv2wuxKPP5vlRcQ1OAZbq2CE4Kysco4FUpU= +github.com/mattn/go-isatty v0.0.14 h1:yVuAays6BHfxijgZPzw+3Zlu5yQgKGP2/hcQbHb7S9Y= +github.com/mattn/go-isatty v0.0.14/go.mod h1:7GGIvUiUoEMVVmxf/4nioHXj79iQHKdU27kJ6hsGG94= github.com/mattn/go-runewidth v0.0.2/go.mod h1:LwmH8dsx7+W8Uxz3IHJYH5QSwggIsqBzpuz5H//U1FU= github.com/mattn/go-runewidth v0.0.4 h1:2BvfKmzob6Bmd4YsL0zygOqfdFnK7GR4QL06Do4/p7Y= github.com/mattn/go-runewidth v0.0.4/go.mod h1:LwmH8dsx7+W8Uxz3IHJYH5QSwggIsqBzpuz5H//U1FU= @@ -1116,8 +1162,9 @@ github.com/multiformats/go-multiaddr v0.3.0/go.mod h1:dF9kph9wfJ+3VLAaeBqo9Of8x4 github.com/multiformats/go-multiaddr v0.3.1/go.mod h1:uPbspcUPd5AfaP6ql3ujFY+QWzmBD8uLLL4bXW0XfGc= github.com/multiformats/go-multiaddr v0.3.3/go.mod h1:lCKNGP1EQ1eZ35Za2wlqnabm9xQkib3fyB+nZXHLag0= github.com/multiformats/go-multiaddr v0.4.0/go.mod h1:YcpyLH8ZPudLxQlemYBPhSm0/oCXAT8Z4mzFpyoPyRc= -github.com/multiformats/go-multiaddr v0.4.1 h1:Pq37uLx3hsyNlTDir7FZyU8+cFCTqd5y1KiM2IzOutI= github.com/multiformats/go-multiaddr v0.4.1/go.mod h1:3afI9HfVW8csiF8UZqtpYRiDyew8pRX7qLIGHu9FLuM= +github.com/multiformats/go-multiaddr v0.5.0 h1:i/JuOoVg4szYQ4YEzDGtb2h0o8M7CG/Yq6cGlcjWZpM= +github.com/multiformats/go-multiaddr v0.5.0/go.mod h1:3KAxNkUqLTJ20AAwN4XVX4kZar+bR+gh4zgbfr3SNug= github.com/multiformats/go-multiaddr-dns v0.0.1/go.mod h1:9kWcqw/Pj6FwxAwW38n/9403szc57zJPs45fmnznu3Q= github.com/multiformats/go-multiaddr-dns v0.0.2/go.mod h1:9kWcqw/Pj6FwxAwW38n/9403szc57zJPs45fmnznu3Q= github.com/multiformats/go-multiaddr-dns v0.2.0/go.mod h1:TJ5pr5bBO7Y1B18djPuRsVkduhQH2YqYSbxWJzYGdK0= @@ -1140,7 +1187,6 @@ github.com/multiformats/go-multibase v0.0.3 h1:l/B6bJDQjvQ5G52jw4QGSYeOTZoAwIO77 github.com/multiformats/go-multibase v0.0.3/go.mod h1:5+1R4eQrT3PkYZ24C3W2Ue2tPwIdYQD509ZjSb5y9Oc= github.com/multiformats/go-multicodec v0.2.0/go.mod h1:/y4YVwkfMyry5kFbMTbLJKErhycTIftytRV+llXdyS4= github.com/multiformats/go-multicodec v0.3.0/go.mod h1:qGGaQmioCDh+TeFOnxrbU0DaIPw8yFgAZgFG0V7p1qQ= -github.com/multiformats/go-multicodec v0.3.1-0.20210902112759-1539a079fd61 h1:ZrUuMKNgJ52qHPoQ+bx0h0uBfcWmN7Px+4uKSZeesiI= github.com/multiformats/go-multicodec v0.3.1-0.20210902112759-1539a079fd61/go.mod h1:1Hj/eHRaVWSXiSNNfcEPcwZleTmdNP81xlxDLnWU9GQ= github.com/multiformats/go-multicodec v0.4.0 h1:fbqb6ky7erjdD+/zaEBJgZWu1i8D6i/wmPywGK7sdow= github.com/multiformats/go-multicodec v0.4.0/go.mod h1:1Hj/eHRaVWSXiSNNfcEPcwZleTmdNP81xlxDLnWU9GQ= @@ -1203,6 +1249,8 @@ github.com/onsi/gomega v1.10.1/go.mod h1:iN09h71vgCQne3DLsj+A5owkum+a2tYe+TOCB1y github.com/onsi/gomega v1.13.0 h1:7lLHu94wT9Ij0o6EWWclhu0aOh32VxhkwEJvzuWPeak= github.com/onsi/gomega v1.13.0/go.mod h1:lRk9szgn8TxENtWd0Tp4c3wjlRfMTMH27I+3Je41yGY= github.com/op/go-logging v0.0.0-20160315200505-970db520ece7/go.mod h1:HzydrMdWErDVzsI23lYNej1Htcns9BCg93Dk0bBINWk= +github.com/opencontainers/runtime-spec v1.0.2 h1:UfAcuLBJB9Coz72x1hgl8O5RVzTdNiaglX6v2DM6FI0= +github.com/opencontainers/runtime-spec v1.0.2/go.mod h1:jwyrGlmzljRJv/Fgzds9SsS/C5hL+LL3ko9hs6T5lQ0= github.com/opentracing-contrib/go-observer v0.0.0-20170622124052-a52f23424492/go.mod h1:Ngi6UdF0k5OKD5t5wlmGhe/EDKPoUM3BXZSSfIuJbis= github.com/opentracing/basictracer-go v1.0.0/go.mod h1:QfBfYuafItcjQuMwinw9GhYKwFXS9KnPs5lxoYwgW74= github.com/opentracing/opentracing-go v1.0.2/go.mod h1:UkNAQd3GIcIGf0SeVgPpRdFStlNbqXla1AfSYxPUl2o= @@ -1216,6 +1264,8 @@ github.com/openzipkin/zipkin-go v0.2.1/go.mod h1:NaW6tEwdmWMaCDZzg8sh+IBNOxHMPnh github.com/openzipkin/zipkin-go v0.2.2/go.mod h1:NaW6tEwdmWMaCDZzg8sh+IBNOxHMPnhQw8ySjnjRyN4= github.com/pact-foundation/pact-go v1.0.4/go.mod h1:uExwJY4kCzNPcHRj+hCR/HBbOOIwwtUjcrb0b5/5kLM= github.com/pascaldekloe/goe v0.0.0-20180627143212-57f6aae5913c/go.mod h1:lzWF7FIEvWOWxwDKqyGYQf6ZUaNfKdP144TG7ZOy1lc= +github.com/pbnjay/memory v0.0.0-20210728143218-7b4eea64cf58 h1:onHthvaw9LFnH4t2DcNVpwGmV9E1BkGknEliJkfwQj0= +github.com/pbnjay/memory v0.0.0-20210728143218-7b4eea64cf58/go.mod h1:DXv8WO4yhMYhSNPKjeNKa5WY9YCIEBRbNzFFPJbWO6Y= github.com/pborman/uuid v1.2.0/go.mod h1:X/NO0urCmaxf9VXbdlT7C2Yzkj2IKimNn4k+gtPdI/k= github.com/pelletier/go-toml v1.2.0/go.mod h1:5z9KED0ma1S8pY6P1sdut58dfprrGBbd/94hg7ilaic= github.com/performancecopilot/speed v3.0.0+incompatible/go.mod h1:/CLtqpZ5gBg1M9iaPbIdPPGyKcA8hKdoy6hAWba7Yac= @@ -1279,6 +1329,10 @@ github.com/prometheus/procfs v0.7.3 h1:4jVXhlkAyzOScmCkXBTOLRLTz8EeU+eyjrwB/EPq0 github.com/prometheus/procfs v0.7.3/go.mod h1:cz+aTbrPOrUb4q7XlbU9ygM+/jj0fzG6c1xBZuNvfVA= github.com/prometheus/statsd_exporter v0.21.0 h1:hA05Q5RFeIjgwKIYEdFd59xu5Wwaznf33yKI+pyX6T8= github.com/prometheus/statsd_exporter v0.21.0/go.mod h1:rbT83sZq2V+p73lHhPZfMc3MLCHmSHelCh9hSGYNLTQ= +github.com/raulk/clock v1.1.0 h1:dpb29+UKMbLqiU/jqIJptgLR1nn23HLgMY0sTCDza5Y= +github.com/raulk/clock v1.1.0/go.mod h1:3MpVxdZ/ODBQDxbN+kzshf5OSZwPjtMDx6BBXBmOeY0= +github.com/raulk/go-watchdog v1.2.0 h1:konN75pw2BMmZ+AfuAm5rtFsWcJpKF3m02rKituuXNo= +github.com/raulk/go-watchdog v1.2.0/go.mod h1:lzSbAl5sh4rtI8tYHU01BWIDzgzqaQLj6RcA1i4mlqI= github.com/rcrowley/go-metrics v0.0.0-20181016184325-3113b8401b8a/go.mod h1:bCqnVzQkZxMG4s8nGwiZ5l3QUCyqpo9Y+/ZMZ9VjZe4= github.com/rogpeppe/fastuuid v0.0.0-20150106093220-6724a57986af/go.mod h1:XWv6SoW27p1b0cqNHllgS5HIMJraePCO15w5zCzIWYg= github.com/rogpeppe/fastuuid v1.2.0/go.mod h1:jVj6XXZzXRy/MSR5jhDC/2q6DgLz+nrA6LYCDYWNEvQ= @@ -1322,6 +1376,7 @@ github.com/shurcooL/webdavfs v0.0.0-20170829043945-18c3829fa133/go.mod h1:hKmq5k github.com/sirupsen/logrus v1.2.0/go.mod h1:LxeOpSwHxABJmUn/MG1IvRgCAasNZTLOkJPxbbu5VWo= github.com/sirupsen/logrus v1.4.2/go.mod h1:tLMulIdttU9McNUspp0xgXVQah82FyeX6MwdIuYE2rE= github.com/sirupsen/logrus v1.6.0/go.mod h1:7uNnSEd1DgxDLC74fIahvMZmmYsHGZGEOFrfsX/uA88= +github.com/sirupsen/logrus v1.7.0/go.mod h1:yWOB1SBYBC5VeMP7gHvWumXLIWorT60ONWic61uBYv0= github.com/sirupsen/logrus v1.8.1/go.mod h1:yWOB1SBYBC5VeMP7gHvWumXLIWorT60ONWic61uBYv0= github.com/smartystreets/assertions v0.0.0-20180927180507-b2de0cb4f26d/go.mod h1:OnSkiWE9lh6wB0YB77sQom3nweQdgAjqCqsofrRNTgc= github.com/smartystreets/assertions v1.0.0 h1:UVQPSSmc3qtTi+zPPkCXvZX9VvW/xT/NsRvKfwY81a8= @@ -1374,6 +1429,7 @@ github.com/tv42/httpunix v0.0.0-20191220191345-2ba4b9c3382c/go.mod h1:hzIxponao9 github.com/ugorji/go/codec v0.0.0-20181204163529-d75b2dcb6bc8/go.mod h1:VFNgLljTbGfSG7qAOspJ7OScBnGdDN/yBr0sguwnwf0= github.com/urfave/cli v1.20.0/go.mod h1:70zkFmudgCuE/ngEzBv17Jvp/497gISqfk5gWijbERA= github.com/urfave/cli v1.22.1/go.mod h1:Gos4lmkARVdJ6EkW0WaNv/tZAAMe9V7XWyB60NtXRu0= +github.com/urfave/cli v1.22.2/go.mod h1:Gos4lmkARVdJ6EkW0WaNv/tZAAMe9V7XWyB60NtXRu0= github.com/urfave/cli/v2 v2.0.0/go.mod h1:SE9GqnLQmjVa0iPEY0f1w3ygNIYcIJ0OKPMoW2caLfQ= github.com/viant/assertly v0.4.8/go.mod h1:aGifi++jvCrUaklKEKT0BU95igDNaqkvz+49uaYMPRU= github.com/viant/toolbox v0.24.0/go.mod h1:OxMCG57V0PXuIP2HNQrtJf2CjqdmbrOx5EkMILuUhzM= @@ -1475,6 +1531,7 @@ go.uber.org/fx v1.16.0 h1:N8i80+X1DCX+qMRiKzM+jPPZiIiyK/bVCysga3+B+1w= go.uber.org/fx v1.16.0/go.mod h1:OMoT5BnXcOaiexlpjtpE4vcAmzyDKyRs9TRYXCzamx8= go.uber.org/goleak v1.0.0/go.mod h1:8a7PlsEVH3e/a/GLqe5IIrQx6GzcnRmZEufDUTk4A7A= go.uber.org/goleak v1.1.10/go.mod h1:8a7PlsEVH3e/a/GLqe5IIrQx6GzcnRmZEufDUTk4A7A= +go.uber.org/goleak v1.1.11-0.20210813005559-691160354723/go.mod h1:cwTWslyiVhfpKIDGSZEM2HlOvcqm+tG4zioyIeLoqMQ= go.uber.org/goleak v1.1.11 h1:wy28qYRKZgnJTxGxvye5/wgWr1EKjmUDGYox5mGlRlI= go.uber.org/goleak v1.1.11/go.mod h1:cwTWslyiVhfpKIDGSZEM2HlOvcqm+tG4zioyIeLoqMQ= go.uber.org/multierr v1.1.0/go.mod h1:wR5kodmAFQ0UK8QlbwjlSNy0Z68gJhDJUG5sjR94q/0= @@ -1491,6 +1548,7 @@ go.uber.org/zap v1.15.0/go.mod h1:Mb2vm2krFEG5DV0W9qcHBYFtp/Wku1cvYaqPsS/WYfc= go.uber.org/zap v1.16.0/go.mod h1:MA8QOfq0BHJwdXa996Y4dYkAqRKB8/1K1QMMZVaNZjQ= go.uber.org/zap v1.18.1/go.mod h1:xg/QME4nWcxGxrpdeYfq7UvYrLh66cuVKdrbD1XF/NI= go.uber.org/zap v1.19.0/go.mod h1:xg/QME4nWcxGxrpdeYfq7UvYrLh66cuVKdrbD1XF/NI= +go.uber.org/zap v1.19.1/go.mod h1:j3DNczoxDZroyBnOT1L/Q79cfUMGZxlv/9dzN7SM1rI= go.uber.org/zap v1.21.0 h1:WefMeulhovoZ2sYXz7st6K0sLj7bBhpiFaud4r4zST8= go.uber.org/zap v1.21.0/go.mod h1:wjWOCqI0f2ZZrJF/UufIOkiC8ii6tm1iqIsLo76RfJw= go4.org v0.0.0-20180809161055-417644f6feb5/go.mod h1:MkTOUMDaeVYJUOUsaDXIhWPZYa1yOyC1qaOBpL57BhE= @@ -1649,6 +1707,7 @@ golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJ golang.org/x/sync v0.0.0-20201207232520-09787c993a3a/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20210220032951-036812b2e83c h1:5KslGYwFpkhGh+Q16bwMP3cOontH8FOep7tGV86Y7SQ= golang.org/x/sync v0.0.0-20210220032951-036812b2e83c/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sys v0.0.0-20180810173357-98c5dad5d1a0/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20180823144017-11551d06cbcc/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20180905080454-ebe1bf3edb33/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= @@ -1695,6 +1754,7 @@ golang.org/x/sys v0.0.0-20200106162015-b016eb3dc98e/go.mod h1:h1NjWce9XRLGQEsW7w golang.org/x/sys v0.0.0-20200113162924-86b910548bc1/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200116001909-b77594299b42/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200122134326-e047566fdf82/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200124204421-9fbb57f87de9/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200202164722-d101bd2416d5/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200212091648-12a6c2dcc1e4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200223170610-d5e6a3e2c0ae/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= diff --git a/peering/peering_test.go b/peering/peering_test.go index 27c9b717514..09a54f2ce1e 100644 --- a/peering/peering_test.go +++ b/peering/peering_test.go @@ -6,20 +6,22 @@ import ( "time" "github.com/libp2p/go-libp2p" - connmgr "github.com/libp2p/go-libp2p-connmgr" "github.com/libp2p/go-libp2p-core/host" "github.com/libp2p/go-libp2p-core/network" "github.com/libp2p/go-libp2p-core/peer" + "github.com/libp2p/go-libp2p/p2p/net/connmgr" "github.com/stretchr/testify/require" ) -func newNode(ctx context.Context, t *testing.T) host.Host { +func newNode(t *testing.T) host.Host { + cm, err := connmgr.NewConnManager(1, 100, connmgr.WithGracePeriod(0)) + require.NoError(t, err) h, err := libp2p.New( libp2p.ListenAddrStrings("/ip4/127.0.0.1/tcp/0"), // We'd like to set the connection manager low water to 0, but // that would disable the connection manager. - libp2p.ConnectionManager(connmgr.NewConnManager(1, 100, 0)), + libp2p.ConnectionManager(cm), ) require.NoError(t, err) return h @@ -29,12 +31,12 @@ func TestPeeringService(t *testing.T) { ctx, cancel := context.WithCancel(context.Background()) defer cancel() - h1 := newNode(ctx, t) + h1 := newNode(t) ps1 := NewPeeringService(h1) - h2 := newNode(ctx, t) - h3 := newNode(ctx, t) - h4 := newNode(ctx, t) + h2 := newNode(t) + h3 := newNode(t) + h4 := newNode(t) // peer 1 -> 2 ps1.AddPeer(peer.AddrInfo{ID: h2.ID(), Addrs: h2.Addrs()}) diff --git a/test/integration/addcat_test.go b/test/integration/addcat_test.go index eebc1f63f76..f564ee5ee3e 100644 --- a/test/integration/addcat_test.go +++ b/test/integration/addcat_test.go @@ -18,8 +18,8 @@ import ( mock "github.com/ipfs/go-ipfs/core/mock" "github.com/ipfs/go-ipfs/thirdparty/unit" logging "github.com/ipfs/go-log" - random "github.com/jbenet/go-random" - peer "github.com/libp2p/go-libp2p-core/peer" + "github.com/jbenet/go-random" + "github.com/libp2p/go-libp2p-core/peer" testutil "github.com/libp2p/go-libp2p-testing/net" mocknet "github.com/libp2p/go-libp2p/p2p/net/mock" ) @@ -97,7 +97,7 @@ func DirectAddCat(data []byte, conf testutil.LatencyConfig) error { defer cancel() // create network - mn := mocknet.New(ctx) + mn := mocknet.New() mn.SetLinkDefaults(mocknet.LinkOptions{ Latency: conf.NetworkLatency, // TODO add to conf. This is tricky because we want 0 values to be functional. diff --git a/test/integration/bench_cat_test.go b/test/integration/bench_cat_test.go index 6115b5b54dd..45b3b9f3e28 100644 --- a/test/integration/bench_cat_test.go +++ b/test/integration/bench_cat_test.go @@ -14,7 +14,7 @@ import ( "github.com/ipfs/go-ipfs/core/coreapi" mock "github.com/ipfs/go-ipfs/core/mock" "github.com/ipfs/go-ipfs/thirdparty/unit" - peer "github.com/libp2p/go-libp2p-core/peer" + "github.com/libp2p/go-libp2p-core/peer" testutil "github.com/libp2p/go-libp2p-testing/net" mocknet "github.com/libp2p/go-libp2p/p2p/net/mock" ) @@ -40,7 +40,7 @@ func benchCat(b *testing.B, data []byte, conf testutil.LatencyConfig) error { defer cancel() // create network - mn := mocknet.New(ctx) + mn := mocknet.New() mn.SetLinkDefaults(mocknet.LinkOptions{ Latency: conf.NetworkLatency, // TODO add to conf. This is tricky because we want 0 values to be functional. diff --git a/test/integration/bitswap_wo_routing_test.go b/test/integration/bitswap_wo_routing_test.go index ec0c2f11a83..9caa78c38c5 100644 --- a/test/integration/bitswap_wo_routing_test.go +++ b/test/integration/bitswap_wo_routing_test.go @@ -19,7 +19,7 @@ func TestBitswapWithoutRouting(t *testing.T) { const numPeers = 4 // create network - mn := mocknet.New(ctx) + mn := mocknet.New() var nodes []*core.IpfsNode for i := 0; i < numPeers; i++ { diff --git a/test/integration/three_legged_cat_test.go b/test/integration/three_legged_cat_test.go index eb82d00083a..009d1af32d6 100644 --- a/test/integration/three_legged_cat_test.go +++ b/test/integration/three_legged_cat_test.go @@ -15,7 +15,7 @@ import ( "github.com/ipfs/go-ipfs/thirdparty/unit" files "github.com/ipfs/go-ipfs-files" - peer "github.com/libp2p/go-libp2p-core/peer" + "github.com/libp2p/go-libp2p-core/peer" testutil "github.com/libp2p/go-libp2p-testing/net" mocknet "github.com/libp2p/go-libp2p/p2p/net/mock" ) @@ -68,7 +68,7 @@ func RunThreeLeggedCat(data []byte, conf testutil.LatencyConfig) error { defer cancel() // create network - mn := mocknet.New(ctx) + mn := mocknet.New() mn.SetLinkDefaults(mocknet.LinkOptions{ Latency: conf.NetworkLatency, // TODO add to conf. This is tricky because we want 0 values to be functional. diff --git a/test/integration/wan_lan_dht_test.go b/test/integration/wan_lan_dht_test.go index da2468d5a1e..44305e05174 100644 --- a/test/integration/wan_lan_dht_test.go +++ b/test/integration/wan_lan_dht_test.go @@ -72,7 +72,7 @@ func RunDHTConnectivity(conf testutil.LatencyConfig, numPeers int) error { defer cancel() // create network - mn := mocknet.New(ctx) + mn := mocknet.New() mn.SetLinkDefaults(mocknet.LinkOptions{ Latency: conf.NetworkLatency, Bandwidth: math.MaxInt32, @@ -209,9 +209,9 @@ WanStartupWait: for { select { case err := <-testPeer.DHT.WAN.RefreshRoutingTable(): - //if err != nil { + // if err != nil { // fmt.Printf("Error refreshing routing table: %v\n", err) - //} + // } if testPeer.DHT.WAN.RoutingTable() == nil || testPeer.DHT.WAN.RoutingTable().Size() == 0 || err != nil { diff --git a/test/sharness/t0139-swarm-rcmgr.sh b/test/sharness/t0139-swarm-rcmgr.sh new file mode 100755 index 00000000000..39bbf1d5204 --- /dev/null +++ b/test/sharness/t0139-swarm-rcmgr.sh @@ -0,0 +1,66 @@ +#!/usr/bin/env bash +# +test_description="Test ipfs swarm ResourceMgr config and commands" + +. lib/test-lib.sh + +test_init_ipfs + +# swarm limit|stats should fail in offline mode + +test_expect_success 'disconnected: swarm limit requires running daemon' ' + test_expect_code 1 ipfs swarm limit system 2> actual && + test_should_contain "missing ResourceMgr" actual +' +test_expect_success 'disconnected: swarm stats requires running daemon' ' + test_expect_code 1 ipfs swarm stats all 2> actual && + test_should_contain "missing ResourceMgr" actual +' + +# swarm limit|stats should fail in online mode by default +# because Resource Manager is opt-in for now +test_launch_ipfs_daemon + +test_expect_success 'ResourceMgr disabled by default: swarm limit requires Swarm.ResourceMgr.Enabled' ' + test_expect_code 1 ipfs swarm limit system 2> actual && + test_should_contain "missing ResourceMgr" actual +' +test_expect_success 'ResourceMgr disabled by default: swarm stats requires Swarm.ResourceMgr.Enabled' ' + test_expect_code 1 ipfs swarm stats all 2> actual && + test_should_contain "missing ResourceMgr" actual +' + +# swarm limit|stat should work when Swarm.ResourceMgr.Enabled +test_kill_ipfs_daemon +test_expect_success "test_config_set succeeds" " + ipfs config --json Swarm.ResourceMgr.Enabled true +" +test_launch_ipfs_daemon + +# every scope has the same fields, so we only inspect System +test_expect_success 'ResourceMgr enabled: swarm limit' ' + ipfs swarm limit system --enc=json | tee json && + jq -e .Conns < json && + jq -e .ConnsInbound < json && + jq -e .ConnsOutbound < json && + jq -e .FD < json && + jq -e .Memory < json && + jq -e .Streams < json && + jq -e .StreamsInbound < json && + jq -e .StreamsOutbound < json +' + +# every scope has the same fields, so we only inspect System +test_expect_success 'ResourceMgr enabled: swarm stats' ' + ipfs swarm stats all --enc=json | tee json && + jq -e .System.Memory < json && + jq -e .System.NumConnsInbound < json && + jq -e .System.NumConnsOutbound < json && + jq -e .System.NumFD < json && + jq -e .System.NumStreamsInbound < json && + jq -e .System.NumStreamsOutbound < json && + jq -e .Transient.Memory < json +' + +test_kill_ipfs_daemon +test_done From 5d712166b292aef2bb770c036182ec261fc08357 Mon Sep 17 00:00:00 2001 From: Marcin Rataj Date: Fri, 8 Apr 2022 17:43:30 +0200 Subject: [PATCH 344/414] feat: detect changes in go-libp2p-resource-manager (#8857) This adds simple check that will scream loud and clear every time go-libp2p libraries change any of the implicit defaults related to go-libp2p-resource-manager --- core/node/libp2p/rcmgr.go | 2 +- core/node/libp2p/rcmgr_defaults.go | 825 ++++++++++++++++++++--------- go.mod | 1 + go.sum | 8 + 4 files changed, 594 insertions(+), 242 deletions(-) diff --git a/core/node/libp2p/rcmgr.go b/core/node/libp2p/rcmgr.go index d0bccd277fe..511e3185242 100644 --- a/core/node/libp2p/rcmgr.go +++ b/core/node/libp2p/rcmgr.go @@ -69,7 +69,7 @@ func ResourceManager(cfg config.SwarmConfig) func(fx.Lifecycle, repo.Repo) (netw return nil, opts, err } - setDefaultServiceLimits(limiter) // see rcmgr_defaults.go + libp2p.SetDefaultServiceLimits(limiter) ropts := []rcmgr.Option{rcmgr.WithMetrics(createRcmgrMetrics())} diff --git a/core/node/libp2p/rcmgr_defaults.go b/core/node/libp2p/rcmgr_defaults.go index dddc2b32411..e5e0cbb346f 100644 --- a/core/node/libp2p/rcmgr_defaults.go +++ b/core/node/libp2p/rcmgr_defaults.go @@ -1,27 +1,25 @@ package libp2p import ( + "encoding/json" + "fmt" "math/bits" + "strings" config "github.com/ipfs/go-ipfs/config" - "github.com/libp2p/go-libp2p-core/protocol" + "github.com/libp2p/go-libp2p" rcmgr "github.com/libp2p/go-libp2p-resource-manager" - "github.com/libp2p/go-libp2p/p2p/host/autonat" - relayv1 "github.com/libp2p/go-libp2p/p2p/protocol/circuitv1/relay" - circuit "github.com/libp2p/go-libp2p/p2p/protocol/circuitv2/proto" - relayv2 "github.com/libp2p/go-libp2p/p2p/protocol/circuitv2/relay" - "github.com/libp2p/go-libp2p/p2p/protocol/holepunch" - "github.com/libp2p/go-libp2p/p2p/protocol/identify" - "github.com/libp2p/go-libp2p/p2p/protocol/ping" + + "github.com/wI2L/jsondiff" ) // This file defines implicit limit defaults used when Swarm.ResourceMgr.Enabled -// We keep vendored copy to ensure go-ipfs is not impacted when go-libp2p decides -// to change defaults in any of the future releases. // adjustedDefaultLimits allows for tweaking defaults based on external factors, // such as values in Swarm.ConnMgr.HiWater config. func adjustedDefaultLimits(cfg config.SwarmConfig) rcmgr.DefaultLimitConfig { + // Run checks to avoid introducing regressions + checkImplicitDefaults() // Return to use unmodified static limits based on values from go-libp2p 0.18 // return defaultLimits @@ -30,7 +28,7 @@ func adjustedDefaultLimits(cfg config.SwarmConfig) rcmgr.DefaultLimitConfig { // (based on https://github.com/filecoin-project/lotus/pull/8318/files) // - give it more memory, up to 4G, min of 1G // - if Swarm.ConnMgr.HighWater is too high, adjust Conn/FD/Stream limits - defaultLimits := staticDefaultLimits.WithSystemMemory(.125, 1<<30, 4<<30) + defaultLimits := rcmgr.DefaultLimits.WithSystemMemory(.125, 1<<30, 4<<30) // Do we need to adjust due to Swarm.ConnMgr.HighWater? if cfg.ConnMgr.Type == "basic" { @@ -67,247 +65,592 @@ func logScale(val int) int { return 1 << bitlen } -// defaultLimits are the limits used by the default rcmgr limiter constructors. -// This is a vendored copy of -// https://github.com/libp2p/go-libp2p-resource-manager/blob/v0.1.5/limit_defaults.go#L49 -var staticDefaultLimits = rcmgr.DefaultLimitConfig{ - SystemBaseLimit: rcmgr.BaseLimit{ - StreamsInbound: 4096, - StreamsOutbound: 16384, - Streams: 16384, - ConnsInbound: 256, - ConnsOutbound: 1024, - Conns: 1024, - FD: 512, - }, - - SystemMemory: rcmgr.MemoryLimit{ - MemoryFraction: 0.125, - MinMemory: 128 << 20, - MaxMemory: 1 << 30, - }, - - TransientBaseLimit: rcmgr.BaseLimit{ - StreamsInbound: 128, - StreamsOutbound: 512, - Streams: 512, - ConnsInbound: 32, - ConnsOutbound: 128, - Conns: 128, - FD: 128, - }, - - TransientMemory: rcmgr.MemoryLimit{ - MemoryFraction: 1, - MinMemory: 64 << 20, - MaxMemory: 64 << 20, - }, - - ServiceBaseLimit: rcmgr.BaseLimit{ - StreamsInbound: 2048, - StreamsOutbound: 8192, - Streams: 8192, - }, - - ServiceMemory: rcmgr.MemoryLimit{ - MemoryFraction: 0.125 / 4, - MinMemory: 64 << 20, - MaxMemory: 256 << 20, - }, - - ServicePeerBaseLimit: rcmgr.BaseLimit{ - StreamsInbound: 256, - StreamsOutbound: 512, - Streams: 512, - }, - - ServicePeerMemory: rcmgr.MemoryLimit{ - MemoryFraction: 0.125 / 16, - MinMemory: 16 << 20, - MaxMemory: 64 << 20, - }, - - ProtocolBaseLimit: rcmgr.BaseLimit{ - StreamsInbound: 1024, - StreamsOutbound: 4096, - Streams: 4096, - }, - - ProtocolMemory: rcmgr.MemoryLimit{ - MemoryFraction: 0.125 / 8, - MinMemory: 64 << 20, - MaxMemory: 128 << 20, - }, - - ProtocolPeerBaseLimit: rcmgr.BaseLimit{ - StreamsInbound: 128, - StreamsOutbound: 256, - Streams: 512, - }, - - ProtocolPeerMemory: rcmgr.MemoryLimit{ - MemoryFraction: 0.125 / 16, - MinMemory: 16 << 20, - MaxMemory: 64 << 20, - }, - - PeerBaseLimit: rcmgr.BaseLimit{ - StreamsInbound: 512, - StreamsOutbound: 1024, - Streams: 1024, - ConnsInbound: 8, - ConnsOutbound: 16, - Conns: 16, - FD: 8, - }, - - PeerMemory: rcmgr.MemoryLimit{ - MemoryFraction: 0.125 / 16, - MinMemory: 64 << 20, - MaxMemory: 128 << 20, - }, - - ConnBaseLimit: rcmgr.BaseLimit{ - ConnsInbound: 1, - ConnsOutbound: 1, - Conns: 1, - FD: 1, - }, - - ConnMemory: 1 << 20, - - StreamBaseLimit: rcmgr.BaseLimit{ - StreamsInbound: 1, - StreamsOutbound: 1, - Streams: 1, - }, +// checkImplicitDefaults compares libp2p defaults agains expected ones +// and panics when they don't match. This ensures we are not surprised +// by silent default limit changes when we update go-libp2p dependencies. +func checkImplicitDefaults() { + ok := true - StreamMemory: 16 << 20, -} - -// setDefaultServiceLimits sets the default limits for bundled libp2p services. -// This is a vendored copy of -// https://github.com/libp2p/go-libp2p/blob/v0.18.0/limits.go -func setDefaultServiceLimits(limiter *rcmgr.BasicLimiter) { - if limiter.ServiceLimits == nil { - limiter.ServiceLimits = make(map[string]rcmgr.Limit) - } - if limiter.ServicePeerLimits == nil { - limiter.ServicePeerLimits = make(map[string]rcmgr.Limit) + // Check 1: did go-libp2p-resource-manager's DefaultLimits change? + defaults, err := json.Marshal(rcmgr.DefaultLimits) + if err != nil { + log.Fatal(err) } - if limiter.ProtocolLimits == nil { - limiter.ProtocolLimits = make(map[protocol.ID]rcmgr.Limit) + changes, err := jsonDiff([]byte(expectedDefaultLimits), defaults) + if err != nil { + log.Fatal(err) } - if limiter.ProtocolPeerLimits == nil { - limiter.ProtocolPeerLimits = make(map[protocol.ID]rcmgr.Limit) + if len(changes) > 0 { + ok = false + log.Errorf("===> OOF! go-libp2p-resource-manager changed DefaultLimits\n"+ + "=> changes ('test' represents the old value):\n%s\n"+ + "=> go-libp2p-resource-manager DefaultLimits update needs a review:\n"+ + "Please inspect if changes impact go-ipfs users, and update expectedDefaultLimits in rcmgr_defaults.go to remove this message", + strings.Join(changes, "\n"), + ) } - // identify - setServiceLimits(limiter, identify.ServiceName, - limiter.DefaultServiceLimits. - WithMemoryLimit(1, 4<<20, 64<<20). // max 64MB service memory - WithStreamLimit(128, 128, 256), // max 256 streams -- symmetric - peerLimit(16, 16, 32)) - - setProtocolLimits(limiter, identify.ID, - limiter.DefaultProtocolLimits.WithMemoryLimit(1, 4<<20, 32<<20), - peerLimit(16, 16, 32)) - setProtocolLimits(limiter, identify.IDPush, - limiter.DefaultProtocolLimits.WithMemoryLimit(1, 4<<20, 32<<20), - peerLimit(16, 16, 32)) - setProtocolLimits(limiter, identify.IDDelta, - limiter.DefaultProtocolLimits.WithMemoryLimit(1, 4<<20, 32<<20), - peerLimit(16, 16, 32)) - - // ping - setServiceLimits(limiter, ping.ServiceName, - limiter.DefaultServiceLimits. - WithMemoryLimit(1, 4<<20, 64<<20). // max 64MB service memory - WithStreamLimit(128, 128, 128), // max 128 streams - asymmetric - peerLimit(2, 3, 4)) - setProtocolLimits(limiter, ping.ID, - limiter.DefaultProtocolLimits.WithMemoryLimit(1, 4<<20, 64<<20), - peerLimit(2, 3, 4)) - - // autonat - setServiceLimits(limiter, autonat.ServiceName, - limiter.DefaultServiceLimits. - WithMemoryLimit(1, 4<<20, 64<<20). // max 64MB service memory - WithStreamLimit(128, 128, 128), // max 128 streams - asymmetric - peerLimit(2, 2, 2)) - setProtocolLimits(limiter, autonat.AutoNATProto, - limiter.DefaultProtocolLimits.WithMemoryLimit(1, 4<<20, 64<<20), - peerLimit(2, 2, 2)) - - // holepunch - setServiceLimits(limiter, holepunch.ServiceName, - limiter.DefaultServiceLimits. - WithMemoryLimit(1, 4<<20, 64<<20). // max 64MB service memory - WithStreamLimit(128, 128, 256), // max 256 streams - symmetric - peerLimit(2, 2, 2)) - setProtocolLimits(limiter, holepunch.Protocol, - limiter.DefaultProtocolLimits.WithMemoryLimit(1, 4<<20, 64<<20), - peerLimit(2, 2, 2)) - - // relay/v1 - setServiceLimits(limiter, relayv1.ServiceName, - limiter.DefaultServiceLimits. - WithMemoryLimit(1, 4<<20, 64<<20). // max 64MB service memory - WithStreamLimit(1024, 1024, 1024), // max 1024 streams - asymmetric - peerLimit(64, 64, 64)) - - // relay/v2 - setServiceLimits(limiter, relayv2.ServiceName, - limiter.DefaultServiceLimits. - WithMemoryLimit(1, 4<<20, 64<<20). // max 64MB service memory - WithStreamLimit(1024, 1024, 1024), // max 1024 streams - asymmetric - peerLimit(64, 64, 64)) + // Check 2: did go-libp2p's SetDefaultServiceLimits change? + testLimiter := rcmgr.NewStaticLimiter(rcmgr.DefaultLimits) + libp2p.SetDefaultServiceLimits(testLimiter) - // circuit protocols, both client and service - setProtocolLimits(limiter, circuit.ProtoIDv1, - limiter.DefaultProtocolLimits. - WithMemoryLimit(1, 4<<20, 64<<20). - WithStreamLimit(1280, 1280, 1280), - peerLimit(128, 128, 128)) - setProtocolLimits(limiter, circuit.ProtoIDv2Hop, - limiter.DefaultProtocolLimits. - WithMemoryLimit(1, 4<<20, 64<<20). - WithStreamLimit(1280, 1280, 1280), - peerLimit(128, 128, 128)) - setProtocolLimits(limiter, circuit.ProtoIDv2Stop, - limiter.DefaultProtocolLimits. - WithMemoryLimit(1, 4<<20, 64<<20). - WithStreamLimit(1280, 1280, 1280), - peerLimit(128, 128, 128)) - -} - -func setServiceLimits(limiter *rcmgr.BasicLimiter, svc string, limit rcmgr.Limit, peerLimit rcmgr.Limit) { - if _, ok := limiter.ServiceLimits[svc]; !ok { - limiter.ServiceLimits[svc] = limit + serviceDefaults, err := json.Marshal(testLimiter) + if err != nil { + log.Fatal(err) } - if _, ok := limiter.ServicePeerLimits[svc]; !ok { - limiter.ServicePeerLimits[svc] = peerLimit + changes, err = jsonDiff([]byte(expectedDefaultServiceLimits), serviceDefaults) + if err != nil { + log.Fatal(err) } -} - -func setProtocolLimits(limiter *rcmgr.BasicLimiter, proto protocol.ID, limit rcmgr.Limit, peerLimit rcmgr.Limit) { - if _, ok := limiter.ProtocolLimits[proto]; !ok { - limiter.ProtocolLimits[proto] = limit + if len(changes) > 0 { + ok = false + log.Errorf("===> OOF! go-libp2p changed DefaultServiceLimits\n"+ + "=> changes ('test' represents the old value):\n%s\n"+ + "=> go-libp2p SetDefaultServiceLimits update needs a review:\n"+ + "Please inspect if changes impact go-ipfs users, and update expectedDefaultServiceLimits in rcmgr_defaults.go to remove this message", + strings.Join(changes, "\n"), + ) } - if _, ok := limiter.ProtocolPeerLimits[proto]; !ok { - limiter.ProtocolPeerLimits[proto] = peerLimit + if !ok { + log.Fatal("daemon will refuse to run with the resource manager until this is resolved") } } -func peerLimit(numStreamsIn, numStreamsOut, numStreamsTotal int) rcmgr.Limit { - return &rcmgr.StaticLimit{ - // memory: 256kb for window buffers plus some change for message buffers per stream - Memory: int64(numStreamsTotal * (256<<10 + 16384)), - BaseLimit: rcmgr.BaseLimit{ - StreamsInbound: numStreamsIn, - StreamsOutbound: numStreamsOut, - Streams: numStreamsTotal, - }, +// jsonDiff compares two strings and returns diff in JSON Patch format +func jsonDiff(old []byte, updated []byte) ([]string, error) { + // generate 'invertible' patch which includes old values as "test" op + patch, err := jsondiff.CompareJSONOpts(old, updated, jsondiff.Invertible()) + changes := make([]string, len(patch)) + if err != nil { + return changes, err + } + for i, op := range patch { + changes[i] = fmt.Sprintf(" %s", op) } + return changes, nil } + +// https://github.com/libp2p/go-libp2p-resource-manager/blob/v0.1.5/limit_defaults.go#L49 +const expectedDefaultLimits = `{ + "SystemBaseLimit": { + "Streams": 16384, + "StreamsInbound": 4096, + "StreamsOutbound": 16384, + "Conns": 1024, + "ConnsInbound": 256, + "ConnsOutbound": 1024, + "FD": 512 + }, + "SystemMemory": { + "MemoryFraction": 0.125, + "MinMemory": 134217728, + "MaxMemory": 1073741824 + }, + "TransientBaseLimit": { + "Streams": 512, + "StreamsInbound": 128, + "StreamsOutbound": 512, + "Conns": 128, + "ConnsInbound": 32, + "ConnsOutbound": 128, + "FD": 128 + }, + "TransientMemory": { + "MemoryFraction": 1, + "MinMemory": 67108864, + "MaxMemory": 67108864 + }, + "ServiceBaseLimit": { + "Streams": 8192, + "StreamsInbound": 2048, + "StreamsOutbound": 8192, + "Conns": 0, + "ConnsInbound": 0, + "ConnsOutbound": 0, + "FD": 0 + }, + "ServiceMemory": { + "MemoryFraction": 0.03125, + "MinMemory": 67108864, + "MaxMemory": 268435456 + }, + "ServicePeerBaseLimit": { + "Streams": 512, + "StreamsInbound": 256, + "StreamsOutbound": 512, + "Conns": 0, + "ConnsInbound": 0, + "ConnsOutbound": 0, + "FD": 0 + }, + "ServicePeerMemory": { + "MemoryFraction": 0.0078125, + "MinMemory": 16777216, + "MaxMemory": 67108864 + }, + "ProtocolBaseLimit": { + "Streams": 4096, + "StreamsInbound": 1024, + "StreamsOutbound": 4096, + "Conns": 0, + "ConnsInbound": 0, + "ConnsOutbound": 0, + "FD": 0 + }, + "ProtocolMemory": { + "MemoryFraction": 0.015625, + "MinMemory": 67108864, + "MaxMemory": 134217728 + }, + "ProtocolPeerBaseLimit": { + "Streams": 512, + "StreamsInbound": 128, + "StreamsOutbound": 256, + "Conns": 0, + "ConnsInbound": 0, + "ConnsOutbound": 0, + "FD": 0 + }, + "ProtocolPeerMemory": { + "MemoryFraction": 0.0078125, + "MinMemory": 16777216, + "MaxMemory": 67108864 + }, + "PeerBaseLimit": { + "Streams": 1024, + "StreamsInbound": 512, + "StreamsOutbound": 1024, + "Conns": 16, + "ConnsInbound": 8, + "ConnsOutbound": 16, + "FD": 8 + }, + "PeerMemory": { + "MemoryFraction": 0.0078125, + "MinMemory": 67108864, + "MaxMemory": 134217728 + }, + "ConnBaseLimit": { + "Streams": 0, + "StreamsInbound": 0, + "StreamsOutbound": 0, + "Conns": 1, + "ConnsInbound": 1, + "ConnsOutbound": 1, + "FD": 1 + }, + "ConnMemory": 1048576, + "StreamBaseLimit": { + "Streams": 1, + "StreamsInbound": 1, + "StreamsOutbound": 1, + "Conns": 0, + "ConnsInbound": 0, + "ConnsOutbound": 0, + "FD": 0 + }, + "StreamMemory": 16777216 +}` + +// https://github.com/libp2p/go-libp2p/blob/v0.18.0/limits.go#L17 +const expectedDefaultServiceLimits = `{ + "SystemLimits": { + "Streams": 16384, + "StreamsInbound": 4096, + "StreamsOutbound": 16384, + "Conns": 1024, + "ConnsInbound": 256, + "ConnsOutbound": 1024, + "FD": 512, + "Memory": 1073741824 + }, + "TransientLimits": { + "Streams": 512, + "StreamsInbound": 128, + "StreamsOutbound": 512, + "Conns": 128, + "ConnsInbound": 32, + "ConnsOutbound": 128, + "FD": 128, + "Memory": 67108864 + }, + "DefaultServiceLimits": { + "Streams": 8192, + "StreamsInbound": 2048, + "StreamsOutbound": 8192, + "Conns": 0, + "ConnsInbound": 0, + "ConnsOutbound": 0, + "FD": 0, + "Memory": 67108864 + }, + "DefaultServicePeerLimits": { + "Streams": 512, + "StreamsInbound": 256, + "StreamsOutbound": 512, + "Conns": 0, + "ConnsInbound": 0, + "ConnsOutbound": 0, + "FD": 0, + "Memory": 16777216 + }, + "ServiceLimits": { + "libp2p.autonat": { + "Streams": 128, + "StreamsInbound": 128, + "StreamsOutbound": 128, + "Conns": 0, + "ConnsInbound": 0, + "ConnsOutbound": 0, + "FD": 0, + "Memory": 67108864 + }, + "libp2p.holepunch": { + "Streams": 256, + "StreamsInbound": 128, + "StreamsOutbound": 128, + "Conns": 0, + "ConnsInbound": 0, + "ConnsOutbound": 0, + "FD": 0, + "Memory": 67108864 + }, + "libp2p.identify": { + "Streams": 256, + "StreamsInbound": 128, + "StreamsOutbound": 128, + "Conns": 0, + "ConnsInbound": 0, + "ConnsOutbound": 0, + "FD": 0, + "Memory": 67108864 + }, + "libp2p.ping": { + "Streams": 128, + "StreamsInbound": 128, + "StreamsOutbound": 128, + "Conns": 0, + "ConnsInbound": 0, + "ConnsOutbound": 0, + "FD": 0, + "Memory": 67108864 + }, + "libp2p.relay/v1": { + "Streams": 1024, + "StreamsInbound": 1024, + "StreamsOutbound": 1024, + "Conns": 0, + "ConnsInbound": 0, + "ConnsOutbound": 0, + "FD": 0, + "Memory": 67108864 + }, + "libp2p.relay/v2": { + "Streams": 1024, + "StreamsInbound": 1024, + "StreamsOutbound": 1024, + "Conns": 0, + "ConnsInbound": 0, + "ConnsOutbound": 0, + "FD": 0, + "Memory": 67108864 + } + }, + "ServicePeerLimits": { + "libp2p.autonat": { + "Streams": 2, + "StreamsInbound": 2, + "StreamsOutbound": 2, + "Conns": 0, + "ConnsInbound": 0, + "ConnsOutbound": 0, + "FD": 0, + "Memory": 557056 + }, + "libp2p.holepunch": { + "Streams": 2, + "StreamsInbound": 2, + "StreamsOutbound": 2, + "Conns": 0, + "ConnsInbound": 0, + "ConnsOutbound": 0, + "FD": 0, + "Memory": 557056 + }, + "libp2p.identify": { + "Streams": 32, + "StreamsInbound": 16, + "StreamsOutbound": 16, + "Conns": 0, + "ConnsInbound": 0, + "ConnsOutbound": 0, + "FD": 0, + "Memory": 8912896 + }, + "libp2p.ping": { + "Streams": 4, + "StreamsInbound": 2, + "StreamsOutbound": 3, + "Conns": 0, + "ConnsInbound": 0, + "ConnsOutbound": 0, + "FD": 0, + "Memory": 1114112 + }, + "libp2p.relay/v1": { + "Streams": 64, + "StreamsInbound": 64, + "StreamsOutbound": 64, + "Conns": 0, + "ConnsInbound": 0, + "ConnsOutbound": 0, + "FD": 0, + "Memory": 17825792 + }, + "libp2p.relay/v2": { + "Streams": 64, + "StreamsInbound": 64, + "StreamsOutbound": 64, + "Conns": 0, + "ConnsInbound": 0, + "ConnsOutbound": 0, + "FD": 0, + "Memory": 17825792 + } + }, + "DefaultProtocolLimits": { + "Streams": 4096, + "StreamsInbound": 1024, + "StreamsOutbound": 4096, + "Conns": 0, + "ConnsInbound": 0, + "ConnsOutbound": 0, + "FD": 0, + "Memory": 67108864 + }, + "DefaultProtocolPeerLimits": { + "Streams": 512, + "StreamsInbound": 128, + "StreamsOutbound": 256, + "Conns": 0, + "ConnsInbound": 0, + "ConnsOutbound": 0, + "FD": 0, + "Memory": 16777216 + }, + "ProtocolLimits": { + "/ipfs/id/1.0.0": { + "Streams": 4096, + "StreamsInbound": 1024, + "StreamsOutbound": 4096, + "Conns": 0, + "ConnsInbound": 0, + "ConnsOutbound": 0, + "FD": 0, + "Memory": 33554432 + }, + "/ipfs/id/push/1.0.0": { + "Streams": 4096, + "StreamsInbound": 1024, + "StreamsOutbound": 4096, + "Conns": 0, + "ConnsInbound": 0, + "ConnsOutbound": 0, + "FD": 0, + "Memory": 33554432 + }, + "/ipfs/ping/1.0.0": { + "Streams": 4096, + "StreamsInbound": 1024, + "StreamsOutbound": 4096, + "Conns": 0, + "ConnsInbound": 0, + "ConnsOutbound": 0, + "FD": 0, + "Memory": 67108864 + }, + "/libp2p/autonat/1.0.0": { + "Streams": 4096, + "StreamsInbound": 1024, + "StreamsOutbound": 4096, + "Conns": 0, + "ConnsInbound": 0, + "ConnsOutbound": 0, + "FD": 0, + "Memory": 67108864 + }, + "/libp2p/circuit/relay/0.1.0": { + "Streams": 1280, + "StreamsInbound": 1280, + "StreamsOutbound": 1280, + "Conns": 0, + "ConnsInbound": 0, + "ConnsOutbound": 0, + "FD": 0, + "Memory": 67108864 + }, + "/libp2p/circuit/relay/0.2.0/hop": { + "Streams": 1280, + "StreamsInbound": 1280, + "StreamsOutbound": 1280, + "Conns": 0, + "ConnsInbound": 0, + "ConnsOutbound": 0, + "FD": 0, + "Memory": 67108864 + }, + "/libp2p/circuit/relay/0.2.0/stop": { + "Streams": 1280, + "StreamsInbound": 1280, + "StreamsOutbound": 1280, + "Conns": 0, + "ConnsInbound": 0, + "ConnsOutbound": 0, + "FD": 0, + "Memory": 67108864 + }, + "/libp2p/dcutr": { + "Streams": 4096, + "StreamsInbound": 1024, + "StreamsOutbound": 4096, + "Conns": 0, + "ConnsInbound": 0, + "ConnsOutbound": 0, + "FD": 0, + "Memory": 67108864 + }, + "/p2p/id/delta/1.0.0": { + "Streams": 4096, + "StreamsInbound": 1024, + "StreamsOutbound": 4096, + "Conns": 0, + "ConnsInbound": 0, + "ConnsOutbound": 0, + "FD": 0, + "Memory": 33554432 + } + }, + "ProtocolPeerLimits": { + "/ipfs/id/1.0.0": { + "Streams": 32, + "StreamsInbound": 16, + "StreamsOutbound": 16, + "Conns": 0, + "ConnsInbound": 0, + "ConnsOutbound": 0, + "FD": 0, + "Memory": 8912896 + }, + "/ipfs/id/push/1.0.0": { + "Streams": 32, + "StreamsInbound": 16, + "StreamsOutbound": 16, + "Conns": 0, + "ConnsInbound": 0, + "ConnsOutbound": 0, + "FD": 0, + "Memory": 8912896 + }, + "/ipfs/ping/1.0.0": { + "Streams": 4, + "StreamsInbound": 2, + "StreamsOutbound": 3, + "Conns": 0, + "ConnsInbound": 0, + "ConnsOutbound": 0, + "FD": 0, + "Memory": 1114112 + }, + "/libp2p/autonat/1.0.0": { + "Streams": 2, + "StreamsInbound": 2, + "StreamsOutbound": 2, + "Conns": 0, + "ConnsInbound": 0, + "ConnsOutbound": 0, + "FD": 0, + "Memory": 557056 + }, + "/libp2p/circuit/relay/0.1.0": { + "Streams": 128, + "StreamsInbound": 128, + "StreamsOutbound": 128, + "Conns": 0, + "ConnsInbound": 0, + "ConnsOutbound": 0, + "FD": 0, + "Memory": 35651584 + }, + "/libp2p/circuit/relay/0.2.0/hop": { + "Streams": 128, + "StreamsInbound": 128, + "StreamsOutbound": 128, + "Conns": 0, + "ConnsInbound": 0, + "ConnsOutbound": 0, + "FD": 0, + "Memory": 35651584 + }, + "/libp2p/circuit/relay/0.2.0/stop": { + "Streams": 128, + "StreamsInbound": 128, + "StreamsOutbound": 128, + "Conns": 0, + "ConnsInbound": 0, + "ConnsOutbound": 0, + "FD": 0, + "Memory": 35651584 + }, + "/libp2p/dcutr": { + "Streams": 2, + "StreamsInbound": 2, + "StreamsOutbound": 2, + "Conns": 0, + "ConnsInbound": 0, + "ConnsOutbound": 0, + "FD": 0, + "Memory": 557056 + }, + "/p2p/id/delta/1.0.0": { + "Streams": 32, + "StreamsInbound": 16, + "StreamsOutbound": 16, + "Conns": 0, + "ConnsInbound": 0, + "ConnsOutbound": 0, + "FD": 0, + "Memory": 8912896 + } + }, + "DefaultPeerLimits": { + "Streams": 1024, + "StreamsInbound": 512, + "StreamsOutbound": 1024, + "Conns": 16, + "ConnsInbound": 8, + "ConnsOutbound": 16, + "FD": 8, + "Memory": 67108864 + }, + "PeerLimits": null, + "ConnLimits": { + "Streams": 0, + "StreamsInbound": 0, + "StreamsOutbound": 0, + "Conns": 1, + "ConnsInbound": 1, + "ConnsOutbound": 1, + "FD": 1, + "Memory": 1048576 + }, + "StreamLimits": { + "Streams": 1, + "StreamsInbound": 1, + "StreamsOutbound": 1, + "Conns": 0, + "ConnsInbound": 0, + "ConnsOutbound": 0, + "FD": 0, + "Memory": 16777216 + } +}` diff --git a/go.mod b/go.mod index e4b4f903bbf..9bcece6d7ce 100644 --- a/go.mod +++ b/go.mod @@ -103,6 +103,7 @@ require ( github.com/prometheus/client_golang v1.11.0 github.com/stretchr/testify v1.7.0 github.com/syndtr/goleveldb v1.0.0 + github.com/wI2L/jsondiff v0.2.0 github.com/whyrusleeping/go-sysinfo v0.0.0-20190219211824-4a357d4b90b1 github.com/whyrusleeping/multiaddr-filter v0.0.0-20160516205228-e903e4adabd7 go.opencensus.io v0.23.0 diff --git a/go.sum b/go.sum index be5a76d8952..d5b56935d93 100644 --- a/go.sum +++ b/go.sum @@ -1423,6 +1423,12 @@ github.com/syndtr/goleveldb v1.0.0/go.mod h1:ZVVdQEZoIme9iO1Ch2Jdy24qqXrMMOU6lpP github.com/tarm/serial v0.0.0-20180830185346-98f6abe2eb07/go.mod h1:kDXzergiv9cbyO7IOYJZWg1U88JhDg3PB6klq9Hg2pA= github.com/texttheater/golang-levenshtein v0.0.0-20180516184445-d188e65d659e h1:T5PdfK/M1xyrHwynxMIVMWLS7f/qHwfslZphxtGnw7s= github.com/texttheater/golang-levenshtein v0.0.0-20180516184445-d188e65d659e/go.mod h1:XDKHRm5ThF8YJjx001LtgelzsoaEcvnA7lVWz9EeX3g= +github.com/tidwall/gjson v1.14.0 h1:6aeJ0bzojgWLa82gDQHcx3S0Lr/O51I9bJ5nv6JFx5w= +github.com/tidwall/gjson v1.14.0/go.mod h1:/wbyibRr2FHMks5tjHJ5F8dMZh3AcwJEMf5vlfC0lxk= +github.com/tidwall/match v1.1.1 h1:+Ho715JplO36QYgwN9PGYNhgZvoUSc9X2c80KVTi+GA= +github.com/tidwall/match v1.1.1/go.mod h1:eRSPERbgtNPcGhD8UCthc6PmLEQXEWd3PRB5JTxsfmM= +github.com/tidwall/pretty v1.2.0 h1:RWIZEg2iJ8/g6fDDYzMpobmaoGh5OLl4AXtGUGPcqCs= +github.com/tidwall/pretty v1.2.0/go.mod h1:ITEVvHYasfjBbM0u2Pg8T2nJnzm8xPwvNhhsoaGGjNU= github.com/tmc/grpc-websocket-proxy v0.0.0-20170815181823-89b8d40f7ca8/go.mod h1:ncp9v5uamzpCO7NfCPTXjqaC+bZgJeR0sMTm6dMHP7U= github.com/tv42/httpunix v0.0.0-20191220191345-2ba4b9c3382c h1:u6SKchux2yDvFQnDHS3lPnIRmfVJ5Sxy3ao2SIdysLQ= github.com/tv42/httpunix v0.0.0-20191220191345-2ba4b9c3382c/go.mod h1:hzIxponao9Kjc7aWznkXaL4U4TWaDSs8zcsY4Ka08nM= @@ -1433,6 +1439,8 @@ github.com/urfave/cli v1.22.2/go.mod h1:Gos4lmkARVdJ6EkW0WaNv/tZAAMe9V7XWyB60NtX github.com/urfave/cli/v2 v2.0.0/go.mod h1:SE9GqnLQmjVa0iPEY0f1w3ygNIYcIJ0OKPMoW2caLfQ= github.com/viant/assertly v0.4.8/go.mod h1:aGifi++jvCrUaklKEKT0BU95igDNaqkvz+49uaYMPRU= github.com/viant/toolbox v0.24.0/go.mod h1:OxMCG57V0PXuIP2HNQrtJf2CjqdmbrOx5EkMILuUhzM= +github.com/wI2L/jsondiff v0.2.0 h1:dE00WemBa1uCjrzQUUTE/17I6m5qAaN0EMFOg2Ynr/k= +github.com/wI2L/jsondiff v0.2.0/go.mod h1:axTcwtBkY4TsKuV+RgoMhHyHKKFRI6nnjRLi8LLYQnA= github.com/wangjia184/sortedset v0.0.0-20160527075905-f5d03557ba30/go.mod h1:YkocrP2K2tcw938x9gCOmT5G5eCD6jsTz0SZuyAqwIE= github.com/warpfork/go-testmark v0.3.0/go.mod h1:jhEf8FVxd+F17juRubpmut64NEG6I2rgkUhlcqqXwE0= github.com/warpfork/go-testmark v0.9.0 h1:nc+uaCiv5lFQLYjhuC2LTYeJ7JaC+gdDmsz9r0ISy0Y= From fbf76663f4db6f3c4ed89d8c017d9319d2727121 Mon Sep 17 00:00:00 2001 From: Ian Davis Date: Fri, 8 Apr 2022 21:07:44 +0100 Subject: [PATCH 345/414] fix(gw): update metrics only when payload data sent (#8827) * fix: report gateway http metrics only when response is successful * fix(gw): 304 Not Modified as no-op This fix ensures we don't do any additional work when Etag match what user already has in their own cache. Co-authored-by: Marcin Rataj --- core/corehttp/gateway_handler.go | 60 ++++++++++++++++++-- core/corehttp/gateway_handler_block.go | 10 ++-- core/corehttp/gateway_handler_unixfs_dir.go | 7 ++- core/corehttp/gateway_handler_unixfs_file.go | 11 ++-- 4 files changed, 74 insertions(+), 14 deletions(-) diff --git a/core/corehttp/gateway_handler.go b/core/corehttp/gateway_handler.go index 32d2eebaef8..b14b88739d2 100644 --- a/core/corehttp/gateway_handler.go +++ b/core/corehttp/gateway_handler.go @@ -36,8 +36,10 @@ const ( immutableCacheControl = "public, max-age=29030400, immutable" ) -var onlyAscii = regexp.MustCompile("[[:^ascii:]]") -var noModtime = time.Unix(0, 0) // disables Last-Modified header if passed as modtime +var ( + onlyAscii = regexp.MustCompile("[[:^ascii:]]") + noModtime = time.Unix(0, 0) // disables Last-Modified header if passed as modtime +) // HTML-based redirect for errors which can be recovered from, but we want // to provide hint to people that they should fix things on their end. @@ -96,6 +98,54 @@ func (sw *statusResponseWriter) WriteHeader(code int) { sw.ResponseWriter.WriteHeader(code) } +// ServeContent replies to the request using the content in the provided ReadSeeker +// and returns the status code written and any error encountered during a write. +// It wraps http.ServeContent which takes care of If-None-Match+Etag, +// Content-Length and range requests. +func ServeContent(w http.ResponseWriter, req *http.Request, name string, modtime time.Time, content io.ReadSeeker) (int, bool, error) { + ew := &errRecordingResponseWriter{ResponseWriter: w} + http.ServeContent(ew, req, name, modtime, content) + + // When we calculate some metrics we want a flag that lets us to ignore + // errors and 304 Not Modified, and only care when requested data + // was sent in full. + dataSent := ew.code/100 == 2 && ew.err == nil + + return ew.code, dataSent, ew.err +} + +// errRecordingResponseWriter wraps a ResponseWriter to record the status code and any write error. +type errRecordingResponseWriter struct { + http.ResponseWriter + code int + err error +} + +func (w *errRecordingResponseWriter) WriteHeader(code int) { + if w.code == 0 { + w.code = code + } + w.ResponseWriter.WriteHeader(code) +} + +func (w *errRecordingResponseWriter) Write(p []byte) (int, error) { + n, err := w.ResponseWriter.Write(p) + if err != nil && w.err == nil { + w.err = err + } + return n, err +} + +// ReadFrom exposes errRecordingResponseWriter's underlying ResponseWriter to io.Copy +// to allow optimized methods to be taken advantage of. +func (w *errRecordingResponseWriter) ReadFrom(r io.Reader) (n int64, err error) { + n, err = io.Copy(w.ResponseWriter, r) + if err != nil && w.err == nil { + w.err = err + } + return n, err +} + func newGatewaySummaryMetric(name string, help string) *prometheus.SummaryVec { summaryMetric := prometheus.NewSummaryVec( prometheus.SummaryOpts{ @@ -360,7 +410,8 @@ func (i *gatewayHandler) getOrHeadHandler(w http.ResponseWriter, r *http.Request trace.SpanFromContext(r.Context()).SetAttributes(attribute.String("ResolvedPath", resolvedPath.String())) // Finish early if client already has matching Etag - if r.Header.Get("If-None-Match") == getEtag(r, resolvedPath.Cid()) { + ifNoneMatch := r.Header.Get("If-None-Match") + if ifNoneMatch == getEtag(r, resolvedPath.Cid()) || ifNoneMatch == getDirListingEtag(resolvedPath.Cid()) { w.WriteHeader(http.StatusNotModified) return } @@ -401,7 +452,7 @@ func (i *gatewayHandler) getOrHeadHandler(w http.ResponseWriter, r *http.Request case "application/vnd.ipld.car": logger.Debugw("serving car stream", "path", contentPath) carVersion := formatParams["version"] - i.serveCar(w, r, resolvedPath, contentPath, carVersion, begin) + i.serveCar(w, r, resolvedPath, contentPath, carVersion, begin) return default: // catch-all for unsuported application/vnd.* err := fmt.Errorf("unsupported format %q", responseFormat) @@ -644,7 +695,6 @@ func addCacheControlHeaders(w http.ResponseWriter, r *http.Request, contentPath // TODO: set Cache-Control based on TTL of IPNS/DNSLink: https://github.com/ipfs/go-ipfs/issues/1818#issuecomment-1015849462 // TODO: set Last-Modified based on /ipns/ publishing timestamp? - } else { // immutable! CACHE ALL THE THINGS, FOREVER! wolololol w.Header().Set("Cache-Control", immutableCacheControl) diff --git a/core/corehttp/gateway_handler_block.go b/core/corehttp/gateway_handler_block.go index 891c418c87a..afd553d3080 100644 --- a/core/corehttp/gateway_handler_block.go +++ b/core/corehttp/gateway_handler_block.go @@ -38,10 +38,12 @@ func (i *gatewayHandler) serveRawBlock(w http.ResponseWriter, r *http.Request, r w.Header().Set("Content-Type", "application/vnd.ipld.raw") w.Header().Set("X-Content-Type-Options", "nosniff") // no funny business in the browsers :^) - // Done: http.ServeContent will take care of + // ServeContent will take care of // If-None-Match+Etag, Content-Length and range requests - http.ServeContent(w, r, name, modtime, content) + _, dataSent, _ := ServeContent(w, r, name, modtime, content) - // Update metrics - i.rawBlockGetMetric.WithLabelValues(contentPath.Namespace()).Observe(time.Since(begin).Seconds()) + if dataSent { + // Update metrics + i.rawBlockGetMetric.WithLabelValues(contentPath.Namespace()).Observe(time.Since(begin).Seconds()) + } } diff --git a/core/corehttp/gateway_handler_unixfs_dir.go b/core/corehttp/gateway_handler_unixfs_dir.go index e458e803076..15827713591 100644 --- a/core/corehttp/gateway_handler_unixfs_dir.go +++ b/core/corehttp/gateway_handler_unixfs_dir.go @@ -8,6 +8,7 @@ import ( "time" "github.com/dustin/go-humanize" + cid "github.com/ipfs/go-cid" files "github.com/ipfs/go-ipfs-files" "github.com/ipfs/go-ipfs/assets" "github.com/ipfs/go-ipfs/tracing" @@ -93,7 +94,7 @@ func (i *gatewayHandler) serveDirectory(w http.ResponseWriter, r *http.Request, // Generated dir index requires custom Etag (it may change between go-ipfs versions) if assets.BindataVersionHash != "" { - dirEtag := `"DirIndex-` + assets.BindataVersionHash + `_CID-` + resolvedPath.Cid().String() + `"` + dirEtag := getDirListingEtag(resolvedPath.Cid()) w.Header().Set("Etag", dirEtag) if r.Header.Get("If-None-Match") == dirEtag { w.WriteHeader(http.StatusNotModified) @@ -204,3 +205,7 @@ func (i *gatewayHandler) serveDirectory(w http.ResponseWriter, r *http.Request, // Update metrics i.unixfsGenDirGetMetric.WithLabelValues(contentPath.Namespace()).Observe(time.Since(begin).Seconds()) } + +func getDirListingEtag(dirCid cid.Cid) string { + return `"DirIndex-` + assets.BindataVersionHash + `_CID-` + dirCid.String() + `"` +} diff --git a/core/corehttp/gateway_handler_unixfs_file.go b/core/corehttp/gateway_handler_unixfs_file.go index e8a3718fc16..2938c8f4883 100644 --- a/core/corehttp/gateway_handler_unixfs_file.go +++ b/core/corehttp/gateway_handler_unixfs_file.go @@ -82,10 +82,13 @@ func (i *gatewayHandler) serveFile(w http.ResponseWriter, r *http.Request, resol // special fixup around redirects w = &statusResponseWriter{w} - // Done: http.ServeContent will take care of + // ServeContent will take care of // If-None-Match+Etag, Content-Length and range requests - http.ServeContent(w, r, name, modtime, content) + _, dataSent, _ := ServeContent(w, r, name, modtime, content) - // Update metrics - i.unixfsFileGetMetric.WithLabelValues(contentPath.Namespace()).Observe(time.Since(begin).Seconds()) + // Was response successful? + if dataSent { + // Update metrics + i.unixfsFileGetMetric.WithLabelValues(contentPath.Namespace()).Observe(time.Since(begin).Seconds()) + } } From e1c8d78d7d62046c24bc24252880b4311f6cbebe Mon Sep 17 00:00:00 2001 From: Adin Schmahmann Date: Fri, 8 Apr 2022 16:31:26 -0400 Subject: [PATCH 346/414] chore: update deps (#8859) --- go.mod | 4 ++-- go.sum | 14 ++++++++------ 2 files changed, 10 insertions(+), 8 deletions(-) diff --git a/go.mod b/go.mod index 687669f8fd8..3cbfbe3eb28 100644 --- a/go.mod +++ b/go.mod @@ -61,8 +61,8 @@ require ( github.com/ipfs/tar-utils v0.0.2 github.com/ipld/go-car v0.3.2 github.com/ipld/go-car/v2 v2.1.1 - github.com/ipld/go-codec-dagpb v1.3.2 - github.com/ipld/go-ipld-prime v0.14.2 + github.com/ipld/go-codec-dagpb v1.4.0 + github.com/ipld/go-ipld-prime v0.16.0 github.com/jbenet/go-random v0.0.0-20190219211222-123a90aedc0c github.com/jbenet/go-temp-err-catcher v0.1.0 github.com/jbenet/goprocess v0.1.4 diff --git a/go.sum b/go.sum index 298a32211c9..e12f621d602 100644 --- a/go.sum +++ b/go.sum @@ -230,8 +230,9 @@ github.com/francoispqt/gojay v1.2.13/go.mod h1:ehT5mTG4ua4581f1++1WLG0vPdaA9HaiD github.com/franela/goblin v0.0.0-20200105215937-c9ffbefa60db/go.mod h1:7dvUGVsVBjqR7JHJk0brhHOZYGmfBYOrK0ZhYMEtBr4= github.com/franela/goreq v0.0.0-20171204163338-bcd34c9993f8/go.mod h1:ZhphrRTfi2rbfLwlschooIH4+wKKDR4Pdxhh+TRoA20= github.com/frankban/quicktest v1.11.3/go.mod h1:wRf/ReqHper53s+kmmSZizM8NamnL3IM0I9ntUbOk+k= -github.com/frankban/quicktest v1.14.0 h1:+cqqvzZV87b4adx/5ayVOaYZ2CrvM4ejQvUdBzPPUss= github.com/frankban/quicktest v1.14.0/go.mod h1:NeW+ay9A/U67EYXNFA1nPE8e/tnQv/09mUdL/ijj8og= +github.com/frankban/quicktest v1.14.2 h1:SPb1KFFmM+ybpEjPUhCCkZOM5xlovT5UbrMvWnXyBns= +github.com/frankban/quicktest v1.14.2/go.mod h1:mgiwOwqx65TmIk1wJ6Q7wvnVMocbUorkibMOrVTHZps= github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo= github.com/fsnotify/fsnotify v1.4.9/go.mod h1:znqG4EE+3YCdAaPaxE2ZRY/06pZUdp0tY4IgpuI1SZQ= github.com/fsnotify/fsnotify v1.5.1 h1:mZcQUHVQUQWoPXXtuf9yuEXKudkV2sx1E06UadKWpgI= @@ -324,8 +325,9 @@ github.com/google/go-cmp v0.5.2/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/ github.com/google/go-cmp v0.5.3/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/go-cmp v0.5.4/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= -github.com/google/go-cmp v0.5.6 h1:BKbKCqvP6I+rmFHt06ZmyQtvB8xAkWdhFyr0ZUNZcxQ= github.com/google/go-cmp v0.5.6/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= +github.com/google/go-cmp v0.5.7 h1:81/ik6ipDQS2aGcBfIN5dHDB36BwrStyeAQquSYCV4o= +github.com/google/go-cmp v0.5.7/go.mod h1:n+brtR0CgQNWTVd5ZUFpTBC8YFBDLK/h/bpaJ8/DtOE= github.com/google/go-github v17.0.0+incompatible/go.mod h1:zLgOLi98H3fifZn+44m+umXrS52loVEgC2AApnigrVQ= github.com/google/go-querystring v1.0.0/go.mod h1:odCYkC5MyYFN7vkCjXpyrEuKhc/BUO6wN/zVPAxq5ck= github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= @@ -615,16 +617,16 @@ github.com/ipld/go-car/v2 v2.1.1 h1:saaKz4nC0AdfCGHLYKeXLGn8ivoPC54fyS55uyOLKwA= github.com/ipld/go-car/v2 v2.1.1/go.mod h1:+2Yvf0Z3wzkv7NeI69i8tuZ+ft7jyjPYIWZzeVNeFcI= github.com/ipld/go-codec-dagpb v1.2.0/go.mod h1:6nBN7X7h8EOsEejZGqC7tej5drsdBAXbMHyBT+Fne5s= github.com/ipld/go-codec-dagpb v1.3.0/go.mod h1:ga4JTU3abYApDC3pZ00BC2RSvC3qfBb9MSJkMLSwnhA= -github.com/ipld/go-codec-dagpb v1.3.2 h1:MZQUIjanHXXfDuYmtWYT8nFbqfFsZuyHClj6VDmSXr4= -github.com/ipld/go-codec-dagpb v1.3.2/go.mod h1:ga4JTU3abYApDC3pZ00BC2RSvC3qfBb9MSJkMLSwnhA= +github.com/ipld/go-codec-dagpb v1.4.0 h1:VqADPIFng8G4vz5EQytmmcx/2gEgOHfBuw/kIuCgDAY= +github.com/ipld/go-codec-dagpb v1.4.0/go.mod h1:ErNNglIi5KMur/MfFE/svtgQthzVvf+43MrzLbpcIZY= github.com/ipld/go-ipld-prime v0.9.0/go.mod h1:KvBLMr4PX1gWptgkzRjVZCrLmSGcZCb/jioOQwCqZN8= github.com/ipld/go-ipld-prime v0.9.1-0.20210324083106-dc342a9917db/go.mod h1:KvBLMr4PX1gWptgkzRjVZCrLmSGcZCb/jioOQwCqZN8= github.com/ipld/go-ipld-prime v0.11.0/go.mod h1:+WIAkokurHmZ/KwzDOMUuoeJgaRQktHtEaLglS3ZeV8= github.com/ipld/go-ipld-prime v0.12.3/go.mod h1:PaeLYq8k6dJLmDUSLrzkEpoGV4PEfe/1OtFN/eALOc8= github.com/ipld/go-ipld-prime v0.14.0/go.mod h1:9ASQLwUFLptCov6lIYc70GRB4V7UTyLD0IJtrDJe6ZM= github.com/ipld/go-ipld-prime v0.14.1/go.mod h1:QcE4Y9n/ZZr8Ijg5bGPT0GqYWgZ1704nH0RDcQtgTP0= -github.com/ipld/go-ipld-prime v0.14.2 h1:P5fO2usnisXwrN/1sR5exCgEvINg/w/27EuYPKB/zx8= -github.com/ipld/go-ipld-prime v0.14.2/go.mod h1:QcE4Y9n/ZZr8Ijg5bGPT0GqYWgZ1704nH0RDcQtgTP0= +github.com/ipld/go-ipld-prime v0.16.0 h1:RS5hhjB/mcpeEPJvfyj0qbOj/QL+/j05heZ0qa97dVo= +github.com/ipld/go-ipld-prime v0.16.0/go.mod h1:axSCuOCBPqrH+gvXr2w9uAOulJqBPhHPT2PjoiiU1qA= github.com/ipld/go-ipld-prime/storage/bsadapter v0.0.0-20211210234204-ce2a1c70cd73 h1:TsyATB2ZRRQGTwafJdgEUQkmjOExRV0DNokcihZxbnQ= github.com/ipld/go-ipld-prime/storage/bsadapter v0.0.0-20211210234204-ce2a1c70cd73/go.mod h1:2PJ0JgxyB08t0b2WKrcuqI3di0V+5n6RS/LTUJhkoxY= github.com/jackpal/gateway v1.0.5/go.mod h1:lTpwd4ACLXmpyiCTRtfiNyVnUmqT9RivzCDQetPfnjA= From 52bf1339460220b80d6afdd21eb710ef7d8eaf18 Mon Sep 17 00:00:00 2001 From: makeworld <25111343+makeworld-the-better-one@users.noreply.github.com> Date: Fri, 8 Apr 2022 17:09:23 -0400 Subject: [PATCH 347/414] fix(gw): missing return if dir fails to finalize (#8806) --- core/corehttp/gateway_handler.go | 1 + 1 file changed, 1 insertion(+) diff --git a/core/corehttp/gateway_handler.go b/core/corehttp/gateway_handler.go index b14b88739d2..d2446450b53 100644 --- a/core/corehttp/gateway_handler.go +++ b/core/corehttp/gateway_handler.go @@ -662,6 +662,7 @@ func (i *gatewayHandler) deleteHandler(w http.ResponseWriter, r *http.Request) { nnode, err := root.GetDirectory().GetNode() if err != nil { webError(w, "WritableGateway: failed to finalize", err, http.StatusInternalServerError) + return } ncid := nnode.Cid() From 9bd346e25004df4fd7927ab151097f975fb433c2 Mon Sep 17 00:00:00 2001 From: Gus Eggert Date: Mon, 11 Apr 2022 17:09:00 -0400 Subject: [PATCH 348/414] fix: fix context plumbing in gateway handlers (#8871) This ensures that child contexts are passed around between the handlers so that traces show the call hierarchy correctly. --- core/corehttp/gateway_handler.go | 6 +++--- core/corehttp/gateway_handler_block.go | 5 +++-- core/corehttp/gateway_handler_car.go | 6 +++--- core/corehttp/gateway_handler_unixfs.go | 11 ++++++----- core/corehttp/gateway_handler_unixfs_dir.go | 7 ++++--- core/corehttp/gateway_handler_unixfs_file.go | 5 +++-- 6 files changed, 22 insertions(+), 18 deletions(-) diff --git a/core/corehttp/gateway_handler.go b/core/corehttp/gateway_handler.go index d2446450b53..0c34cc9b175 100644 --- a/core/corehttp/gateway_handler.go +++ b/core/corehttp/gateway_handler.go @@ -443,16 +443,16 @@ func (i *gatewayHandler) getOrHeadHandler(w http.ResponseWriter, r *http.Request switch responseFormat { case "": // The implicit response format is UnixFS logger.Debugw("serving unixfs", "path", contentPath) - i.serveUnixFs(w, r, resolvedPath, contentPath, begin, logger) + i.serveUnixFS(r.Context(), w, r, resolvedPath, contentPath, begin, logger) return case "application/vnd.ipld.raw": logger.Debugw("serving raw block", "path", contentPath) - i.serveRawBlock(w, r, resolvedPath, contentPath, begin) + i.serveRawBlock(r.Context(), w, r, resolvedPath, contentPath, begin) return case "application/vnd.ipld.car": logger.Debugw("serving car stream", "path", contentPath) carVersion := formatParams["version"] - i.serveCar(w, r, resolvedPath, contentPath, carVersion, begin) + i.serveCAR(r.Context(), w, r, resolvedPath, contentPath, carVersion, begin) return default: // catch-all for unsuported application/vnd.* err := fmt.Errorf("unsupported format %q", responseFormat) diff --git a/core/corehttp/gateway_handler_block.go b/core/corehttp/gateway_handler_block.go index afd553d3080..8d6ce0f3686 100644 --- a/core/corehttp/gateway_handler_block.go +++ b/core/corehttp/gateway_handler_block.go @@ -2,6 +2,7 @@ package corehttp import ( "bytes" + "context" "io/ioutil" "net/http" "time" @@ -13,8 +14,8 @@ import ( ) // serveRawBlock returns bytes behind a raw block -func (i *gatewayHandler) serveRawBlock(w http.ResponseWriter, r *http.Request, resolvedPath ipath.Resolved, contentPath ipath.Path, begin time.Time) { - ctx, span := tracing.Span(r.Context(), "Gateway", "ServeRawBlock", trace.WithAttributes(attribute.String("path", resolvedPath.String()))) +func (i *gatewayHandler) serveRawBlock(ctx context.Context, w http.ResponseWriter, r *http.Request, resolvedPath ipath.Resolved, contentPath ipath.Path, begin time.Time) { + ctx, span := tracing.Span(ctx, "Gateway", "ServeRawBlock", trace.WithAttributes(attribute.String("path", resolvedPath.String()))) defer span.End() blockCid := resolvedPath.Cid() blockReader, err := i.api.Block().Get(ctx, resolvedPath) diff --git a/core/corehttp/gateway_handler_car.go b/core/corehttp/gateway_handler_car.go index d7dca46b381..1958088706e 100644 --- a/core/corehttp/gateway_handler_car.go +++ b/core/corehttp/gateway_handler_car.go @@ -17,9 +17,9 @@ import ( "go.opentelemetry.io/otel/trace" ) -// serveCar returns a CAR stream for specific DAG+selector -func (i *gatewayHandler) serveCar(w http.ResponseWriter, r *http.Request, resolvedPath ipath.Resolved, contentPath ipath.Path, carVersion string, begin time.Time) { - ctx, span := tracing.Span(r.Context(), "Gateway", "ServeCar", trace.WithAttributes(attribute.String("path", resolvedPath.String()))) +// serveCAR returns a CAR stream for specific DAG+selector +func (i *gatewayHandler) serveCAR(ctx context.Context, w http.ResponseWriter, r *http.Request, resolvedPath ipath.Resolved, contentPath ipath.Path, carVersion string, begin time.Time) { + ctx, span := tracing.Span(ctx, "Gateway", "ServeCAR", trace.WithAttributes(attribute.String("path", resolvedPath.String()))) defer span.End() ctx, cancel := context.WithCancel(ctx) defer cancel() diff --git a/core/corehttp/gateway_handler_unixfs.go b/core/corehttp/gateway_handler_unixfs.go index 2252b3891c6..f91e2df3b37 100644 --- a/core/corehttp/gateway_handler_unixfs.go +++ b/core/corehttp/gateway_handler_unixfs.go @@ -1,6 +1,7 @@ package corehttp import ( + "context" "fmt" "html" "net/http" @@ -14,8 +15,8 @@ import ( "go.uber.org/zap" ) -func (i *gatewayHandler) serveUnixFs(w http.ResponseWriter, r *http.Request, resolvedPath ipath.Resolved, contentPath ipath.Path, begin time.Time, logger *zap.SugaredLogger) { - ctx, span := tracing.Span(r.Context(), "Gateway", "ServeUnixFs", trace.WithAttributes(attribute.String("path", resolvedPath.String()))) +func (i *gatewayHandler) serveUnixFS(ctx context.Context, w http.ResponseWriter, r *http.Request, resolvedPath ipath.Resolved, contentPath ipath.Path, begin time.Time, logger *zap.SugaredLogger) { + ctx, span := tracing.Span(ctx, "Gateway", "ServeUnixFS", trace.WithAttributes(attribute.String("path", resolvedPath.String()))) defer span.End() // Handling UnixFS dr, err := i.api.Unixfs().Get(ctx, resolvedPath) @@ -28,16 +29,16 @@ func (i *gatewayHandler) serveUnixFs(w http.ResponseWriter, r *http.Request, res // Handling Unixfs file if f, ok := dr.(files.File); ok { logger.Debugw("serving unixfs file", "path", contentPath) - i.serveFile(w, r, resolvedPath, contentPath, f, begin) + i.serveFile(ctx, w, r, resolvedPath, contentPath, f, begin) return } // Handling Unixfs directory dir, ok := dr.(files.Directory) if !ok { - internalWebError(w, fmt.Errorf("unsupported UnixFs type")) + internalWebError(w, fmt.Errorf("unsupported UnixFS type")) return } logger.Debugw("serving unixfs directory", "path", contentPath) - i.serveDirectory(w, r, resolvedPath, contentPath, dir, begin, logger) + i.serveDirectory(ctx, w, r, resolvedPath, contentPath, dir, begin, logger) } diff --git a/core/corehttp/gateway_handler_unixfs_dir.go b/core/corehttp/gateway_handler_unixfs_dir.go index 15827713591..7d491ea49fd 100644 --- a/core/corehttp/gateway_handler_unixfs_dir.go +++ b/core/corehttp/gateway_handler_unixfs_dir.go @@ -1,6 +1,7 @@ package corehttp import ( + "context" "net/http" "net/url" gopath "path" @@ -23,8 +24,8 @@ import ( // serveDirectory returns the best representation of UnixFS directory // // It will return index.html if present, or generate directory listing otherwise. -func (i *gatewayHandler) serveDirectory(w http.ResponseWriter, r *http.Request, resolvedPath ipath.Resolved, contentPath ipath.Path, dir files.Directory, begin time.Time, logger *zap.SugaredLogger) { - ctx, span := tracing.Span(r.Context(), "Gateway", "ServeDirectory", trace.WithAttributes(attribute.String("path", resolvedPath.String()))) +func (i *gatewayHandler) serveDirectory(ctx context.Context, w http.ResponseWriter, r *http.Request, resolvedPath ipath.Resolved, contentPath ipath.Path, dir files.Directory, begin time.Time, logger *zap.SugaredLogger) { + ctx, span := tracing.Span(ctx, "Gateway", "ServeDirectory", trace.WithAttributes(attribute.String("path", resolvedPath.String()))) defer span.End() // HostnameOption might have constructed an IPNS/IPFS path using the Host header. @@ -69,7 +70,7 @@ func (i *gatewayHandler) serveDirectory(w http.ResponseWriter, r *http.Request, logger.Debugw("serving index.html file", "path", idxPath) // write to request - i.serveFile(w, r, resolvedPath, idxPath, f, begin) + i.serveFile(ctx, w, r, resolvedPath, idxPath, f, begin) return case resolver.ErrNoLink: logger.Debugw("no index.html; noop", "path", idxPath) diff --git a/core/corehttp/gateway_handler_unixfs_file.go b/core/corehttp/gateway_handler_unixfs_file.go index 2938c8f4883..1852705fd08 100644 --- a/core/corehttp/gateway_handler_unixfs_file.go +++ b/core/corehttp/gateway_handler_unixfs_file.go @@ -1,6 +1,7 @@ package corehttp import ( + "context" "fmt" "io" "mime" @@ -19,8 +20,8 @@ import ( // serveFile returns data behind a file along with HTTP headers based on // the file itself, its CID and the contentPath used for accessing it. -func (i *gatewayHandler) serveFile(w http.ResponseWriter, r *http.Request, resolvedPath ipath.Resolved, contentPath ipath.Path, file files.File, begin time.Time) { - _, span := tracing.Span(r.Context(), "Gateway", "ServeFile", trace.WithAttributes(attribute.String("path", resolvedPath.String()))) +func (i *gatewayHandler) serveFile(ctx context.Context, w http.ResponseWriter, r *http.Request, resolvedPath ipath.Resolved, contentPath ipath.Path, file files.File, begin time.Time) { + _, span := tracing.Span(ctx, "Gateway", "ServeFile", trace.WithAttributes(attribute.String("path", resolvedPath.String()))) defer span.End() // Set Cache-Control and read optional Last-Modified time From 9210c08fa69c454e14fc183b5d4237ddecbf3550 Mon Sep 17 00:00:00 2001 From: Franky W Date: Thu, 31 Mar 2022 12:25:49 +0200 Subject: [PATCH 349/414] Remove gobindata Since go1.16, there are built in tools that allow for embeding filesystem inside the binary. We now make use of the `embed` package to have all files put into the binary, removing the need to generate the files and removes dependencies Co-authored-by: Jorropo --- assets/README.md | 8 +- assets/assets.go | 44 +- assets/assets_test.go | 53 --- assets/bindata.go | 433 -------------------- assets/bindata_dep.go | 9 - assets/bindata_version_hash.go | 6 - core/corehttp/gateway_handler_unixfs_dir.go | 4 +- go.mod | 2 +- go.sum | 4 - 9 files changed, 45 insertions(+), 518 deletions(-) delete mode 100644 assets/assets_test.go delete mode 100644 assets/bindata.go delete mode 100644 assets/bindata_dep.go delete mode 100644 assets/bindata_version_hash.go diff --git a/assets/README.md b/assets/README.md index 3bfea9b8f64..02af2f19ca0 100644 --- a/assets/README.md +++ b/assets/README.md @@ -5,15 +5,11 @@ This directory contains the go-ipfs assets: * Getting started documentation (`init-doc`). * Directory listing HTML template (`dir-index-html`). -These assets are compiled into `bindata.go` with `go generate`. - ## Re-generating -Do not edit the .go files directly. - -Instead, edit the source files and use `go generate` from within the +Edit the source files and use `go generate` from within the assets directory: ``` go generate . -``` \ No newline at end of file +``` diff --git a/assets/assets.go b/assets/assets.go index d8bf49a00ea..579a8b2ca73 100644 --- a/assets/assets.go +++ b/assets/assets.go @@ -1,23 +1,30 @@ //go:generate npm run build --prefix ./dir-index-html/ -//go:generate go run github.com/go-bindata/go-bindata/v3/go-bindata -mode=0644 -modtime=1403768328 -pkg=assets init-doc dir-index-html/dir-index.html dir-index-html/knownIcons.txt -//go:generate gofmt -s -w bindata.go -//go:generate sh -c "sed -i \"s/.*BindataVersionHash.*/BindataVersionHash=\\\"$(git hash-object bindata.go)\\\"/\" bindata_version_hash.go" -//go:generate gofmt -s -w bindata_version_hash.go package assets import ( + "embed" "fmt" + "io" + "io/fs" "path/filepath" + "strconv" "github.com/ipfs/go-ipfs/core" "github.com/ipfs/go-ipfs/core/coreapi" + "github.com/cespare/xxhash" cid "github.com/ipfs/go-cid" files "github.com/ipfs/go-ipfs-files" options "github.com/ipfs/interface-go-ipfs-core/options" "github.com/ipfs/interface-go-ipfs-core/path" ) +//go:embed init-doc dir-index-html/dir-index.html dir-index-html/knownIcons.txt +var dir embed.FS + +// AssetHash a non-cryptographic hash of all embedded assets +var AssetHash string + // initDocPaths lists the paths for the docs we want to seed during --init var initDocPaths = []string{ filepath.Join("init-doc", "about"), @@ -29,6 +36,35 @@ var initDocPaths = []string{ filepath.Join("init-doc", "ping"), } +func init() { + sum := xxhash.New() + err := fs.WalkDir(Asset, ".", func(path string, d fs.DirEntry, err error) error { + if d.IsDir() { + return nil + } + + file, err := dir.Open(path) + if err != nil { + return err + } + defer file.Close() + _, err = io.Copy(sum, file) + return err + }) + if err != nil { + panic("error creating asset sum: " + err.Error()) + } + + AssetHash = strconv.FormatUint(sum.Sum64(), 32) +} + +// Asset loads and returns the asset for the given name. +// It returns an error if the asset could not be found or +// could not be loaded. +func Asset(f string) ([]byte, error) { + return dir.ReadFile(f) +} + // SeedInitDocs adds the list of embedded init documentation to the passed node, pins it and returns the root key func SeedInitDocs(nd *core.IpfsNode) (cid.Cid, error) { return addAssetList(nd, initDocPaths) diff --git a/assets/assets_test.go b/assets/assets_test.go deleted file mode 100644 index 8300af88489..00000000000 --- a/assets/assets_test.go +++ /dev/null @@ -1,53 +0,0 @@ -package assets - -import ( - "bytes" - "io/ioutil" - "sync" - "testing" -) - -// TestEmbeddedDocs makes sure we don't forget to regenerate after documentation change -func TestEmbeddedDocs(t *testing.T) { - testNFiles(initDocPaths, 5, t, "documents") -} - -func testNFiles(fs []string, wantCnt int, t *testing.T, ftype string) { - if len(fs) < wantCnt { - t.Fatalf("expected %d %s. got %d", wantCnt, ftype, len(fs)) - } - - var wg sync.WaitGroup - for _, f := range fs { - wg.Add(1) - // compare asset - go func(f string) { - defer wg.Done() - testOneFile(f, t) - }(f) - } - wg.Wait() -} - -func testOneFile(f string, t *testing.T) { - // load data from filesystem (git) - vcsData, err := ioutil.ReadFile(f) - if err != nil { - t.Errorf("asset %s: could not read vcs file: %s", f, err) - return - } - - // load data from emdedded source - embdData, err := Asset(f) - if err != nil { - t.Errorf("asset %s: could not read vcs file: %s", f, err) - return - } - - if !bytes.Equal(vcsData, embdData) { - t.Errorf("asset %s: vcs and embedded data isn't equal", f) - return - } - - t.Logf("checked %s", f) -} diff --git a/assets/bindata.go b/assets/bindata.go deleted file mode 100644 index 512eb789cd9..00000000000 --- a/assets/bindata.go +++ /dev/null @@ -1,433 +0,0 @@ -// Code generated by go-bindata. (@generated) DO NOT EDIT. - -//Package assets generated by go-bindata.// sources: -// init-doc/about -// init-doc/contact -// init-doc/help -// init-doc/ping -// init-doc/quick-start -// init-doc/readme -// init-doc/security-notes -// dir-index-html/dir-index.html -// dir-index-html/knownIcons.txt -package assets - -import ( - "bytes" - "compress/gzip" - "fmt" - "io" - "io/ioutil" - "os" - "path/filepath" - "strings" - "time" -) - -func bindataRead(data []byte, name string) ([]byte, error) { - gz, err := gzip.NewReader(bytes.NewBuffer(data)) - if err != nil { - return nil, fmt.Errorf("read %q: %v", name, err) - } - - var buf bytes.Buffer - _, err = io.Copy(&buf, gz) - clErr := gz.Close() - - if err != nil { - return nil, fmt.Errorf("read %q: %v", name, err) - } - if clErr != nil { - return nil, err - } - - return buf.Bytes(), nil -} - -type asset struct { - bytes []byte - info os.FileInfo -} - -type bindataFileInfo struct { - name string - size int64 - mode os.FileMode - modTime time.Time -} - -// Name return file name -func (fi bindataFileInfo) Name() string { - return fi.name -} - -// Size return file size -func (fi bindataFileInfo) Size() int64 { - return fi.size -} - -// Mode return file mode -func (fi bindataFileInfo) Mode() os.FileMode { - return fi.mode -} - -// ModTime return file modify time -func (fi bindataFileInfo) ModTime() time.Time { - return fi.modTime -} - -// IsDir return file whether a directory -func (fi bindataFileInfo) IsDir() bool { - return fi.mode&os.ModeDir != 0 -} - -// Sys return file is sys mode -func (fi bindataFileInfo) Sys() interface{} { - return nil -} - -var _initDocAbout = []byte("\x1f\x8b\x08\x00\x00\x00\x00\x00\x00\xff\x64\x94\x41\x6f\xe4\xb6\x0f\xc5\xef\xfe\x14\xef\xf6\xdf\x4d\xc6\x33\xc0\xff\xb8\x28\x7a\x68\xd3\x74\x83\x05\x82\x00\x49\x51\xf4\x16\x5a\xe2\xd8\x6c\x64\xd1\x90\xe8\x99\x75\x3f\x7d\x21\x79\x9c\x4c\xb1\xb9\x24\x70\x48\x8a\xfc\x91\xef\x35\xf8\xe1\xe7\xe1\xe9\xfe\x19\x6d\x8b\x87\x68\x9c\xda\xa7\x40\x91\x8d\xd2\x82\x7b\x09\x8c\xbc\x64\xe3\xb1\x69\x6a\x90\x64\x10\xfa\xa0\x1d\x85\x1d\x4e\x9c\xb2\x68\x64\xbf\xc3\xc4\x9c\x5a\xd3\xb6\xfc\xc6\x51\x02\xaf\x59\x7b\x3c\x18\x9c\x8e\x9d\x44\xce\xe8\x55\x3d\xc4\x33\xe5\xe6\x98\x74\xc4\xef\x62\x3b\xfc\x22\xf6\xa2\x29\x71\xb4\x1d\xbe\x91\xe7\x31\x08\xed\xf0\x7c\xff\xbc\x03\x45\x0f\x1b\x18\x7f\x72\x57\x0b\x49\x46\x90\x37\x06\x21\x4b\xec\x03\xa3\x13\x6b\x1b\x5b\xb3\x91\xcf\x94\xc6\x1d\xf8\xbb\x1b\x28\xf6\x12\x7b\xf4\x62\xd0\xee\x6f\x76\x96\xf7\xeb\x8c\x53\xd2\x93\x78\xce\xa0\x08\x29\xc3\x1e\xc9\x31\x28\x23\xcb\x38\x05\x6e\x28\xd7\x07\xbf\xbe\xbc\x3c\xe1\xcc\xdd\x0e\xdd\x6c\x38\x8b\x0d\x98\x38\x8d\x14\x39\x3a\x46\x37\x4b\xb0\x56\xe2\x1e\x7f\xe9\x0c\x47\x11\x14\xb2\x62\xd4\x39\x5a\x4d\x3f\x6b\x0a\xbe\x21\xc3\x41\xa6\x63\xde\x5f\xa3\x9b\x92\x9a\x3a\x0d\x5f\x9a\x16\x9e\x8f\x15\x0b\xc1\x69\x34\x8e\xd6\x92\xf7\x89\x73\x66\x5f\x11\x6e\xe4\x5b\x38\xd5\xe4\x25\x92\x71\xde\x62\xe1\x39\xc8\x89\xd3\x52\xff\x7d\x01\xbc\xf1\xc3\xed\x15\x56\xdc\x16\xd0\xd7\x4d\x7c\xec\xa7\xb4\x31\x50\x86\x97\xc4\xce\x34\x49\x45\xb3\x3e\x9f\x9b\x76\x9d\x89\xba\xc0\x57\x39\xf8\x74\x12\xc2\xfd\x1f\xcf\xbf\x7d\xbe\x2e\x7a\xe6\xae\x54\x2b\x38\x3a\xc6\x5c\x86\x30\xc5\x49\xf8\x0c\xaf\x6e\x1e\x39\xda\x65\x7d\x15\x11\x77\x4d\xbb\x16\x05\x39\xc7\x39\x4b\x79\xa5\x54\xae\xf0\xc9\xf0\x3a\x98\x4d\x5f\x0e\x2b\x43\xd1\xc3\x4f\x13\xd9\xf0\xf3\x6b\xd3\xa2\x4b\x7a\xce\x9c\x32\x34\x81\xbf\x1b\xc7\x72\x85\xb9\x3e\x1d\x98\x52\x2c\x0f\xcf\x99\xf1\x5a\x52\xbf\x1c\x0e\xaf\x97\xf9\xc2\xb2\x8e\x3b\x5c\x81\xde\x70\xf6\x33\x25\x8a\xc6\xbc\x5e\x00\xcd\x36\x70\x34\x71\x62\xcb\xc7\x94\xa3\xfa\x39\x50\xaa\x73\x6a\x8c\xec\x4c\x34\x22\xd0\xc2\x09\x7a\xe2\x04\x8a\x0b\x22\xdb\x59\xd3\xdb\xfb\xaa\x9b\x16\x49\x67\x2b\x07\x59\x23\x9b\xb6\x34\x57\x90\xfd\xe7\x33\xee\xbe\xbe\xe0\xd3\xdb\x65\x83\x07\xa7\x89\xc2\xe7\x8f\xd8\x32\x7c\xdb\x51\x69\x39\xd2\x58\xb2\x32\xa7\x93\x38\xde\x42\x3e\x16\xde\x4a\xcc\x93\x24\xf6\xe8\x82\xba\xb7\x4d\x11\x7c\x99\xa3\x46\xbb\xb4\x4c\xa6\x75\x90\xfa\x57\x9f\x68\x1a\xc4\xb5\x85\xce\x3b\x93\x0b\x25\x89\x7d\x81\x5e\x6a\xb5\x81\x4f\x1c\xe0\xd9\xcf\x53\x10\x47\x65\xfe\xcb\x1e\xab\x9e\xfa\x24\xb6\xe0\x76\x73\x86\x35\xf3\xe3\x74\x2e\xe9\x1c\xeb\xa3\x85\xdd\x2d\xb2\xf4\xb1\x8e\x33\x4f\x93\xa6\xab\x3b\x9d\xfe\x3f\x95\xfe\xaa\x98\xce\xe2\xf9\x47\x8f\x81\x25\x8a\xf9\xc8\x29\xaf\x22\x98\x02\x1b\x87\x05\x9e\x1d\x47\x4b\x14\xe4\x1f\xf6\xa0\xe4\x06\x31\x76\x36\xa7\x02\xeb\xe6\x26\xea\xcd\x0d\x2e\x11\x98\x54\xa2\x41\x8f\x38\x92\x84\x12\x71\x75\xd2\xbf\xde\x3d\x96\x0e\xc8\xfb\x8b\x68\xca\x61\x95\xeb\xb8\x12\x43\x50\x47\x21\x2c\xab\x59\x89\xfd\x2f\x23\xea\x19\x74\x22\x09\x55\x37\x97\x8c\xd5\x12\x8a\x3c\xdc\x20\xb1\x6f\x8f\x49\x38\xfa\xb0\xe0\xd3\xa6\xfd\x4a\x7e\x5d\x6d\x59\xfb\xd5\x3a\xd7\xad\x77\x14\x0b\x06\x1b\xe0\x25\x5b\x92\x6e\xae\xf0\xd7\x76\x8b\x86\xa9\x64\xf3\x76\x16\xa5\xf1\x87\xa7\xc7\xea\xa2\xc5\x4d\xf1\x7e\x14\x6b\xd4\x66\x2d\xab\x97\xd7\x8f\x79\x2a\x66\xb8\xbe\xa6\x11\x4f\xdf\x1e\x9a\xb6\x96\x2b\x9a\xd0\x6a\x7b\x1e\x96\xe6\x6c\x70\x03\x49\xdc\xa8\x93\x55\xed\x56\x9b\x54\x1b\x38\xe1\xf1\xb9\xba\x47\x11\xe4\x48\x13\xee\x4a\x1b\x7b\x8d\xa2\x71\x87\x7d\x57\x5c\x9f\xcd\x95\x9a\xa5\xc3\xe6\xdf\x00\x00\x00\xff\xff\x6d\xaa\xeb\xd6\x91\x06\x00\x00") - -func initDocAboutBytes() ([]byte, error) { - return bindataRead( - _initDocAbout, - "init-doc/about", - ) -} - -func initDocAbout() (*asset, error) { - bytes, err := initDocAboutBytes() - if err != nil { - return nil, err - } - - info := bindataFileInfo{name: "init-doc/about", size: 1681, mode: os.FileMode(420), modTime: time.Unix(1403768328, 0)} - a := &asset{bytes: bytes, info: info} - return a, nil -} - -var _initDocContact = []byte("\x1f\x8b\x08\x00\x00\x00\x00\x00\x00\xff\x1c\xcd\xb1\x6a\x44\x21\x10\x85\xe1\xde\xa7\x38\x90\x5a\xed\xad\x42\x2e\x81\xa4\xcd\x1b\x18\x77\xae\x0e\xac\xce\x8d\x33\x2e\xec\xdb\x07\xb7\x3a\x70\xf8\xe0\x3f\xa4\x13\x5a\x1e\x15\xb2\x0c\x3c\x20\x6b\xe2\xfb\xe7\x40\x69\xd9\x30\x45\x3a\xf8\xc4\x53\x16\x5a\x7e\x10\xf2\x78\xe2\x6f\x91\x1a\xcb\xd0\xe0\xdc\x21\xc3\x72\x31\x58\x23\xf0\x75\x2a\x6e\xf4\x80\x51\xee\xc9\x79\x7c\xac\xaa\x09\xcd\xec\xd2\x14\x63\x65\x6b\xeb\x37\x14\xe9\x71\xcb\x58\xc5\xbf\x96\x55\x17\xa9\xf3\xf8\xa2\xfb\x95\xc0\xb3\x84\x73\x12\x0d\xb9\x51\x90\x59\xe3\xdb\x56\xce\xe3\xb3\x67\xbe\xa7\x1d\x78\xdf\x4f\x60\x71\xff\x01\x00\x00\xff\xff\x7d\x69\x95\xc6\xbd\x00\x00\x00") - -func initDocContactBytes() ([]byte, error) { - return bindataRead( - _initDocContact, - "init-doc/contact", - ) -} - -func initDocContact() (*asset, error) { - bytes, err := initDocContactBytes() - if err != nil { - return nil, err - } - - info := bindataFileInfo{name: "init-doc/contact", size: 189, mode: os.FileMode(420), modTime: time.Unix(1403768328, 0)} - a := &asset{bytes: bytes, info: info} - return a, nil -} - -var _initDocHelp = []byte("\x1f\x8b\x08\x00\x00\x00\x00\x00\x00\xff\x3c\x8e\xb1\x72\x84\x30\x0c\x44\x7b\xbe\x62\x67\x52\x1b\x7a\xda\x54\x69\x93\x2f\xf0\x19\x19\x6b\x62\x2c\x22\xc9\x77\xc3\xdf\x67\xb8\x0b\x29\xb5\xbb\x6f\xb5\x5f\xb2\x11\x0a\xd5\x3d\xf7\x0a\x25\x93\xae\x89\x0c\x59\x14\x99\xdb\xc2\x6d\xc5\x21\x5d\xf1\x88\x07\xa2\x4a\x6f\x0b\x78\xcf\x36\x0f\x43\xc0\x4f\xe7\xf4\x1d\xcc\xa3\xfa\x8c\xf8\x3a\x61\x45\x1e\x90\x8c\x7b\x54\x96\x6e\xcf\x34\x32\x45\xef\x4a\x36\x0e\xe1\x25\x24\xd9\xb6\xd8\x16\x3b\xb9\xca\xe6\x27\x11\x6b\xfd\xd7\xaf\x5c\x08\xe7\xb6\x19\x74\x27\x3d\x2e\x17\x0b\x59\x52\xbe\x91\x81\xdd\xa8\xe6\x21\xa0\xb8\xef\x36\x4f\xd3\xca\x5e\xfa\x6d\x4c\xb2\x4d\x67\xc1\xb4\x4a\xf8\x2b\x82\x17\x82\x69\x82\xd2\x2e\xc6\x2e\x7a\x0c\x01\x6f\x4f\x57\x1a\x58\xd3\x98\x95\xa8\xc9\x42\xa3\xe8\x7a\x11\xe7\xcf\xde\xd8\x0f\x7c\x7c\xbe\x23\x95\xd8\x1a\xd5\xe1\x37\x00\x00\xff\xff\xd3\xb7\x7e\x3c\x37\x01\x00\x00") - -func initDocHelpBytes() ([]byte, error) { - return bindataRead( - _initDocHelp, - "init-doc/help", - ) -} - -func initDocHelp() (*asset, error) { - bytes, err := initDocHelpBytes() - if err != nil { - return nil, err - } - - info := bindataFileInfo{name: "init-doc/help", size: 311, mode: os.FileMode(420), modTime: time.Unix(1403768328, 0)} - a := &asset{bytes: bytes, info: info} - return a, nil -} - -var _initDocPing = []byte("\x1f\x8b\x08\x00\x00\x00\x00\x00\x00\xff\xca\x2c\x48\x2b\x06\x04\x00\x00\xff\xff\x62\xe3\x30\xc9\x04\x00\x00\x00") - -func initDocPingBytes() ([]byte, error) { - return bindataRead( - _initDocPing, - "init-doc/ping", - ) -} - -func initDocPing() (*asset, error) { - bytes, err := initDocPingBytes() - if err != nil { - return nil, err - } - - info := bindataFileInfo{name: "init-doc/ping", size: 4, mode: os.FileMode(420), modTime: time.Unix(1403768328, 0)} - a := &asset{bytes: bytes, info: info} - return a, nil -} - -var _initDocQuickStart = []byte("\x1f\x8b\x08\x00\x00\x00\x00\x00\x00\xff\x8c\x54\xdb\x72\xdb\x38\x0c\x7d\xc7\x57\x60\xdd\x97\xec\xec\x28\x72\xea\x3a\x75\x32\x3b\x99\x49\x9d\xc6\xae\x9b\x78\xe3\xe6\x9e\x37\x5a\x04\x25\xda\xe2\xa5\x24\x6d\x45\xfe\xfa\x1d\xc9\xd7\x99\xe6\xf6\x46\x00\x07\x38\xe7\x10\xa2\x3e\x61\x73\xff\x00\x23\x1c\xcd\x64\x32\xc5\xeb\xc0\x5c\x00\xb8\xc9\xa4\x47\xe9\x91\xa1\xa7\x80\x46\xa0\xcf\x8c\x0b\x48\xcf\x4c\xd9\x9c\x3c\x16\x32\x64\xa8\xa4\x96\x8a\xe5\x48\xcf\x36\x67\x9a\x05\x69\xf4\x3e\xfe\x08\x55\x9f\x22\xa6\x03\x32\x0f\x0c\x1b\xbf\xeb\xc1\xbe\x1a\xdc\xd8\x07\x80\x53\xce\x91\xa1\x90\x39\x61\x30\x28\xad\xf0\xc7\x00\x88\x94\x64\x06\x1b\x19\xe5\xb9\xc1\xc2\xb8\x9c\x37\xf0\xa4\x8e\x00\x6b\x10\x32\xce\x71\x99\x00\xb8\x93\x54\xa0\x0c\x75\x63\x5d\x4c\x58\xc0\x7f\x43\x46\x51\xc6\x7c\x16\x95\x66\x16\xa5\x26\x44\x19\x39\x3a\x01\x80\x1b\x57\x22\x43\x2e\x1d\x25\xc1\xb8\xb2\x6e\x53\x53\x2e\x1d\x0a\x63\x76\xcf\xf1\x98\xb9\x8d\x96\x31\x5b\x34\xf0\x64\x95\x5e\xbc\x9c\x76\xab\xd2\x46\x61\xb4\x9c\xb9\x92\x18\x32\xa9\x53\xbf\x95\x99\xfb\x1d\x95\x4b\x75\xaf\x56\x56\x5a\x5e\xb0\xb7\x2e\x2f\xde\x2e\xbb\x0f\x40\xde\xa4\x5f\x00\xc0\x2f\x12\xe4\x48\x27\xb4\xe3\xc2\x91\x78\xd5\x47\x5d\x8b\xdc\xdb\xe5\x28\xa3\xdc\x02\x40\x8f\x76\x56\x98\xd2\x1f\x0a\x31\x32\xd5\x6d\x7e\x06\x44\x2e\x85\xa8\xce\xcb\x18\xe0\xbf\xf1\x84\x92\xb0\x23\xca\xd4\x89\x97\xa6\xbc\x8f\x88\x57\x24\xbb\xb0\x8d\xc8\x2b\xa9\xf1\x1f\xec\x75\xb7\x54\x56\xea\x7a\xd7\xaf\x7a\xb4\x06\xd3\xe4\xfd\x9d\x57\x73\x9c\x7a\x6f\x0c\xc0\x19\x23\x65\xf4\x96\x9f\xd7\x31\xe2\x5e\xa5\x43\x9b\x90\x91\xc3\x40\x4e\x49\xcd\xf2\xbf\xd7\x20\xc9\x01\x60\x48\xa1\x30\x6e\x5a\xb7\xee\xa9\x99\x0f\x38\x26\x34\x3a\x97\x9a\x36\x40\x5f\x30\xa7\xd0\x12\x39\xbf\xd3\xbb\xfb\xd9\xd4\xda\x8c\x88\x1c\x29\x13\x28\x5a\x5e\x50\xf5\xae\x2e\xcd\x4c\x2f\x37\xb8\x57\x30\xa7\xa5\x4e\x8f\x51\xcc\x3c\x55\xbf\x00\x21\xb5\x4c\xa6\xe5\x5f\x1b\x1e\x55\x81\x01\x31\xe1\x18\x57\x89\xf8\x4f\xdf\xb9\xaf\x1e\xab\x31\xf9\xd6\xeb\x9c\x9c\x97\x46\xaf\xc3\x99\xe5\x2c\xd0\x46\x9d\x51\x8a\x69\xee\xb7\xb1\x16\x32\x5d\xaf\x0e\xd1\x58\xd2\x98\x85\x60\x8f\xe3\x38\x37\x09\xcb\x33\xe3\xc3\x71\xbb\xd9\x3c\x88\x0b\x1a\xcf\x24\x00\x7c\x73\xa6\xf0\x54\xf3\xdd\xd3\xf8\xf6\x47\x7d\xc2\xb7\x9b\x10\xe7\x92\x93\x79\x0d\xda\x69\x76\x9a\x4b\x87\x23\x75\x97\x1c\x2e\x66\xa7\x9a\x7e\x0e\x16\x32\xd1\x03\x2b\xdc\xef\x6e\xff\x28\xbd\x2e\x0f\xc7\x8b\xf6\x97\x41\x96\x94\x56\x0c\x1e\xb3\xde\xed\xf9\x68\x16\xdb\x9c\x95\x9f\xd6\x9d\x37\x3f\x9f\xd2\x5f\xc3\xe2\x6c\xf8\x54\xf4\xc3\xe0\x7a\xd2\xb5\x87\xae\x7d\xfe\x48\x62\x61\x6f\x2f\x44\xd9\xfa\x3a\x98\x5f\x86\xa3\xb3\x62\xfe\xe0\xa9\xbe\x2d\xc5\xd2\xd5\x23\x7d\x47\xd3\x93\x4d\x5a\xfd\xb9\x98\x7c\x7f\x98\x5f\xdc\xf7\x46\x57\xf7\xe3\xfe\xb4\x75\x3a\x39\x6b\x4f\x3a\xc3\xef\xc3\x2f\xa9\x3a\x1f\x76\x06\xca\xf1\x76\xda\x69\xc5\x89\xaf\x7f\x96\xcc\x4d\xb9\x29\x34\x3a\xd2\x9c\x1c\x39\x64\xd6\x7e\x84\xeb\xe1\xeb\xe5\x51\x57\x3e\x3e\x4c\xee\xe8\x5c\x4f\xc5\x5d\x4f\xb4\xca\xb6\x7c\xbe\x79\xfa\x7c\xda\xa5\xeb\x5e\x79\x71\x30\xff\x36\x78\x3c\xe8\xcf\x47\x57\x36\x56\x15\x05\xfc\x1f\x00\x00\xff\xff\x18\xa0\x78\x77\x91\x06\x00\x00") - -func initDocQuickStartBytes() ([]byte, error) { - return bindataRead( - _initDocQuickStart, - "init-doc/quick-start", - ) -} - -func initDocQuickStart() (*asset, error) { - bytes, err := initDocQuickStartBytes() - if err != nil { - return nil, err - } - - info := bindataFileInfo{name: "init-doc/quick-start", size: 1681, mode: os.FileMode(420), modTime: time.Unix(1403768328, 0)} - a := &asset{bytes: bytes, info: info} - return a, nil -} - -var _initDocReadme = []byte("\x1f\x8b\x08\x00\x00\x00\x00\x00\x00\xff\x9c\x53\x4d\x6f\x13\x31\x10\xbd\xfb\x57\xbc\x9e\xb8\x90\x70\xaf\xb8\x21\x21\x7a\x00\x21\x28\xea\xd9\xf5\xce\xc6\x56\xbc\xf6\xe2\x19\x13\x56\xca\x0f\xe0\xd8\x48\x0d\x95\x90\xf2\xe7\xf2\x4b\x90\x4d\x36\x6d\xf3\x71\xa0\xd6\x1c\xc6\x4f\x33\xef\xcd\x3c\xef\x7e\x20\xef\x23\x74\x68\x70\x43\xde\xc4\x8e\x20\x11\x57\x9f\xdf\x7f\xbd\x50\x6a\xfb\xfb\x57\x89\xf5\xc3\x2e\x79\x1a\xeb\x07\x9c\x40\xcf\x55\x57\x7c\xcf\xb7\x1a\x93\xfb\xed\xfa\xae\xc4\x41\xe7\x1e\xdf\xc5\xe6\x1c\x7e\xc4\xf8\x4c\xf0\xfe\xb1\xf3\xe9\xd8\x67\xe7\x3e\x3f\x5f\x15\xc3\x11\xba\x01\xb6\xeb\x3f\xcf\x66\x1a\x19\x8e\xb9\x56\x28\xe7\xe4\xed\x70\x92\x95\x1a\x69\x37\xfb\xe4\x5f\xfd\xc9\xdb\xdd\xa1\x2b\xea\xaa\xc5\x10\xf3\xab\x44\x60\x22\x17\x66\x10\xeb\xf8\x75\xc1\x60\xf5\x0f\x02\x67\x63\x88\xb9\xcd\xde\x0f\x70\x81\x45\x7b\x4f\x8d\x2a\xcf\x5e\x3f\x05\x9d\x08\x21\x2e\xe0\x82\x50\x6a\xb5\x29\x14\x0b\x27\x16\x62\x09\xae\x6f\x19\x1d\xa5\xb9\xa7\x46\xcf\x2e\x94\xc2\xe4\x65\x47\x2d\x71\xa3\x53\x70\x61\x76\x89\xff\x3a\x4b\xb5\x04\x70\x6d\x1d\xc3\x31\xb4\xef\xad\x06\xc7\x56\x16\x3a\xd1\x14\xdf\x98\xa0\xa5\x2c\x9b\x10\x17\x01\x8d\x63\x93\x48\x5c\x0c\x17\xbb\xce\x8f\xd9\xd8\xd2\xd9\x39\xe6\xb2\x5a\x4c\xf0\xda\xcc\x4b\xda\x47\xef\xd8\x4e\x71\x6d\x29\x51\xf5\xe1\x36\xcf\x78\x3a\x6a\x7e\x8a\x82\x81\x04\x4c\x26\x17\xad\x2f\xa4\x9b\x6a\x4a\x05\x9c\x0c\x08\x51\x88\xd1\xc6\x84\x2e\x96\x8a\xd2\xf9\x62\x83\xd4\x3b\x4b\x66\x8e\x98\x05\x5c\x7e\xcd\xd8\x56\xb1\x28\x96\x12\x5a\xe7\x89\xe1\x42\x7d\x5c\x34\x2e\x91\x91\x98\x86\x4b\xa5\x80\xe9\x1b\x7d\x1b\xb3\xd4\xcc\x92\xef\x6b\xf2\x3d\x3b\x33\x9f\xb0\xe8\x24\xd5\xc6\xb7\x93\x09\x32\xeb\x19\x81\x7e\xea\xae\xf7\xc4\xb5\x2c\x91\x6e\x3a\x7a\x74\xbb\x94\x55\x89\x22\x58\x2b\xc6\x65\x27\x75\x59\xf5\x37\x00\x00\xff\xff\x16\x13\x92\x0d\x43\x04\x00\x00") - -func initDocReadmeBytes() ([]byte, error) { - return bindataRead( - _initDocReadme, - "init-doc/readme", - ) -} - -func initDocReadme() (*asset, error) { - bytes, err := initDocReadmeBytes() - if err != nil { - return nil, err - } - - info := bindataFileInfo{name: "init-doc/readme", size: 1091, mode: os.FileMode(420), modTime: time.Unix(1403768328, 0)} - a := &asset{bytes: bytes, info: info} - return a, nil -} - -var _initDocSecurityNotes = []byte("\x1f\x8b\x08\x00\x00\x00\x00\x00\x00\xff\x6c\x53\xd1\x6e\xdb\x46\x10\x7c\xe7\x57\x4c\xf3\xd0\xbc\x28\xb4\x5d\xd7\x72\x6c\x20\x68\xe5\x44\x36\xfc\xe2\x18\xb1\xdb\xa2\x8f\xc7\xe3\x8a\x5c\xe8\x78\x4b\xdc\xed\x89\xe6\xdf\x17\x4b\x41\x46\x81\x56\x8f\xe2\xde\xcc\xec\xce\x0c\xfe\xe7\xf7\xf8\x7c\xff\x82\x4d\x18\x7b\x87\x17\xf2\x25\xb1\xce\x78\x12\xa5\x5c\x55\x7f\x11\x34\xcd\xe8\x5d\x6a\xa1\x02\x8a\xb9\x24\x82\x94\x84\x3c\x67\xa5\x01\x9c\x91\xdd\x8e\xe0\x62\x8b\x24\x4d\xc9\xba\x42\x53\x14\x2e\x04\x64\xd9\xe9\xe4\x12\x55\xbd\xcb\x68\x4a\x97\x57\xa0\x3c\x92\x67\x17\xc2\x8c\x48\xd3\xfb\x44\x8d\xd7\x9e\x33\x5a\xce\x9a\xb8\x29\xca\x12\x0d\x79\x20\x17\xd5\x78\x1b\x23\xa8\xdc\x22\x71\x4c\x74\x60\x9a\x56\x68\x25\x7e\x54\x94\x4c\x60\xc5\x4e\x12\x5c\x9c\xb5\xe7\xd8\x61\xe0\x9c\x0d\xc2\x27\x56\xf6\x2e\xd4\x55\xf5\x1c\xc8\x65\x42\x14\x25\x68\x4f\xd8\x49\x08\x32\x71\xec\x6e\xab\xea\xd3\x91\x9d\x33\x8e\x0c\x27\x55\xcb\x52\xa6\x3d\x8a\xa2\x21\x8a\x70\xa5\x65\xa5\xb6\xc6\xa3\xda\xb8\xdd\xa1\x13\x17\x2a\x98\x48\x2f\xb1\x2d\x5e\x61\x12\x65\xa4\x84\x7c\x3a\xe6\xf2\x0c\x12\x3d\x61\x22\xf8\x20\xa6\x39\x42\x22\x1c\x2e\xea\x73\x24\x5a\xd4\xd5\x26\x85\xc7\xdd\x51\x0a\x22\xe9\x24\x69\x4f\xad\xe1\x75\xc9\x0d\xab\x45\xd0\xe0\xcc\x8f\x03\x21\x53\x62\x29\x19\x25\xb6\x9c\xbd\x1c\x28\x51\x5b\x01\x87\x12\x22\x25\xd7\x70\x60\x65\xca\x27\xad\x53\x62\x55\x8a\xc6\xfb\x20\x47\xa4\x89\xd0\xca\xb2\x1c\xbd\x91\x2f\x6a\x0b\xcf\x15\xec\xa4\xc9\x38\x0f\xdc\x52\x8b\xd6\xa9\xab\x71\x57\x14\xe3\xf1\x86\xa3\x70\x54\x1b\xb5\x99\x26\xd0\x60\x87\x58\x6c\x2a\xd9\xe0\x5d\x05\x74\xac\x7d\x69\xc0\x39\x17\x5a\x41\x12\x68\x70\x1c\xde\x2f\xf2\xbb\x6d\x59\xb3\x60\x4c\x7c\x70\x4a\x61\x5e\x76\xff\xcf\xe7\x87\xe7\x07\xec\x69\xbe\xad\x80\x4f\xf8\xf5\xee\x66\xbd\xbe\xba\xbf\xc3\xcd\x2f\xeb\xcb\xf5\xb7\x8b\x6b\x5c\x7f\xbd\xde\x7c\x5e\x7f\xbb\xc4\xd5\xf9\x66\xb3\xfd\xbc\xb9\xc1\xd5\xcd\xdd\xc5\xe5\xe6\xfe\x72\x79\xd0\xab\x8e\xf9\xf6\xec\x6c\xec\xc6\x7a\x60\xad\xa9\x2d\x67\xe3\x3e\x9f\x05\x91\x7d\x19\x7f\x93\xf1\x4b\x47\xfa\x73\x26\x97\x7c\xff\xe5\xfc\xed\x04\xf2\x8e\x71\x72\xa3\x64\xca\xa0\xe8\xd3\x3c\x2e\xc9\x5c\xb2\x16\x02\xbc\x0c\x43\x89\xec\x9d\xfd\x7b\x8c\x3d\xeb\xc7\x8c\xa7\xef\xaf\x78\xfe\xf1\xfd\xcf\xed\x13\x5e\xb6\x5f\xff\xf8\xb1\xad\x80\xbf\xb7\xaf\x3f\xc1\xac\x30\xfb\x1a\x82\x8a\x2e\x2d\x68\x92\xec\x29\xd6\xb8\x97\x84\x28\xd3\x6a\x09\xa7\x97\x96\xcc\x33\x8e\x3e\x14\xf3\x40\x05\x83\xdb\x53\x05\x2c\xfd\x9b\x08\x0d\x45\xdf\x0f\x2e\xed\x97\x10\x5a\xdc\x16\x15\x19\x13\x6b\xff\x6f\xb1\x1c\x31\x70\xb4\xc8\xc6\x63\xf0\x8b\x96\x44\x2b\x8b\x6c\x4f\x86\xc5\x21\x1c\xfb\x85\x0f\x25\x5a\x97\x3f\x60\x30\x7e\xdb\xb2\xe7\xae\xc7\x48\x69\x27\x69\x70\x16\x5f\x8e\x9a\x5c\x24\x85\x1b\xc7\x5c\x57\xc0\xe3\x0e\x7a\x2a\x0f\x9a\x20\x7e\x6f\x05\xdc\x91\x33\x96\x05\x63\x96\xb2\x3a\x45\xc7\x4b\x54\xe7\xad\xb4\x75\xf5\x4f\x00\x00\x00\xff\xff\xa9\x8a\x29\x7c\x8a\x04\x00\x00") - -func initDocSecurityNotesBytes() ([]byte, error) { - return bindataRead( - _initDocSecurityNotes, - "init-doc/security-notes", - ) -} - -func initDocSecurityNotes() (*asset, error) { - bytes, err := initDocSecurityNotesBytes() - if err != nil { - return nil, err - } - - info := bindataFileInfo{name: "init-doc/security-notes", size: 1162, mode: os.FileMode(420), modTime: time.Unix(1403768328, 0)} - a := &asset{bytes: bytes, info: info} - return a, nil -} - -var _dirIndexHtmlDirIndexHtml = []byte("\x1f\x8b\x08\x00\x00\x00\x00\x00\x00\xff\xcc\xfc\xd7\x12\xf4\xb8\x76\x26\x0a\xde\xeb\x29\xfe\xd9\x31\x17\x33\x87\x2d\x91\x49\x4f\x1d\xed\x8e\xa1\xf7\x49\x6f\x6f\x3a\xe8\xbd\xf7\x54\xe8\xdd\x27\xea\x2f\xa9\x77\xb5\xb4\xa5\xee\x3e\xaa\xe8\x28\x5e\x24\x88\x04\xf0\x01\x0b\x58\x58\x06\x0b\x99\xff\xf0\xff\xe2\x0c\xd6\x8d\x4c\xfe\x47\xbd\x0f\xfd\x7f\xfd\x9b\x7f\xfc\xc7\x1f\xff\xef\x75\x9a\xf6\x1f\x7f\xff\xe7\x1f\x7f\xf7\xe3\x9f\xfe\xe9\x6f\xfe\xe1\x97\xef\x7f\xf4\xc9\x58\xfd\xf9\x4f\xc5\xf8\xa7\xff\xfa\x37\xff\x50\x17\x49\xfe\x5f\xff\xe6\x1f\x86\x62\x4f\x7e\x64\x75\xb2\x6e\xc5\xfe\xe7\x3f\x1d\x7b\xf9\xb7\xe4\x9f\x7e\x80\xff\x52\x30\x26\x43\xf1\xe7\x3f\xe5\xc5\x96\xad\xcd\xbc\x37\xd3\xf8\xa7\x1f\xd9\x34\xee\xc5\xb8\xff\xf9\x4f\xf4\x8f\xbc\x59\x8b\x6c\x9f\xd6\xe7\xc7\x54\xfe\x28\x9b\xbe\xd8\x7e\xd4\xd3\xb6\x17\xf9\x8f\x69\xfc\xb1\xd7\xc5\x8f\xbc\xd9\xf6\xb5\x49\x8f\xbd\xc8\xff\xcb\x8f\xbc\xc8\x8a\x71\x5f\x93\xbe\x79\x8b\xfc\xc7\x55\xa4\x3f\x8e\xad\x19\xab\x1f\xb2\x29\x38\x7f\xfa\x97\x0e\xe7\x75\x9a\x8b\x75\x7f\xfe\xfc\xa7\xa9\xfa\xfb\xbd\xd9\xfb\xe2\x37\x3d\x0a\x3f\xbb\x98\xc6\xff\xa0\xc9\x5f\x1f\xea\x3f\xfe\xe3\x8f\xbf\x33\x93\xbd\xfe\xf1\x4f\xff\xf4\xef\xf4\xf4\xcc\xbf\xed\xe8\x2a\xd2\xad\xd9\x8b\xbf\x5e\xb7\x19\x92\xea\xb7\x95\xeb\x7d\x9f\xb7\xbf\x07\xc1\x2a\xd9\x8b\x2b\x79\xfe\xae\x99\xcb\xed\xef\x9a\x09\xfc\x25\x05\xad\xc1\xe1\x8a\x88\x2e\xa8\xa1\x4a\xf0\x6f\xee\x4e\x2f\x1d\x1f\x8f\xa8\x21\xd6\x27\x6c\x37\x6d\x3f\x43\x98\x0c\x85\x5b\x91\xc8\xc9\x6c\x97\x3f\xfd\x8f\xf3\xbe\x5f\xcd\xbe\x17\xeb\xbf\x99\x87\xbf\x46\xce\xff\xd8\xe2\xff\xe0\x8a\xfd\x8f\x1d\x67\xc9\x9a\xff\xa6\xc7\xed\x18\x86\x64\x7d\xfe\x5b\x9f\xac\x55\xf1\xdf\x7e\x9d\xb9\xbf\xde\xf0\xff\xfc\xac\x66\x6b\x91\xec\xd3\xfa\x9b\x3e\xff\x7f\xbf\x80\xff\x3b\xb5\x7f\xf2\xc3\x7f\x5c\xf5\xff\x1c\x09\x67\x53\x5c\xf3\xb4\xee\xbf\x65\xd9\x26\xdf\xeb\x3f\xe7\xc5\xd9\x64\xc5\xdf\xfe\xcc\xfc\x97\x1f\xcd\xd8\xec\x4d\xd2\xff\xed\x96\x25\x7d\xf1\xe7\xcf\xdf\x41\xbf\xc0\xf4\xcd\xd8\xfd\x58\x8b\xfe\xcf\x7f\xda\xea\x69\xdd\xb3\x63\xff\xd1\x64\xbf\xb0\x49\xbd\x16\xe5\x9f\xff\x94\x27\x7b\xf2\xeb\x62\x80\xf7\xdf\xfe\x52\xf0\x7f\xa7\xc9\x56\xe0\xe8\x7f\xa1\x69\x9a\xa1\x69\x9e\xe6\x19\x9a\xfe\x25\x95\x69\x66\xfa\xe5\x55\xa8\x68\x9a\x66\x7f\xf9\xa0\xad\x5f\x3e\x64\xfa\x5f\xca\xff\xe5\xb1\xe8\xff\xcc\xd3\x4f\x24\x05\x62\x78\x6c\x81\xe4\x7f\x0a\x87\xa6\x59\xaf\xe5\x8e\xcf\x4f\x3c\x7c\xa8\x5d\x13\x78\x57\xdf\x04\xc7\xb9\xe7\x40\x0c\x48\x6c\xf5\x7f\x03\x5f\xfa\x36\xb2\x83\x07\xed\x8b\x80\x47\x2a\x44\x20\x81\x7f\x02\x10\x38\xe7\x0f\x07\x1e\xab\x1d\x83\xe4\xc9\xc5\x25\x28\x9e\x83\xf4\x2b\xfe\x87\xf9\xca\xc3\x7f\x80\xaf\x24\xa6\x59\x02\xdd\xc8\xb7\xe0\xb9\xfa\xe9\x3f\xe3\x01\xbb\x7f\x82\x2b\x9e\x5b\x20\xb1\x40\x41\x09\x6a\x17\x1c\x82\x0f\xf9\xed\x7f\xc5\x07\xf6\xb9\x23\x7e\xc5\xbf\xfe\x2a\x1e\xbc\xfa\xe1\xbf\xc1\xfb\x99\xc7\x81\xd1\x33\x01\x7c\x17\xc6\xdf\xe0\xfd\x16\x5f\xc4\xc3\x13\x28\x06\xcf\x04\x7f\x33\x7f\x3f\xe9\xfd\xab\x78\x7f\x9d\xfe\x7f\x35\xde\x5f\xf3\xff\x7a\xbc\x3f\xd7\xe3\xaf\xe3\xfd\x4f\xe8\xff\x4d\xfe\x5f\xf3\xc7\xaf\xf4\xff\x55\xbc\x33\xb5\x13\x10\xfb\x59\xfe\x93\xbe\xbf\x4e\xff\xcf\xf9\xfd\x5f\xa7\x1f\x5b\x5c\xcb\x04\x9a\xb1\x4b\xc1\x69\xc6\x44\x10\x57\x73\xfb\xfc\x7f\x46\xff\xb6\xf4\xce\xaf\xf4\x80\xda\x1d\xa4\x20\xa4\xf7\x33\x48\x71\x4a\x52\x82\xea\x2f\xed\x27\x65\xe7\x41\x02\x40\x42\xf3\x7f\x4a\x3f\xb5\x0b\x2b\x38\x28\x3c\x00\x12\xe2\xe6\x9d\xa0\xfd\x0c\x2b\x08\x65\xf3\x02\x52\x92\x9a\xfc\x9b\x3c\x70\xaf\x82\xf6\xeb\xf8\xfe\x03\xfa\x7f\xd2\xf7\x57\xdb\xff\x4f\xf1\x7f\xce\xcf\x5f\xe5\x57\x55\x2d\xec\x13\x40\xb6\x3e\xfd\xdf\xc1\xfb\x6c\x42\xf8\xeb\x78\xfe\x35\xde\x6f\x9e\x5f\xca\xbd\x9f\xf8\xe0\xf7\x1e\xca\xbf\x8e\x47\x22\x62\x0c\xfe\x65\xfd\x9c\x7f\x1f\xee\xaf\xe2\x7f\xf0\x9f\xf8\x3f\xd7\xeb\x21\xfd\x01\xfc\x99\xff\x05\x2f\x31\xff\x37\xa0\xfe\x5d\xfc\x9f\x78\x7b\xf6\xbf\x54\x1f\x1c\x49\x9a\x36\xab\x92\xa6\xb9\x8b\xbb\x68\xfa\xa2\xf5\x5f\x84\x32\x43\xd3\xec\x4f\x51\x5c\xd1\xfc\x7f\x98\xff\x59\xdf\xa4\x4d\x9a\xe6\x50\xe9\xfa\x67\x3c\xfa\xcf\x7f\xfe\xd5\x2a\xfc\x69\x8a\xfc\xd7\xdf\x18\x20\xff\x00\xfe\xfa\xd5\xdf\xfc\xc3\xb6\x3f\xbf\xa4\xe0\xff\xf5\xc3\x99\x8e\x35\x2b\x7e\xfc\xed\x4f\x0b\xe3\x17\x1d\xb2\xfd\xdd\xb4\x56\x3f\xfe\x2f\xf0\xa7\x0a\xfc\xdb\xff\x96\xf6\xc9\xd8\xfd\xf8\xc7\x34\xc9\xba\x6a\x9d\x8e\x31\xff\xdb\x9f\x0a\xe7\xef\x8f\xb5\xff\xff\xfc\x46\xff\xcc\x63\xf5\x2f\xca\xa7\xf1\x19\xc3\xbe\x20\x55\xac\xa6\x5f\x68\xfc\x3a\x5e\xcd\x7b\xd5\xaf\x2a\xe9\x17\x0d\xc3\xd2\xd1\x2f\x69\x49\x82\x54\xfd\xcb\x8b\x18\xda\x42\x20\xd9\x6e\x0a\xc7\x50\x0e\x0b\x4f\x6c\x31\x4c\x2c\x52\x4d\xec\x30\x4a\x1a\x08\x63\xec\x2b\x7d\x14\xd8\x58\x96\xf5\xfd\xcf\x15\x0a\x18\xc5\xe6\x05\xaf\xf8\x2e\xbc\xd7\x7e\xb4\x9b\xa7\xad\x31\xff\xe8\x3e\x8d\xf6\x8f\xcc\x07\x37\xee\xc9\x2a\x2f\x7a\xfc\x2d\x6e\x29\x8b\xec\x5a\x79\x29\x60\xed\x82\x15\xe1\xf7\xec\x78\xa4\xcb\x1d\x32\x57\x05\x5a\x68\x6d\x99\xa0\x56\xab\x1a\x36\xc6\x07\xb3\x9d\x87\x58\x06\x98\x2e\x3e\xc7\xab\x13\xed\x9b\x9f\xfe\x61\x63\x5c\x15\x8d\x31\x50\x52\x54\xd2\x10\xfe\x8e\xed\x94\x4a\x1d\xe3\x81\x4a\xda\x55\xc8\xc8\x12\x44\xb7\x8c\x9b\xdc\xb4\xe5\x0f\x54\xd6\xd9\xb8\xdf\x06\x8a\xb2\x99\xc1\xbc\x26\x4d\x0c\x25\xff\x1c\xd2\x55\x12\xe3\x6e\x75\x68\x9b\x8d\xcf\x65\xdc\x72\x5f\xde\x06\xfb\x8d\x12\xcd\xaf\x52\x3c\x0b\xd3\xce\xcd\x6b\x25\x5c\x60\x47\xee\xbf\x3a\x0b\xdd\xf2\x52\x4b\xd9\xcb\xa5\x0d\x69\xf8\xef\xac\x39\x5e\x02\x05\x45\x6a\x97\x43\x53\x69\xd2\xd2\x7e\xf8\xcc\x8c\xc7\xab\x24\xaa\x94\x93\xd7\xc8\xb7\x1f\xbe\x19\x8f\xb5\xc5\x5b\x97\x91\x1e\x99\x98\x17\x7f\x15\xac\x85\x4f\x77\xdc\xe5\x87\x98\x3a\x3f\x5f\x9b\x56\xbe\xec\xe7\x76\xa3\x5b\xb6\x6a\x50\x1f\x6c\xaf\x1f\x04\x8b\x47\x96\xc0\x08\x3e\xe3\xc2\xc0\x6e\xd0\x7d\x40\x64\xaf\x14\x1f\xba\x12\xff\xec\x04\x99\x2f\xe2\x54\x5a\x50\xbe\x7f\xd4\x97\x1e\xf8\xd0\xb8\xf1\x6a\xe4\x7d\xe5\x08\x98\x77\xe8\x6c\x85\xb1\xcd\x48\x8c\x19\x6e\xf3\x13\xa3\x9f\x9d\xca\x57\x78\xf8\xf1\x13\xba\x00\xa1\xee\x06\x91\xe4\x65\x6c\x03\xf2\xb7\x54\x17\x62\x1e\x61\x39\x27\x56\xaf\x22\x2e\x23\xd9\xaf\x00\x2e\xc6\x4f\xa2\xa6\x44\xce\x37\xae\xd8\xbc\x40\x73\xba\xd5\x03\x2c\xe9\xea\xa2\xb5\x94\xa3\xc3\x92\xe0\x72\xab\xfb\xc9\x28\x8e\xe7\x1b\xb6\x8a\xb1\x91\x2c\xff\xf9\xff\xfb\x7f\xff\x86\x01\xd7\x62\x2e\x92\xfd\xef\xc7\xe9\x9f\xdf\x7e\x5b\xb6\x35\x6f\xf1\xf7\xbf\x18\x5a\x49\x33\xfe\xd3\x3f\xb3\xf0\x9c\x54\xc5\x1f\x8b\x83\x87\xfa\x9f\x39\x78\xde\xbc\x77\x3f\xa1\x0f\x1d\x99\x65\x5e\x1b\x0f\x18\xba\x31\x09\xf9\xfe\xc7\x9f\xd8\xa5\xa7\xe1\xd7\x5a\xbc\xea\xd2\x79\x7e\x0d\x18\x5a\x3b\x51\x51\xe1\x4a\x9e\x1b\x0c\x5e\xda\x04\x77\xf1\x59\x97\xbf\xe9\xa6\x71\x64\xd8\xe2\x55\x45\xe5\x1d\x5f\x10\x98\x60\x82\x50\x97\x77\xec\xb7\x7c\xe0\x8c\xd0\x22\xb0\xd3\xf6\x12\xce\x49\x00\xc3\xb0\xf7\xd4\xa9\x6f\x22\x7f\xa6\x35\xc1\xb6\x33\x7d\x28\x63\x4c\x3d\x9e\xb9\x2b\xae\x97\xd5\x26\x68\x43\xab\xd0\x9e\x0f\x05\x86\x1f\x62\xe3\xf7\xcc\x8c\xe0\x75\x97\x1c\x0a\x07\xa5\x03\xb2\xcf\x30\xd4\x5e\x20\xf3\x5e\x9d\x24\x5e\xa7\xde\x64\x98\xe2\x66\x89\x8d\x76\x94\xc7\x99\xe9\x46\xe5\xf8\x75\xc7\x94\xbb\x09\x9f\x40\xc5\xb6\x36\x9c\xf2\xaa\x78\x48\x82\x71\x84\x54\xa9\x1a\x22\x69\xa4\x91\x44\x3f\x6d\xdd\x8b\xa8\xf0\x68\xa0\x9f\x0b\x64\xaa\x22\x93\xbe\xa2\xa8\xb4\x67\x69\xd5\x72\x39\x94\xb2\xc0\xd1\xa1\x32\xb7\xc7\x51\x35\x44\xde\xca\x82\x2f\xa3\x26\x34\xf7\xd9\x5e\x29\x16\x74\x8f\x42\x81\x15\x86\x01\xc1\xc6\xc5\xcf\xb0\xdf\xd5\x0e\x3b\xb2\x64\x60\xb0\xf9\x52\x5d\xe3\x2b\xdc\x28\x28\x3f\xf3\x7c\xd9\xfe\x17\x08\xa3\x70\x2b\xb2\x25\xa6\x3f\x33\x83\x92\x45\x47\x8f\x17\x05\xa2\x62\x7c\x23\x1a\x84\x7e\x41\x71\x72\x2f\xbe\x0d\xd1\xec\x2b\x61\x67\x6f\x96\xed\x4e\xcb\xd1\x4c\x66\xc1\x6a\x1d\xfb\xbd\xb2\x98\x3e\xe5\x88\xbf\x85\xbe\xab\x0b\xce\xb2\x27\x3c\x50\xf5\x54\x5e\x27\xde\xcd\xc3\x7b\x18\x37\x02\x31\x46\x4d\x93\xec\x0a\x72\x62\x1b\x69\x83\x9f\xc7\x60\xbf\x9a\x71\x5c\x6d\xc7\x6b\x8d\x9b\x0e\x2c\x95\x2b\xd2\x2c\x27\x22\xed\x6c\x5c\x37\x09\x96\xa8\x58\x97\x14\xe8\x99\x14\x28\x91\x31\x78\xed\xc7\x68\x4f\x6b\xda\x8f\x67\xdf\xb1\x51\xd2\x35\x5e\xec\xd8\xe7\xc6\x2d\x0f\x21\xd1\xf6\xea\x3c\x3a\x87\xb7\x5b\x49\x1d\xd0\x72\xea\x78\xaf\x40\x72\x95\xde\xd7\x32\x5e\x27\x11\xea\xdb\x5a\x69\x3c\xaa\x2c\xdd\x92\xa6\x96\xf5\xfa\x6a\x64\x69\xfa\x54\x05\x66\x0a\xc3\x44\x2a\xe9\xd5\x61\x63\x8e\x87\xaa\x27\x50\x2a\x41\x56\x87\xd3\x13\x54\x03\xd5\xbd\xaf\xdc\xc1\x09\x0a\xd4\x06\xb7\x73\x9e\x7f\x28\xa0\x42\x20\x30\xad\x3a\x78\xbc\xcb\x43\xee\x3e\xb4\x65\x31\x48\x1a\x7f\xc9\x9e\xda\x09\x4c\x16\x6a\x48\xd1\xbd\xdc\x57\xb7\xa9\xde\x3c\x73\xb1\xab\xb1\x4b\xa0\x3d\xaa\xaa\x2a\x9a\x59\xa9\x53\x45\x77\x93\x64\xec\x6b\xe8\x53\xcb\xa0\x8d\x2b\xb3\x6c\x31\x9f\x21\x86\xd0\x32\x5f\x5a\x7b\xf2\x69\x3c\x76\x98\xdc\x86\x19\x72\x7e\x6d\x60\xbb\xca\x73\x55\xa8\x0f\x65\x5a\x52\x30\x29\xc1\xe7\x02\x73\xe4\x75\xbf\x3a\xee\x75\x89\x51\x36\x1b\x0e\x27\x5e\x95\xe7\x74\x3a\xbe\xc0\x1a\x1e\x66\x04\xf8\xe3\xdb\xee\x14\xc8\xbe\x34\x9d\x0e\x5a\xcb\xae\x25\xd3\xd8\xd5\xef\x2a\x21\x92\x24\xfb\x63\xc9\x87\xf1\xbf\xcb\x07\xc8\xeb\x3e\x26\x0f\xf1\x51\xb9\xaf\x87\xdf\x9f\xb4\xd7\xd5\x3e\x6f\x4e\x4c\xb6\xf1\x93\x66\x2b\x4c\x04\x7d\x74\x53\x6a\xd9\x0d\xc9\xce\xa9\xca\x5c\x10\x5d\x14\xe5\x8b\x7d\x4f\xa9\x9e\xa6\x3a\x33\x46\xf3\x42\x23\x5e\x94\x3b\xb6\x06\x26\x4d\x64\xd4\x01\x89\x89\x31\x46\xf2\xa1\x80\xcf\xd6\xa8\xdd\xac\x6d\x14\xe5\x8c\x5f\xf3\x34\x74\x12\x94\x44\x78\x41\x60\x8c\x5b\x91\x4e\x9b\x89\xe8\xd3\xa4\xb3\x7c\xb7\x1b\xaa\xd6\x16\x13\x97\xa7\x8f\x6f\x84\x8a\xf9\x29\x94\xb6\xc5\x54\x62\x71\x9f\x89\xcf\x66\x7e\x12\xec\x33\x34\xa5\xc1\x3d\xe9\xf9\xf2\xe4\xf0\xb2\xe9\x4a\x4f\x2e\x27\xbb\xb5\x3e\x89\x61\xdc\xc4\x68\xe4\x34\xc7\x5a\x02\xf1\x27\x2c\x0e\x76\x51\x08\xa3\x05\x36\x15\x69\xad\xec\x4b\x0f\x15\x79\x77\xa2\x45\x7c\x86\xa8\x68\x33\x9a\x41\xa9\x73\x1e\x8a\xe3\x55\xb2\xac\x87\x80\xdc\x6b\x71\x55\xa6\xcf\x52\x62\xcd\x0a\xf9\x02\x07\x7d\xa2\x67\x45\x31\xc6\x9d\xb1\x43\xc9\xbf\x87\x09\x56\xc5\x38\x0f\xc5\x52\xf3\x7a\x75\xe4\xc5\x07\x52\xae\x01\xe0\x0e\x4f\x7e\xbc\xdc\xed\x97\x03\x4e\x9f\x49\x2f\x43\x30\xb7\x8b\x75\x60\x0a\xfe\x96\x36\xb7\x09\xbe\x0d\x02\xf4\xfa\xfc\xda\x17\xd7\x35\xe4\x7b\xb3\x32\xed\x0e\x6f\x5a\x9c\xe5\xc0\xf6\x47\xd7\x98\xd8\x57\xa8\x95\xea\xea\xda\xc2\x76\x0b\xcd\xa9\x73\x63\xf2\x95\x65\xa4\xab\xab\xab\x58\x3a\xc6\x01\x2f\xd7\x58\x6a\xbf\x5a\x2b\x26\xe7\xfc\x6d\x26\xa1\x8b\x19\x29\x42\x16\x9c\x41\x7a\x34\x57\x78\x9e\x37\x0d\xb6\xe0\xd0\x2c\xf2\x25\x22\xdc\xca\x0f\x26\x00\x82\x3c\xb0\x04\x81\xc9\x5f\x5a\x61\x14\xa7\xf3\xa7\x60\x82\xac\x88\x8a\x96\xaa\xb1\xd1\x38\x7e\xed\x44\x64\xba\xfc\x52\x91\x54\xb8\x45\xcd\x8e\xbd\x92\x41\xec\x01\xbe\xd1\x9b\x62\xc5\x7d\xf3\x6e\x89\xb2\xa2\x4e\x95\x59\x4e\x38\xb4\x5b\xa5\xa7\x57\x8c\xaf\xdc\x5d\x18\x7b\x83\x85\x54\xeb\xc3\xb4\x31\x73\x9e\xd5\x59\x29\xc9\x5b\x90\x4e\xb8\x30\xfe\x0a\x4b\x91\xb3\xf2\x39\xda\x99\x83\x7a\xb3\x3d\x11\x40\xcd\x62\xaf\x37\x5c\xa4\x31\x17\xd4\xe5\x09\xcd\x78\xce\x43\x4c\x7c\xd5\x1d\xb6\xdd\x81\x41\x6b\x35\x9e\xf0\x91\x5c\x4c\xd4\x58\x3e\x12\xd3\xa9\xbd\x1f\xd1\x16\xb3\x7a\xfd\xdb\x30\x50\x68\x39\x4d\x89\x46\x83\x55\x77\x5b\xf5\x95\x95\x8e\x6a\x12\xad\x36\x13\x9f\x4a\x41\x6f\x00\x0e\xc5\x61\xf3\xf7\xe1\x52\x31\xb6\x6c\xa7\x3b\xdb\x09\x18\x51\xe5\x7b\x1f\xa9\xe8\x39\x1b\xdb\x02\x31\x3b\x1b\x5c\xd4\x76\xa2\x4e\x7f\x39\xb8\x23\x8a\xdb\xdb\xca\xba\x63\x73\x00\xa6\x9e\xea\x60\x48\x32\xe8\x09\x21\x00\x27\x7c\x77\x09\xb0\xca\xc2\x85\xae\xc4\x93\xa8\xeb\xfb\xa3\x05\x4c\xb3\x16\x92\x3f\x12\x54\x64\xe2\x6c\x6d\x21\x63\x9b\x82\x85\xd0\x97\xc1\x22\x2e\x2e\x22\x21\x71\x2f\xca\xb5\x28\xc3\x0d\xec\x19\xa0\x07\x5e\xdd\x45\xd3\xc3\x94\xf4\xd9\xdd\x7f\xe9\xcf\xcf\xdd\xc9\xf7\x82\xdb\x39\x87\x35\xb0\xec\x7f\x4a\x66\x34\x7f\x2c\x91\xd1\x61\x7f\x31\x29\xa0\xcf\xc9\xf7\xbc\x67\xba\xe6\x1b\x2f\x0c\x6d\x25\x8e\x60\x35\x4a\xe4\x0d\xbd\x1a\xd5\x93\x2b\xa0\x1f\x0d\x71\xd3\x03\xb4\x40\x80\x3e\xb7\x10\x61\x66\xb0\x32\xb7\x23\xd0\xd6\xe5\x59\x2c\xc2\xf5\x6e\x7d\xa7\x4f\xe1\xb3\x47\xe2\x14\x5e\xdf\x8b\xb8\x4e\xe2\xbd\xa2\x6a\x57\x43\x44\xbb\x10\x82\xc2\x08\x6c\xc6\x5e\x82\x30\xa0\xcf\x54\x07\x00\xc8\xf9\x35\xf9\xb6\x44\x12\xa9\x75\xd9\x8b\xb9\x48\xc5\x9b\x78\x69\xdf\x27\x2f\xcb\xca\x2f\xd7\x0f\x15\x49\xe7\xc6\x27\x40\x7c\x80\xe3\x3d\xe6\x53\x8a\x39\xbb\xa5\x02\xf9\xf3\x9e\xf1\xfb\x5c\x60\xa5\xf6\x83\xde\x12\xf2\x53\x09\x3a\x70\x9f\xdf\x2c\x19\x67\x14\xdc\xb1\x9c\x9e\x86\x50\x62\x1e\xd8\xf3\x18\xc3\x80\x75\xba\x07\x19\x0a\xcc\xcc\x14\x37\x3d\xed\x98\xa4\x1b\x0a\x74\xa8\x40\xc4\x73\xf6\x8c\x9b\x43\xae\x98\x56\x82\x63\x8f\x97\xc8\x8b\x86\x65\x76\x2a\xcc\xd0\x2b\x09\x89\x2c\x23\xd5\x30\x2a\x80\xc0\xa3\xef\xe7\xf5\xb1\x11\xa9\xa8\x3a\x95\x5f\x9a\x80\x71\x44\x1f\xb5\x91\xd3\x22\x36\xb9\x76\x32\x37\x16\xdc\x59\xba\x11\x1a\xfe\x60\x0c\xb6\xf5\x87\x1f\x81\x41\xa0\x57\x04\x40\xbb\x0c\xd8\x67\xda\xa6\xce\xee\x34\x4a\x2f\x07\x18\xba\xc0\x1f\xee\x4b\x36\x5d\xb7\x53\xea\xb5\x53\x91\x12\x33\x08\x99\xcd\x4c\x3e\x59\x74\xac\xe4\xda\xc9\x8a\xcc\x53\x4e\x26\x83\x87\x79\x47\x41\x73\xf4\xe0\x61\x85\x64\x20\x97\x04\x17\xbd\x56\x10\xc5\x25\x22\xd6\xb3\x9b\x27\x7c\xa1\x39\xeb\x62\x7a\x6a\x73\x96\x1c\xd0\xe4\x60\x96\x84\xd6\x0e\xa7\x2a\x5e\xc2\x67\x3e\xf6\xce\x39\x5e\x60\x58\xa7\x97\x30\x9a\xe0\xbd\x0a\xa3\x2b\x30\x77\x0d\x66\x95\x7f\x94\x6b\x80\x82\xc9\xa9\x94\xb2\xe5\xce\xd5\x55\xef\xfd\xa2\xe5\x87\xef\x68\xc3\xc2\x6a\x0f\x04\xe3\xbc\xc2\x8e\xe9\xe2\x7a\xef\xab\x8f\x57\xac\x05\xd0\xe6\x1c\xde\x41\xb3\x51\x7d\x59\xf6\x25\x9c\xca\x7d\xcc\x6c\xcb\x47\x9e\x97\x65\x46\x37\x25\xea\x90\x1b\x7d\x3c\x46\x1f\xb7\xab\xe8\x2c\xa4\xeb\xbb\x36\x2e\x6d\xe3\x36\x69\xfa\x22\x07\x6a\x60\x8a\xcb\x95\x3e\x2b\xe1\x32\x35\x96\xad\x9c\x23\x95\x5c\x39\x1e\xed\x0a\x4a\x07\xd6\x7e\x71\x8a\xbb\xa1\x5f\x0e\x14\x5e\x16\x42\xbf\x0c\x28\xac\xbd\x5a\x91\x16\x4c\xc8\x70\x9b\x9c\xfe\x14\xaf\x42\x75\x71\xe8\xe2\x37\x33\xcd\x3f\x7a\x3f\x26\x02\xbd\xbe\x49\x0b\x72\x10\xd7\xe8\x61\xaf\xd0\x82\xf5\xa8\xf0\x4a\x96\xa3\xae\xdb\xf1\x8c\xf6\xd6\x47\x4f\x1c\x0d\xdb\x3d\xf0\xd3\x2d\x74\xa7\xb3\x35\xbc\x47\x32\x40\x00\x5d\x4d\x40\x59\x6b\xa6\x2b\x9a\xf2\x31\xf6\x69\xe3\x95\x74\x95\x91\xa1\x4c\x25\x9c\x5f\xc4\x47\x69\x86\x36\x0d\xcb\x57\x46\xd8\xc2\x21\xf1\xf7\xdd\xfa\x65\xf9\xc7\xda\xfc\xd3\x7f\xb7\x17\x3a\x8f\xda\x17\xfe\xc3\x7b\x61\x3c\xc4\x33\x8f\x24\x2e\xa3\xa5\x8a\x60\xba\xbb\xe0\xd9\xbb\xc3\xee\xf5\x4a\x78\xec\xa3\xaa\x82\x02\x52\xf4\x88\x4c\x15\x4e\x57\xe0\x14\x96\x93\xd7\x12\x53\x45\x25\x1b\xcb\x44\xaa\x8b\x7b\xb2\x29\x25\xc1\x3e\x2f\xc4\xd7\x83\x93\x58\xc5\x5e\xec\x8a\xa9\xfb\xd6\x67\xfd\x8a\xb9\xa3\xb8\x5e\x6a\x5e\x57\x04\x8e\x1b\x03\x24\xd8\x6f\xc2\xdd\x88\xa1\xed\x78\x69\xb4\xcc\x22\x56\x60\xa2\xda\xac\x2c\x8f\x33\x09\xa8\x6f\xa9\x4a\x44\x79\xe4\xa3\x2f\x60\xe4\xc8\x7f\xf0\xa2\x07\xc0\xc7\x83\x07\x46\x70\x82\x58\x9d\x03\x45\xf5\x33\xc8\xa8\x3c\x66\x82\x60\x15\xfd\x72\x83\x87\x4f\x04\xa6\xdf\x40\x90\x1f\x94\xec\x85\x42\xd1\x18\x34\x38\x8f\x9f\x5b\x2a\xa2\xe4\xa8\x7c\x2e\x7f\xe7\x74\xa6\x3e\x8b\xd8\xd3\xaa\xe8\xde\x64\xce\x7e\x28\x30\x98\xef\xba\x1d\xb7\xbb\x05\x6d\xfb\xea\x48\xac\x16\x15\x96\xca\x3f\x06\x5e\x8e\x45\x40\x1f\xd3\xbb\x73\x91\xe3\x68\x05\x65\xb8\xb8\x73\x84\x0c\x9c\x65\x37\x81\xc4\xd4\x71\x74\x17\x77\x95\xfd\xf6\xa9\xa0\x3b\x96\x23\x90\xce\x41\x71\x7c\x76\x30\xf4\xcb\xf4\x89\x56\x87\xb3\x79\xd2\xe4\x6f\x89\xc1\x41\x92\xc1\xad\x23\xb9\xe5\xcb\x66\x04\x7d\x87\x1a\x99\x6e\xf4\x1b\xd0\xd8\x67\x23\xdb\x52\x54\x78\xaf\xe9\xe0\x60\x8e\x0d\x0e\x76\xac\x92\x9a\xb8\xdd\x5f\xac\x6b\x9a\x59\xba\x89\x70\x5c\x70\xc0\x69\x40\x52\x02\x63\x7d\x07\xd6\x7b\x8f\xa0\x15\x38\x68\x14\x86\x8d\xdb\x18\xce\x95\xc3\xee\x38\x25\x16\x2e\x81\xb6\x09\x8f\x65\xda\x04\x29\xbf\xe5\x1d\xc1\x11\x3f\xb1\xbb\xcd\xb6\x54\x31\x20\xee\x9c\x6f\xb8\x30\x2b\x5b\x21\xb2\xcc\xed\x40\x62\x15\x89\xcc\xbb\x5c\x38\x3c\x93\x68\x35\x46\x23\x2d\xc3\xac\x93\x3a\xa9\x59\xf3\xb3\x40\x27\x3c\xfc\x1a\x5c\xe2\xd1\x7d\x10\x5c\xdc\xe4\x60\x5c\x5d\x88\x4b\x1a\xcc\x3e\x0f\x42\xec\xb0\xb0\x11\xb5\x74\xfc\x23\x7f\x99\xac\x48\xe1\x83\xe6\xec\xaf\x45\xa6\x4e\x40\xfb\xfe\x2b\x0b\xea\x34\xb0\x56\x33\x00\x50\x7f\x38\xe8\xa3\x46\xfd\x26\xf5\xf6\x13\x4f\x04\xbf\x39\x3c\x0b\x23\x2a\x76\xd2\x5b\x58\x83\x12\x05\xbf\x71\x77\xd8\xe7\x5d\x30\x0e\x36\xf2\x37\xfc\xcc\xb0\xba\xd4\xb7\x39\xf9\x98\x1b\x39\x20\xc9\xee\x39\x3d\x3f\xbd\x4e\x6d\xb1\xa5\xaa\x8e\xf5\x3e\x85\xed\x6e\x85\xed\xc3\xd6\x44\xbf\x72\x14\x91\xed\x50\x60\xdc\x97\x2a\x65\x28\xb7\x26\x4f\x6e\xe9\xaf\xf8\xe4\x26\xe5\xeb\x84\x19\x5f\xd4\x0c\xd2\x0d\x33\x7f\xa3\x35\x4f\x2f\x70\x87\x1e\x57\x59\xec\x3d\xf7\x28\x6f\x2d\x15\xd6\xd3\x67\x47\x91\xab\x34\x78\xb7\xa8\xc0\x3e\x4c\xe6\x37\xd2\xab\x49\xc5\xc2\xda\x4b\x1d\x7f\xa2\xf0\xb3\x0b\xd7\xb7\x8c\x99\xdb\xa1\x0c\xe4\x1b\x74\x74\x26\x2d\x36\x0e\xe1\x1d\x38\x82\x48\x36\xa9\xf4\xe4\x83\x11\x71\x5a\xa0\x11\xb1\x71\x71\xf6\xeb\x70\x22\x19\x24\x6e\x42\x0d\xe1\x07\x02\x96\xa8\xaa\xd3\xcc\xe9\x04\x25\x27\x0d\xa9\x0a\xff\x74\x3d\x18\xc5\xf6\x30\x7e\xed\x94\xaa\xaa\xfe\xfc\x9f\xf3\x3d\xce\x3f\x98\x21\x31\x7c\xfe\x62\x48\x90\xfb\x01\x41\xb4\x67\x86\x71\xf6\x85\xc6\xd7\x9d\x17\x58\xb5\x90\x99\xbe\x3a\x99\x1e\x03\x69\x61\xa7\xa2\xb8\x99\x14\xa0\x2d\x80\x66\x62\x92\x86\x37\x80\x96\xbb\x7c\x80\x71\xdc\xf2\x14\x59\x08\x54\xa6\x93\xaa\x8f\x3a\xdb\x52\x83\x4d\x83\x22\x76\xa9\x82\xa4\xa2\xd4\x02\xa8\xfe\xe1\xad\xd5\x3d\x9d\x47\x34\xcd\xa3\x28\x8a\x0c\x00\x3e\x7c\x65\x31\xb7\x34\x03\x20\x35\xa4\xcf\xb1\x36\x76\x9c\xdf\xad\x92\x34\x2a\xc3\x21\x01\x70\x7c\x80\x99\x4a\x48\x0c\x1f\x92\x1b\xa8\x38\x83\x2c\x52\x17\x08\x5c\x18\xe2\xdf\x86\xfa\xc6\x0d\x98\xad\x4b\x92\x9f\x23\xac\x5b\x0c\x2d\x96\x33\x6b\xcc\xcb\x77\x3d\x60\x0a\x21\xce\xdb\x94\xe7\x08\x37\xc6\x36\xcb\x6e\xc4\xbd\xb2\x8e\xd2\x99\xc6\xf1\xa0\x31\x2b\xa5\x66\x0d\x85\x21\x0e\x11\x3d\xa7\xae\x85\xf5\xae\x86\xf7\xbf\xe0\x9b\x58\xa5\xb4\x43\x67\x99\x32\x05\x76\x58\xcf\x61\xfa\xd5\xdc\x63\xf1\xf8\xf9\x3c\xa9\x86\x82\x0d\xd8\x77\x32\x6b\x5c\xd8\xd8\x58\xb6\x68\x39\xf5\xd4\x2c\x32\xce\x4c\x28\x12\xc0\x47\x4a\x8e\x48\x6d\xef\x5a\xec\x12\x95\xfb\x8c\x1d\x5e\x75\x6c\x48\x55\xb4\x71\xcf\xf4\x78\xd7\x52\xcc\x5d\xec\x07\x4c\xe4\x0f\xef\x37\xca\xd4\x1f\xa0\x55\xab\xb6\x2e\xc5\x1f\x2f\x84\xc4\xf5\xe3\x39\x32\x3f\x62\x82\x19\x48\x0f\x00\x5e\xee\xd4\x75\xab\x65\x2c\xf0\xc9\x24\x52\xcc\x7c\xd1\x7a\x88\x28\xe5\x2a\x57\x94\x1e\xc1\xbd\x68\x78\x06\xc5\xe2\x98\xbb\xb8\x46\xaf\x27\xfe\x76\xa1\x2f\xb0\x45\x1c\x7b\x78\x5d\x37\xf7\x9a\xdc\x87\x26\x0a\x86\x7c\x98\x4f\x80\xed\xd5\x79\xcd\x38\x4e\xe9\x5d\xbb\xef\x7a\x22\xa9\xcb\x92\x4a\x59\xfe\x22\x13\x1c\x78\x44\xf8\xb9\xc2\xf3\x35\xb0\xe6\xda\xbd\x80\xdb\x51\xd5\x45\xdb\x81\x45\x05\xf7\x3c\xa7\x61\x5c\x7f\xc7\xf9\x02\x9e\x04\xa5\x31\x29\x6e\x70\x0d\xed\x65\x9b\x0c\x1e\x36\xd3\xf0\xcd\x8d\x1b\x3a\x68\x83\x8a\x1e\xe6\xbb\x1b\x31\xa0\x5b\xdc\x64\x50\xf1\xa0\x63\xaf\x81\xb7\x07\x8d\xd3\xce\x96\x81\x74\x8d\x6a\xba\x20\x34\x35\xe1\x98\xde\xc8\x48\x66\x44\x23\xa5\xe8\x8b\x73\x52\x9e\x3a\x60\x8e\xb1\x85\xeb\x33\x63\xce\xbc\x24\x21\xb0\x8c\x16\x75\x5f\xf7\x91\x5b\xc6\x2a\x86\x51\xe6\x37\x27\xc2\xfa\x68\x55\x3f\x80\x37\x05\x99\x3b\x69\x7a\xcb\x4b\xf4\x23\x5b\x30\xc3\x32\xce\x0d\x7e\xfd\x1a\x88\xbd\x7a\x5d\x06\x7e\x61\x8a\xd4\x41\x82\xa7\xce\xb5\x0a\x7a\x77\xf0\xa8\xe8\x44\xee\xfa\xcd\x11\x35\x89\xd5\x12\xfc\xe5\x74\xb1\x8e\x61\xa9\x7d\xc4\x6d\x9c\x05\x73\xf9\x4a\x63\x04\x97\x83\x74\x22\x36\xe6\xe8\xcf\x10\xa5\xb6\xb1\xbd\x8e\x05\xdb\x06\x1d\x51\x8b\xd4\x4c\xe5\xd9\xdf\x4e\x86\xdd\x9b\xaa\x2e\xcb\x18\x21\x79\x63\xf3\x54\x8d\x86\x58\x0e\xce\x6f\x45\xf4\xa3\x8e\x36\xe7\xb6\x5e\x34\x57\x50\x41\x05\xb2\x96\x52\x09\xf4\xef\x2b\x27\xd2\x61\xfe\x83\xc9\x89\xf8\x2f\x67\x14\xc0\x67\xf5\x7a\x3e\x02\x3f\xc8\x49\x45\x3e\x74\x2e\xf0\xb5\xef\x32\xc6\xe6\xb3\x46\x25\xbc\xc8\xc4\x1e\x77\x42\x79\x89\xe3\xa4\x8c\x8f\xc0\xb4\x42\x9e\x05\xda\xc7\xc1\x41\x7c\xe5\x73\x74\xbc\x6e\xaa\x80\xd2\xf6\x27\xc1\x59\x43\x0d\xb0\x25\x3c\xc3\x22\x83\x09\xf3\xf0\x8b\x3c\x41\xd2\x2a\x13\xf0\x82\x04\x9f\x02\x03\x73\x62\x6c\xf4\xb8\xae\xf8\x7b\x54\xa9\x32\x75\xd7\x01\x9b\x53\x46\xd4\x63\xae\xab\xd8\x67\x01\xfc\xa7\x76\xbd\xc4\xc5\xf9\x09\x8e\x25\xa5\x30\xcd\x20\x54\x42\xbb\x2e\x5e\x84\xf9\x3c\xf7\xa0\x83\x56\x9e\xed\xa1\xe7\xb0\xd5\xee\xa3\xe6\x83\xb2\x67\x84\x64\xdd\x83\x16\x9f\x1b\xe3\x7a\x8d\x4d\xc4\x34\x7d\xdb\x90\xcb\xa6\x63\x13\x31\xc3\x2a\x30\xc9\xb4\x1d\xd6\x32\x55\xd4\x9c\x37\x5e\x07\x43\x09\x0d\xce\xda\x41\xc7\xa9\x38\x10\xe5\x92\x44\xd1\x6e\x3c\xad\xde\xf4\x49\x8d\x1d\x54\x86\xc4\x9d\x97\x19\x6a\xa8\x3c\x4d\x11\x69\x08\xa0\x38\x93\x99\x19\x97\xd8\xca\xf2\x2c\x3f\x01\xa8\x55\xb8\x51\x29\x47\x79\x91\x2c\xc4\xda\x22\x1f\x06\xc9\xeb\x5d\x4d\xf3\x08\x56\x4b\x93\xe9\xd6\xfa\x6a\x9b\x28\xef\x74\xea\x1c\x68\x61\xd5\xfd\x28\xb5\x08\x67\xe7\x53\x84\x05\x9c\xd1\x07\xcd\x59\x5f\x91\x19\x98\x53\x4b\xc4\xc3\x15\xec\x84\x2b\x6b\xe4\xd3\x33\x6e\xd0\x50\xf3\x31\xb4\xa9\x0a\x31\xa8\x62\x1d\x3d\x72\x1a\xd6\xac\x93\x4a\xbe\x75\x86\xb6\xe6\xec\xc9\x65\x5c\x4b\x6f\xed\x5e\x61\xae\xdc\x4d\x8d\xaa\x25\x53\xa7\x7f\x6d\x38\x1b\xe3\x74\xf9\xd2\xfa\x93\x2d\x22\x11\xa6\x92\x6a\xc3\xa5\xfe\x5e\x06\x98\x6f\xb7\x73\x1d\x10\xd3\x30\xca\xf6\xdd\x4e\x58\xbb\x68\x85\x56\x58\x19\x3b\x6e\xb8\x0a\xa3\x74\xf9\x16\x7b\xf6\x62\xe6\x64\xd8\xf2\x27\xe3\x1c\x68\x24\xe9\x5b\x0c\x08\x1a\x78\x4f\x3e\x62\xd4\x18\x8e\xfb\x6c\xe3\x77\x45\x4b\x8b\x5c\x6f\x0b\x93\x49\x58\xd7\xd2\xab\xfa\x46\xb1\xa3\x7f\x82\xee\xbd\x75\xdf\xb3\x60\x5b\xb7\x6a\xad\x14\x8c\x0f\x1e\xd1\x0b\xbb\x36\xb7\x39\x0e\x78\xb3\xa8\xab\x9d\xc2\x01\x8c\xf0\xa5\x80\x66\xde\xd7\x59\xa5\x8a\x82\xb2\x95\xa8\xb9\x87\x41\x10\xdd\x1d\x9d\xc1\x53\x69\xcd\xdf\xd0\x43\xee\x6d\xa3\xbd\x2b\x80\xde\xcc\x5a\xf4\x7b\xa4\x3c\xe4\x1e\xde\x65\x83\x81\xa2\x84\xfa\x54\x9d\xd1\x50\xc3\x5d\xd3\x49\x0f\x15\xdd\xb4\x76\x9f\x26\x03\x3b\x51\x63\x0c\x5b\xbf\x1f\x58\xfd\x2c\x0e\xe5\x7f\x62\x2b\xfd\xba\xb5\xdc\xc2\xbc\x58\x03\xf0\xbe\x3d\xc6\xe8\x24\x0d\xb9\x7e\xbc\x5b\xff\xca\x0c\x03\x68\xb6\xeb\x7a\xda\x8a\x7a\xf9\x06\xa9\x9f\xdd\x03\x0f\x43\xbb\xe5\x75\x48\xbf\x2f\x19\x86\xce\x3a\xd2\x8e\x33\x1f\xa9\x48\x95\xa9\x6a\x3f\x7e\xfd\x19\xc1\xd7\xb9\x60\x6a\xa7\x26\xf6\x93\xa2\x84\x5e\x5e\x5e\x44\xd3\xde\xa6\x35\xc1\x8a\x5a\x9e\xf2\x7b\x3a\x24\x7f\xb0\xd3\xcb\xec\xfe\x4b\x7c\xae\xfb\xac\x3f\x4f\x2f\x87\x78\xec\xaa\x49\x61\x13\xf1\xcb\x16\xf5\xa1\xb8\x49\x5f\x2b\xb1\xe3\xc5\x0c\x8e\x27\x90\x74\x85\x9b\x09\x5a\x23\x20\xe8\x00\x05\xd4\xfb\x03\x69\xdf\x88\x5d\x61\x99\xf0\x7c\x4d\x0e\x20\x21\x83\xea\xd9\x9a\x1d\x87\x30\x08\x7d\x35\x28\x7d\x9b\x8f\xd3\xf7\xc9\x48\x1f\x3b\x70\x1c\xe1\x02\xbb\xa1\xc0\xb6\x05\xfd\x34\xc1\x0b\x0f\x9c\x17\x6b\xd3\x06\xa4\xbe\x77\x69\xe2\x14\x12\xcc\x08\xb7\x2a\xec\xa8\x07\x58\x0e\x93\x26\x91\x00\x32\xff\xc1\xfa\xa3\xb4\xc9\xe9\x13\xf3\xce\x7e\x99\x75\x17\x48\x5b\x90\xae\x31\x50\x7c\x79\xf3\xde\x8e\x23\xe5\x05\x7c\x80\x5c\xe6\x84\x2d\xb4\x6f\xcc\xa9\x0c\x8f\xf7\x2c\x8e\x7e\xdf\x9d\x25\x80\xbd\x4b\x02\xc4\x76\x61\xa1\x7a\x5a\x67\x47\x83\xc7\xd6\x23\x29\x40\x78\xf4\xab\xed\xdd\xfe\x36\x14\xdd\x4d\xa8\xd8\x92\x5e\xce\x92\xdb\xea\xca\xa7\x81\x7a\xb5\xb7\x0c\xcd\x8c\xc0\xba\x74\x34\xe8\xed\x62\x14\xb7\x67\xe1\x70\x5d\x2c\x5b\xd7\xee\xba\x41\x51\x98\xab\x18\xd4\x13\x98\xba\x32\xe7\x01\x61\xb0\xb9\x62\xa4\xaf\xe7\xdd\x96\x4a\x4b\x1b\x39\x4b\x25\xe2\xf2\x87\xa0\x17\xbb\x4e\xc9\xea\x0a\x36\xf0\x10\xe8\x17\x0b\x39\xe3\xe1\x08\xae\x08\x47\xea\x33\xcf\x97\x1a\xf9\xb9\x68\x10\xae\x50\xbf\xcc\x22\xca\xc5\xe8\x17\x1a\xeb\xed\xa5\x67\x57\xfc\x7a\x64\x37\xc6\xb3\xaa\xcd\xab\x8c\x87\xe6\x08\x43\x7c\x48\x53\x7a\xf1\x4c\x66\x45\x17\xfc\x58\x1b\xb9\xcc\xd6\x2e\x1a\xf9\x53\xef\x22\x4f\xdb\x01\x67\x09\x8b\xa5\x38\x05\xa7\x51\xe4\x81\xfa\xa9\x96\xa8\x17\x25\xdb\xb4\x62\x5e\xed\x3e\x29\x62\xef\xd3\x13\x67\x91\x10\x04\x94\xb6\xe0\xba\x51\x98\xb5\x7d\x16\x7e\xe1\x0a\x00\x36\x04\x9f\x31\xed\x7d\xfb\xb3\xf8\x34\xbc\x6d\x24\x24\x23\x4a\x1f\x3e\x5d\x1d\xba\x58\xd6\xf6\xe6\x97\x26\x93\xac\x9d\x04\x23\x87\x93\xf4\x39\xf9\x6e\xc4\xa5\xd0\x33\x75\x9e\x65\x0a\x93\x44\x93\xa7\x13\xed\x77\x36\x9d\x60\x25\x13\x85\x26\xb5\xde\x06\xaa\x57\x25\x74\x9f\xa6\x99\x4b\x15\xcd\xd3\xa4\x31\x89\x39\x0a\x35\x9f\x16\xfa\x5d\xa3\x01\xd9\xfc\x07\xd3\xb4\xa5\xf2\x97\xfd\xb4\x51\x26\x0f\xf1\x1e\x38\xc4\x70\x50\x2d\x73\x18\x02\x96\xcc\x09\x79\xd2\xfb\x5b\x5f\x93\xdf\x9e\x36\xac\xc4\x50\x05\xfa\x2a\x4f\xe9\xbc\x5c\x50\xd0\xc9\x02\xf4\x40\xdd\x18\x99\xe1\xca\x5a\x32\xe0\x20\x9a\xe5\xc5\xaa\x96\xbb\xd4\x83\xd2\x24\xe1\xf7\xba\x40\x0c\x57\x81\xe2\xc0\x87\xf1\x05\x21\x94\x78\xc7\xc9\xa2\x00\x53\x8a\x40\x90\x47\xa4\xaf\x4a\x4f\xb5\x0f\x0c\x96\x2f\x90\xbc\xe9\x48\x9b\x11\xfc\x5d\x77\x22\x2e\x97\x97\x52\xf4\x35\x8a\x01\x05\x05\x0b\x78\x36\x84\xb6\xc9\x1a\xfb\x0c\xfb\x6a\xc6\xc4\x57\x9a\xc6\xb0\x83\x27\xdc\x21\x7d\xbc\x03\xdd\x96\x59\x75\xf0\x16\x69\x54\xd7\x9e\xc2\x70\xcc\x98\x6c\xbb\x9b\xe0\x80\x63\x61\x3d\x84\x1e\x9e\xcf\x23\x47\xcd\xcb\x20\x38\xdd\xb3\x4e\x77\x95\x6d\xc0\xd9\xe8\x71\xa0\xd0\xa3\xf7\xe0\x06\x84\x57\x5b\x04\x6e\x6d\x59\x68\x8c\x5b\x5f\x67\x74\xba\xe8\xe9\x32\x2e\x4c\x36\x13\xed\x87\xf2\x34\x62\xd7\x11\xa8\x85\x74\x39\x86\x17\xcc\xf4\x8b\xa5\xc6\xc2\x56\x3d\xcb\xb2\xb7\x0a\xb9\xe7\x19\x3f\xb2\x8f\xb2\xf2\x9d\x56\x33\x0b\xa0\xd5\x00\x9a\xde\x20\xb0\x32\x4f\x36\x8a\xf9\xe8\x3c\x58\x90\xda\x34\x52\x2d\x2a\x9d\x8f\x14\x69\xad\xea\x5c\x36\xeb\xf0\x5e\x55\x52\xc0\x07\x1b\x84\xf4\x26\x2d\x07\x67\x63\x45\x7f\x15\xca\xe9\x19\xf6\x0a\x91\x52\xe1\x34\x11\x35\x43\xe2\xe9\xb2\xab\x1b\xac\x41\xd9\x67\xbe\x0e\x12\xa2\xfa\xe4\xe7\xb7\x77\xae\xf6\x2a\xfa\x22\x7d\x89\x9d\x0e\xb5\xa9\xaf\xa1\x19\x14\xee\x82\x2a\xf9\x55\x85\x03\x4e\x10\xf9\x4a\x6d\xef\xf2\xdb\x16\x55\x08\xf5\x9c\x9b\x81\x75\xf1\x3d\x04\x8a\x02\x25\x91\xdf\xfa\x4c\x0d\xaf\x67\x4a\xde\xe0\xcb\xe5\x3d\xbb\xe2\x00\x37\x29\xd5\xca\xbc\xb9\x0c\xb9\xd4\x1a\x19\xf8\x53\xc1\xef\xf6\xea\x7d\xa2\xea\x08\x77\x62\x06\xf3\xa6\xc7\x13\x1f\xef\xf0\x61\x3e\xb8\x87\x7e\xdf\x17\x2e\x91\x4c\x30\x6e\x48\x5c\x3e\xb0\x40\x65\xef\x3e\xf3\xf7\x98\x6d\x4b\x34\x25\xd2\xec\xc8\xea\x7e\x43\xaf\x92\xfb\xb2\x30\x4b\x16\x3e\x3f\x30\x35\x1c\xdf\xee\x73\xb8\x5f\x12\xa6\x26\x10\x77\x24\x7e\xac\x49\x48\x12\x12\x1e\xff\xb6\x83\x36\x06\xb7\xa7\x3c\x1f\xed\x71\xfb\x9d\x41\x3a\x92\x61\x2a\xa6\xe0\x0b\xcb\x6d\x02\x7b\xeb\x7e\x67\x6b\x37\xdb\xb6\x3f\xd6\x1e\xec\x7e\xe3\x15\x77\xfb\xe9\xf5\xbc\x05\x1e\x18\x37\xb1\x5a\x0f\xda\xb4\xaa\xaa\xde\x19\x0c\xf2\xdd\x46\xe3\x6e\xed\xd9\x81\x68\xe7\xcf\x4b\x27\xa1\xb6\x7f\xf0\x6c\x12\x58\xd8\xdc\xa6\x96\x4f\x74\x35\xde\xd9\x45\x48\xdc\x5c\x1c\xda\xd4\x81\x58\x11\x61\x1e\xe0\x2c\x1a\xc4\x30\x18\x47\x0c\x1d\x8f\x38\xde\xef\x13\x13\xe4\x8b\xbc\xb6\x80\x9f\x36\x1e\x9d\xe1\xfb\x9a\xab\xee\xb1\x4f\x89\x93\x29\x43\xbd\x06\xe0\x97\xb3\x6d\x8c\x58\xdd\x19\x79\x69\x9a\x21\x08\xf7\x12\xd8\x97\x8d\xd6\xe4\xef\x1e\x62\xc3\x17\x6e\x35\x51\x84\x56\x55\xe3\xbf\x32\x4f\xf6\x4d\x30\xe7\xef\x65\x12\xd2\xb9\x28\xcb\xd1\x0e\xe7\x91\x0b\x1e\x9a\x0a\x11\x19\x74\x1f\x21\xde\x0c\x66\x57\xe7\x39\x27\x23\x96\xfb\x1e\x04\xc1\xc6\xc5\x99\x23\x55\xd9\x97\xae\x27\x64\x5e\x6d\x42\x85\xa9\x35\x69\x23\xdb\xd4\xda\x3a\xcc\x5c\x5d\x74\x59\xa0\xb9\x9f\xf9\x78\x5e\xef\xc5\x8c\x9a\x12\x36\x6c\x4f\x2f\x46\xda\xfa\x16\x4f\xca\xaf\x99\x4b\x62\x42\xd4\x48\x20\xfb\x98\x74\x49\xa0\x95\x91\xb2\xf0\xa9\xd7\xef\xd6\xd8\xb5\x59\xcf\x2c\x5e\x58\x9e\x0e\xf0\xf4\x67\x56\x5e\x59\xe3\xc7\xd6\x76\x0e\x65\x6b\x0f\x42\x57\x96\xcd\x63\x1d\xbb\x68\x70\x6e\x46\x9e\x70\xc9\x72\xb1\x97\x62\x70\xd5\xcc\xe4\xb5\x02\x91\x1d\x49\x00\x8f\x02\x74\xa6\x3b\x3e\x80\x9c\xf6\xf5\xde\x64\x0c\x7a\x36\x01\xb5\x2a\xb3\xa1\xfe\x5b\x4e\xa7\xcb\x37\x78\x9f\xc9\xdd\x5b\x6c\xa3\x0e\xda\xa4\xdd\x7f\x21\xf9\x2b\xce\x48\x8d\x72\xd2\xc4\x6d\x3c\x16\xd9\xa7\xf5\x34\x6a\x63\x3b\xfa\xdb\x74\x36\x6d\x38\x70\x30\x2d\x53\x1c\x1c\xe8\x47\x25\xec\xeb\xed\x0d\x83\xf6\x39\x5d\xd7\xa5\x5a\x16\x4f\xa1\xb7\x6f\x45\x58\xd5\x28\x80\x8a\x19\x92\xa3\x8a\x45\x1c\xae\x46\xd3\x4f\xef\x2a\xed\xb7\xe4\xbf\xdb\x9a\xbc\x06\xad\xd3\x17\x4e\x42\x83\x79\x04\x00\xd9\x0b\xe3\xf4\x31\xd1\x90\x6b\x2a\xbb\x36\x9a\xcb\xa2\x1f\x45\x25\xdc\x74\xfb\x3a\xa0\x99\xd0\x44\xd5\xd0\x32\x5d\x47\x2f\xfc\xd8\x15\x23\x97\x9b\x4f\x93\x97\x5c\xec\xa6\x88\x0b\xf4\x52\xe7\xdf\x95\xc5\x0e\xa8\x04\x5c\xef\x91\xaa\x47\x77\x39\xce\x9d\xf8\x1d\x2c\x77\x6b\xe3\xcf\x00\xe5\x4d\x11\x33\xe2\x6c\x3d\x2f\x68\xe8\x9b\x21\x59\xdd\xb0\x33\xcb\x39\x34\xb3\x6f\x6f\x4d\xe2\xde\xd2\x6c\x35\xaf\x8f\x15\x6e\xe6\x77\x97\xc0\xf1\xb4\xc3\x85\x51\xe6\x49\x95\xf4\x57\xfc\x76\x5f\x06\x32\xf2\x7e\x23\xb4\xef\x43\x47\xea\xec\x2d\x9f\x7c\xff\x34\xc7\xc9\x10\xa5\xcd\xcd\x54\xb7\x52\xdc\xe7\x36\x84\xab\x9b\xa7\x6e\x0b\x8f\x6d\x08\x93\x38\x10\x46\x28\x9b\x7c\x92\x5a\xc1\x14\x07\xe9\xea\xa2\x3b\x8f\xff\x26\x56\x62\xdf\xdb\xf5\xbb\xea\xdf\x3c\xd9\xff\x58\x7b\xbf\xf4\xff\x45\xff\xea\x1e\xf4\x31\xf9\x0f\xef\x99\x05\xf8\x4d\xa0\x63\xde\x87\x9e\x76\x2a\x44\x9f\x9a\xb8\x62\x69\xa4\xb6\x48\x53\xa2\xdb\x74\xb9\x36\x87\x62\x11\x80\x35\xc9\xe0\x13\x80\x00\xe3\xd8\xc5\x13\x79\xe6\x25\xa3\x16\xed\x77\x74\xe5\xf1\x95\x9c\xfa\x72\xf5\x11\xe2\x14\x9e\x7b\x2c\x45\xde\x13\xce\x24\xa6\xdd\x12\xd7\x35\x12\xa0\xa0\x48\xca\x28\xcb\x4c\x2c\x54\x5c\xab\xdd\xe2\x14\x4e\xc0\x50\xa6\x58\x32\x25\xa3\x5c\x5f\x70\xeb\x49\x5c\x9d\x83\xb2\xbe\x47\xad\x20\xfa\x50\xfb\x80\xd3\x17\xd4\x9d\x78\x99\x46\x23\xf4\xc0\x0e\xa2\x69\xbc\x2f\xbf\x35\x2f\xc8\x6b\x4f\x6f\x26\x6c\xea\x8f\xb9\xaf\x1f\x7a\xcb\xb4\xf9\xa9\xb0\x39\xdd\x65\x89\x5f\xeb\xa5\x78\x51\x20\xb9\x86\x0c\xc5\x46\x99\x14\xf8\xf3\xfa\x26\x8d\x75\x30\xd2\xe2\x66\xce\xad\xb7\x4a\x3d\x84\x10\x68\x6c\xf3\xe7\x5e\x49\x82\x14\xee\x80\x7f\x2f\xbd\x19\x6f\xfa\xe5\x69\xf4\x16\xe4\x79\x34\xda\x22\x97\x5c\x75\x8e\xd2\x3b\x40\x3d\x98\x35\xd1\x96\x3c\x82\x7b\xf0\xd4\xad\xaa\x75\xb6\x12\x64\x78\x10\x0a\xca\xaa\xa4\xb8\x85\x98\x04\x7d\x6a\x41\x00\xd4\x53\x54\xdc\x49\xb6\xb5\xc3\x64\xc1\xa2\x1c\x5b\x0e\x07\x60\xfc\x62\x3e\xda\x02\xde\x55\xea\xb0\x4c\xa8\x16\x81\x22\x82\x86\x9b\x77\x0f\x99\x05\x6e\xee\x22\x2c\x65\x0f\x81\x23\x76\x70\xc8\x6a\x7d\x30\xa1\xb7\xfb\x4d\xcb\x2f\xb6\xd4\x84\x39\x87\x3a\x01\x8b\x6d\x5c\x48\x3b\x54\xcd\x0b\x65\xa5\x83\x84\x5e\xb5\x98\x02\xdf\xd9\x03\xd7\x82\xb3\x88\x3a\x0b\x7c\x3f\xbc\xcf\xd0\x90\xee\x97\xb5\xa6\xd9\xe2\xd5\x50\xe5\x53\x0d\x9f\x3e\xb1\x9c\x3d\x80\xc6\x62\x15\x0e\x73\x11\xfc\x6e\x52\xc1\x42\x25\x8d\xbe\x63\x2e\xaf\x92\xd1\x9e\x15\x1c\xa6\xb4\x65\x3b\xe5\x76\x3c\x54\x78\xb3\xf0\xf2\x36\xa0\x84\x31\x38\x88\x93\x01\x44\x6f\x62\x17\x40\xea\xa3\x98\x8c\x96\x72\x06\x54\x56\x88\x12\x82\xac\xa7\x93\x9f\x06\x4a\x39\x3c\x50\x0b\xbc\xa5\x16\xc3\x54\x10\x5e\xcf\x04\x68\x77\xbe\x9b\x40\xe3\x15\x9e\xf4\x4b\x00\xf8\x7b\xcc\x78\x1a\x41\xfa\x7b\x07\x18\xcb\x58\x10\x1e\xb5\x6e\xd8\x62\x58\x6c\xeb\xd4\x85\x22\x30\x85\x20\x0b\x46\xe9\x1f\xad\xe3\x45\x07\xb2\xca\x19\x7a\x2c\x77\x70\x12\x78\x46\xd3\x17\x7b\xa5\xa7\x9d\x22\x4e\x15\xdd\xd6\xef\xab\x83\xf3\xa1\xfa\x63\xed\xc3\x91\xfa\x6d\x88\x7b\xfd\x75\x1f\x52\x7d\xd7\xa1\xc4\x13\xb8\xce\xce\x0e\xfb\xb7\x16\x9c\xe0\x9e\x36\x98\x0f\xfd\xda\xd9\xec\x2c\xd9\x8e\x3b\xf2\x21\xcc\x27\xad\x12\xe5\x2a\x0e\xa4\x4f\x56\xc5\x78\xff\x33\x09\x32\xd1\x78\xcc\x32\xb0\xdf\x9c\x3b\xe7\x79\x81\x87\xc0\x71\x5e\xfe\x7d\x90\xd3\x34\x66\x41\x58\x80\x83\xfb\x96\x36\x88\x8c\xe3\x79\x14\x61\x11\x79\xd5\xca\x04\xd2\x07\xa4\xc0\x2f\x4f\x74\x18\xa3\xda\xe3\x61\x67\xa5\x00\x2f\xf9\x38\x28\x0b\xc5\x15\x02\xb5\x5b\x00\xdc\x6c\x87\xbe\xdd\xa1\x18\x48\x35\x98\x7c\x06\xde\xdf\x4c\xc5\x91\xb1\xd2\xf1\x10\xc3\xe4\x5b\x98\xfa\xc8\x72\xff\x45\x29\x3b\x7c\x21\x75\x79\x79\xab\x95\x8b\xd8\x01\x35\x2c\x02\x91\xcb\x14\x6b\xee\x96\x75\xb0\x01\x69\xa2\x8c\x83\xca\x17\xa1\x1d\xe3\x13\x11\x8a\xbd\x04\x52\x44\x9d\xac\x4e\x73\x8d\x07\x6d\xc7\x48\x2b\xba\x4e\xea\x33\x94\xf4\xc2\xca\x3c\xb4\xd1\x4b\x75\x0c\x8c\x20\xbb\xa2\xf5\xce\x5e\x54\x1f\x02\xa4\x96\x76\x42\x5c\x09\xf7\x84\x61\x38\xf5\xb3\xbf\x6e\x35\x08\xed\x95\xa3\x71\x2b\x26\x03\x97\x17\x4f\x1f\x4f\x62\x9d\x8e\x2e\x9b\xcc\x7c\x23\xbc\x3d\x04\x67\x48\x6d\x73\x65\xc1\xe4\x6d\x17\xa0\xec\x32\x03\x82\x2a\x7a\x99\x3c\x82\x81\x78\x57\xed\xca\x20\x3d\x58\xb7\x75\xa3\x62\xc1\x26\xde\xa1\x93\xa3\xb8\x33\xd7\xc9\x42\x20\xa6\xd9\x40\x18\xa0\xc8\x72\xb4\x58\xad\xa5\x7c\xc5\x09\x00\xbc\x02\xa8\x80\xf2\xaa\x8d\x26\x64\x63\xf9\x30\x7c\xd2\x68\x67\x38\xdf\x91\xb4\x19\x2e\x36\x44\x9e\x37\x59\x73\x60\x34\x43\xe1\xbe\x63\x2a\x9c\x7b\xed\xb6\xb2\x5f\x96\x8b\xc1\x7b\x85\xc4\xaf\xad\x5c\x57\xd4\x04\xd5\xbb\x03\x75\xa4\x27\x57\x5f\x1c\x90\x8f\x5c\x69\xe7\x02\x9d\xd7\xac\x46\x46\xc8\xa2\x42\xbf\x38\x69\x83\x56\xd2\x7d\x18\xba\xbf\x91\x7a\xa1\x1d\x53\x64\x14\x3b\x9c\x43\xe3\xc4\xc8\xbc\x7b\x91\x82\xae\xac\xc9\x18\xd0\xfa\x69\x31\xe2\x5b\xc5\x03\xa4\x4b\xe7\xcc\x0c\x2a\x6e\xe5\x5e\x5e\x81\x1c\x5d\x51\x99\xdd\xd5\x4d\xc6\x38\x5c\xa2\x2a\x79\x31\x7d\xd2\xfc\x1e\x6c\x98\xdb\x03\x8e\xf3\xee\x1e\xfb\x48\x31\x60\x49\xee\xb3\x71\x48\x98\x5b\x06\x85\x89\xe5\x09\xe1\x49\x21\x66\x74\xce\xac\x11\xc2\xd6\x0d\xd9\x5f\x06\x42\xe0\xa4\x15\x84\x84\x82\x2d\x9f\x30\x78\x7c\xe7\xae\x92\xb6\x31\x42\xed\x61\x44\xb8\x7e\x8f\xd5\x56\x7d\xaa\x1f\x76\x42\x76\xbe\x5d\xd7\x4e\xb8\x54\x7f\x9f\x76\x52\x01\xb8\x0a\xed\x4d\xe5\x31\x22\x96\x79\x78\xda\x3f\x50\xfc\x29\x5f\xc8\x2b\x50\x9a\xf1\x2f\xe4\xab\xb7\x63\xf0\x41\x57\x79\xac\xc9\xd6\x8d\x9e\x6b\x72\x2b\x84\x37\x84\xd9\xd0\xd1\x21\xfc\x96\x12\x65\x5a\x5e\x29\xf6\x2b\x7d\x31\xc6\x86\xc8\x64\xdf\xa6\xfb\xa1\x07\xb5\x1d\xbc\xb2\x6c\xae\xdd\x08\x88\x59\x94\x55\x72\xc0\x4f\x57\x1a\x03\xd0\xc2\x20\x08\x0a\xa2\xb2\x4e\x73\xbc\xd3\x2e\xe9\x28\xa5\x12\xf4\x3b\x47\xb6\xf2\xe9\x0f\x76\x2e\x35\xcf\x7f\x91\x1f\x04\x65\x0a\xfc\x4f\x3f\x1a\xa1\xce\xf8\x20\x88\x8a\xe0\xa6\x2e\x33\x21\x94\x61\x1c\x6f\x68\x78\x95\x75\xd8\x7b\x23\xf8\x06\x82\x14\x3a\x32\xe0\x6f\xef\xaa\x8f\xbe\x86\x00\xab\xd4\x89\x78\x4d\xb3\x63\x41\xb9\xbe\x0b\xfc\x96\x72\x36\x53\x35\x31\x6f\xc9\x02\x2a\x4b\x59\x05\xc0\x3b\x1c\x93\x45\x8c\x59\x5c\x3f\xea\x9f\x21\xa6\x00\x92\x22\x90\xb3\x2c\xc8\x2f\xef\x29\xf4\x5a\x3a\xdf\xfa\x35\x45\xc8\x97\xcb\x42\x6e\x38\xdb\xe1\xba\xeb\x93\x05\xfe\x8e\x7c\xc9\xb5\x16\x71\x27\x77\x0c\x58\x3c\x47\x32\x2f\x8f\xa3\x58\xe2\xeb\xf8\xc6\x4b\x87\x28\x77\x45\x34\xdf\x4c\x2e\x99\xb4\x0a\x39\x3c\x66\xc9\x03\x5b\xca\xf2\x0d\xc9\x62\x8a\x8a\x87\xbb\x59\x82\x38\x9e\x4a\xad\xb3\xe9\x98\xce\xca\xf7\xac\xf6\x23\xa1\x11\x03\x4f\xe7\xf7\xe0\x28\x60\x77\x5d\x0f\x7a\x75\x9f\x19\x44\x10\x60\x49\x5a\x8e\x6a\x52\x40\xf0\x0f\xa7\x81\x0f\x8f\x49\x23\xcd\xa9\x51\xef\xe7\x15\xae\x73\xf4\x10\x10\xd9\xf1\x62\x81\x78\x5c\x80\xb9\x05\x5c\x24\xd2\x67\xaa\x91\x3c\x2b\x78\x3b\xaa\x12\x20\x2d\xe5\xa0\x4c\x65\x04\xa3\x25\x77\x33\x72\xb0\x96\x63\xf1\x44\x54\x04\x69\x6b\x87\x5d\xf7\x8c\x03\x67\x73\x90\x8a\xa5\xb3\x97\x75\x79\xb1\xfc\xac\x42\xa3\xd7\xb2\x69\x70\x88\x9b\x96\x35\x8e\xc1\x6b\x66\xdd\x2d\x60\x54\xe5\x11\xd2\xe3\xd2\xa6\x95\x76\xa6\x45\x25\x30\x4b\xdf\x54\x82\x94\xa6\xe2\xcd\x4e\xa3\x1f\x7d\x6b\x78\x85\xf8\xae\x8b\xf5\xea\x9f\x86\xb8\x9e\x7a\xd2\xe3\xc5\xa8\x4f\x6b\xc3\x63\x68\x3a\xc3\x2a\xa7\x15\x9a\xb5\xa7\xa3\xe7\x2b\x4c\x32\xae\xd5\x58\x27\xb5\x83\x5e\x23\x82\x19\x6e\xf7\x67\x57\x80\x58\x0f\xef\xb4\xce\x52\xc2\x04\x60\xbe\xfc\x24\x42\xbd\xee\x6c\x0c\xa3\x5a\x61\xf0\xb5\xba\x7d\x98\xc4\x2c\x89\x0a\x27\xb1\x58\xd9\x0f\x8c\xd3\x8b\x2c\xba\x09\x62\xc1\xda\x3b\x6c\x70\xf4\xc9\x79\x79\x59\xdb\x99\xd5\x2d\xf9\xec\x6c\x58\x2c\xbd\xfc\xcb\x1a\xa6\x9a\xc2\x2f\x1a\x6a\x32\x2c\x67\x30\x62\xac\x8a\x29\x71\x65\x93\xcd\x53\x04\x7d\x39\xd9\x8d\xbe\x9a\x61\xc8\x85\xef\x6c\x01\x90\x5b\x2c\x40\x00\x5f\x27\xb8\xf1\x56\x41\xf7\x08\x5c\x83\xaf\x4f\x98\x65\x26\x9e\xd0\xce\x4c\xa6\xab\x13\x3a\x5a\xa8\x8a\x5f\xdd\xb0\xe0\xf2\xd4\x81\x5a\xa6\x83\xdf\x40\x27\xbd\xe5\x05\x0e\x06\xdd\x26\x6b\x00\xd7\x8a\x88\xd4\x0f\xf9\xca\x59\x71\x15\x47\x04\x98\xf6\x6e\xf3\x7a\xfe\xa6\xed\x9b\xe5\x58\xc0\x2c\x26\x83\xdf\x85\x2d\x7a\xba\x68\xbf\x52\x1b\x9c\xfa\x70\x5b\xc4\xde\x18\xc2\x47\x61\xbe\xb8\xd0\xb8\x39\xee\x3c\x94\x7d\x08\xa9\x34\x87\x84\xae\xeb\x8b\xc1\x41\x24\x29\x37\xc0\x34\x63\x86\x47\x1b\x44\xfb\x14\xb6\x58\x32\xd7\x2a\x90\x6c\x45\x0e\xe1\xc1\x69\xe8\x58\xe8\xe1\x5b\x09\x57\x7d\xc5\x2f\x50\x97\x44\x42\xe5\xd8\x73\x20\x31\xce\xb9\x66\xeb\x5b\x72\x44\x75\x44\xb1\x1a\x44\x84\x23\xda\x99\x91\xfc\xca\x17\xcf\x82\x2b\x89\x8e\x17\x65\x9b\x34\xe8\xf9\x8b\x8c\x61\x64\x88\xe3\xcd\xc5\x54\xbb\xe6\x77\x97\x31\xfb\xfd\xc7\x12\x32\x63\xfe\x6f\x8d\x14\xd7\x7c\x95\x0e\x7a\x80\xa0\xd6\x9d\x3d\x80\x97\xdc\x0f\x6e\xcf\xe7\x2d\x4f\x80\x64\x00\xe5\x35\xab\x61\x89\xfe\x45\xbf\xd4\x0b\xb9\x40\x2d\x52\xd7\x9a\xc7\xaa\x57\x69\xcb\xd1\xd7\x6b\xea\x24\xd5\x87\x55\x67\x17\xaa\x08\x7b\x8e\xda\x25\x1e\xca\xb2\x2f\xb0\x2f\xaf\xe6\xba\xd4\xbf\xe5\x79\x86\xa7\x69\x96\x65\x66\xa0\x89\xc7\x8f\x13\x55\x22\xfe\x8e\xe6\xee\x0c\x30\xa1\x51\x00\x25\x03\x1d\xe0\x37\xf5\xe7\x93\xa8\x49\xea\xeb\x7d\xda\x8f\xcb\xea\xa4\x44\x00\x77\x44\x5d\xca\x65\x4a\xb1\x9e\x1a\xad\x9d\xe4\x1a\x7d\xf2\x20\x5c\xb9\x93\xe2\x36\xae\x79\x93\x54\x07\x18\xbd\x9f\x83\x9a\x0b\x40\xae\x29\x9b\xb3\x01\x3a\xef\x63\x75\x28\x74\xb3\xfa\xcd\x38\x31\x15\x23\xec\x44\xdf\x18\x67\xb4\x85\xe4\x12\x4e\xca\x43\xa1\x33\xbf\x57\x42\x1a\x01\x43\xb5\xf2\x97\xd7\xa6\xde\xaa\x48\xda\x86\xf8\xca\x53\xc7\x8f\x29\xf7\x72\x30\x77\xde\x8e\x66\xe6\xf7\xee\x5c\xc3\xfb\xc0\xfb\xba\x91\x33\x85\xd9\x0d\x1d\xce\x4b\xf2\xee\xcb\x74\x90\x0b\xee\xa8\x96\xa2\x0c\xb1\xb3\x88\xd7\x36\xe5\xc2\x26\x2b\xdd\xa7\xcb\x1e\x2d\x3a\x09\xb9\x48\xca\x4c\xbb\x51\xc9\xfb\x76\x82\x80\xb6\x82\xcb\xdf\x7a\x0c\x31\x14\xb7\x96\x1c\x2a\x79\xfc\xb1\x45\x75\xb0\xa1\xa2\xc9\x2b\x15\x76\xf5\x0f\xb8\x33\x91\x2d\x1b\x05\x57\xcf\xfc\xd5\x3b\x08\x7a\x67\x4f\xd2\xe6\xd6\x8a\x78\x97\xe1\xc2\x7a\xaf\x18\x3c\x63\x1f\xe2\x57\x0a\x66\x8a\xb6\x6c\x3f\xe4\x4a\xab\x11\x7c\xd0\xc3\x44\xc6\x69\x2c\x6c\xc6\xc7\x8a\xe1\x13\xec\x45\xca\x46\xae\x59\xbc\xc2\x65\x9d\x63\x2e\x23\x9f\x24\xb3\x8b\x46\xc9\xf4\x9f\xfa\x0b\xed\x02\xc1\xa3\x96\x33\xaf\x14\xca\xf2\x86\xca\x6b\x65\xb9\x00\x0f\xc5\x2c\x00\xc7\x2a\xc4\x1a\x30\x93\x65\x31\x7e\x6a\xda\xb0\x81\x8b\xa8\xd1\x6f\x1a\xed\x28\xfa\xce\xc6\xa5\xb5\x0c\xd0\xd7\xc4\x64\x3f\x18\x93\x21\xa7\x3b\xef\x4e\x9f\x43\x8e\x76\x8e\xb8\x82\xa2\x4a\xa1\x88\x7e\x69\x5f\xef\x3a\x19\xff\x5e\xa6\x4e\xdd\xfc\x25\xf5\xd3\xc3\x89\xf4\xd0\x11\xb4\xea\x50\x2b\xed\x40\x82\x6a\xe4\x47\x95\x46\x05\x2d\x99\x07\x61\x98\xbc\x0e\xe8\x11\xb1\x20\xb5\xac\x2e\xae\x60\x49\x03\x8b\x84\x99\xf1\xcd\xc0\xf2\xce\x4b\x9d\x5b\x3b\xb0\xb8\xc0\x22\x7f\x9f\xfa\x3c\xdd\x81\xa1\xf3\x7c\xca\x7c\x7b\x91\x10\x61\x4d\xea\xe4\xc0\xf0\x65\x8e\xb9\x7a\x22\x00\x73\x74\xab\xb0\x2c\x1b\xb0\x4a\xa5\x68\xd0\xf8\xd3\x74\x64\x8b\x99\x31\xc5\xc3\xe1\x2d\x7a\x3f\x88\x88\x43\xd4\xab\x32\xe1\x39\x19\x7a\x1e\x8d\xf0\x5b\x0d\x44\x58\xc1\xba\xaf\x6b\x20\xca\x1f\xc8\x61\x56\x77\xdd\xc1\x55\x38\x7c\x7b\xf2\x04\x1b\x78\xce\x42\xd7\x24\x77\x35\x77\xf9\x2c\x0d\xb4\x78\xe1\xac\xf0\x3a\xc0\x1e\x9f\xcb\x2b\xe5\x47\x47\xdc\x5c\x4a\x08\x68\x1a\x1d\x72\xe9\x84\x41\x2a\x52\xd0\xdf\xf7\x80\xe1\xfa\x83\x39\x36\x93\xf0\x1b\x99\xb1\x9b\x3c\xcc\x7b\x66\x69\x54\x10\x84\xd7\x1c\xba\x5a\x35\x19\x54\x29\xeb\x5c\x9d\x5a\xa5\x02\x3c\x5d\x47\x9b\xb0\x8d\xb5\x85\xf7\x1c\x02\x1c\xae\x0f\xe9\x1e\xf2\x9b\xc4\x6a\x83\x4c\xa7\x3c\xfe\xd5\x26\x32\xea\x45\xf9\xb6\x79\x79\xab\xe5\xc5\xef\x81\xc1\xc2\x5b\x12\x7c\x05\x9f\x4d\x51\x6f\x3f\xe2\x23\x21\x28\x0c\x23\x88\xb5\x47\x04\x96\xe7\x31\xa6\x27\xa8\xd3\xcc\x31\x4d\x8a\x1a\xc3\x24\x32\xe9\x43\x7b\x41\x43\x62\xcf\x3e\x9c\x7d\xb2\x7d\x52\x85\xe2\xb1\xf5\x61\xc6\x5d\x42\x98\xf9\x30\xc1\x90\x6a\x88\xe9\xec\xfa\xe3\x68\x78\xf2\x4b\x39\x5c\x31\x27\xda\xcc\x66\x36\xcb\x2e\x09\xe8\x73\x6c\xa2\x1f\x72\xeb\x04\x26\x8c\x79\x73\x8f\x8f\x80\xc5\x4d\xec\x8b\x47\x35\xa1\xaa\x6f\x8d\x6c\x32\xac\x1d\x5e\x33\x98\xbb\x6d\x3f\xc9\x32\xe5\x2d\xa4\x73\xfd\x14\x35\xb2\xeb\xb8\x0d\x30\x48\x30\x15\x1c\x10\xed\x95\x14\xbb\xc5\xa6\x32\x05\x58\xf6\x2a\x3d\x4a\x6a\x03\x9b\x61\x9d\xac\x4e\x18\xdd\xe3\x04\x43\x55\x9e\x18\xdd\xeb\x31\x02\xd8\x77\xd4\x7b\x21\x06\x44\xb5\xb1\x68\xae\x85\x13\x82\x5e\x8e\xad\xd0\xe4\xb3\xd5\x4f\x4c\xd5\x13\x87\x39\xd0\x2d\xf0\x9b\x15\x40\x1a\xd2\x97\x7d\x35\x72\xd2\x07\xf2\xdc\x5c\xf0\xc8\x78\x3c\x48\x3a\x62\x24\xab\xf2\x0d\x85\xff\x62\x87\x11\x36\xa8\xb7\xe5\xc9\x75\x79\x90\xe0\x94\xb8\x9b\x38\xd3\x73\xe1\x9c\x7d\x1e\x9d\xd9\x55\x62\x30\x73\xea\x83\x0a\x64\x82\xb4\xf2\xc0\xae\x8b\xc0\x09\x23\xbe\xd6\xaa\x69\xa3\xbe\x38\xd6\xa7\xe1\xd2\x11\x12\x68\x59\xdb\x94\x99\x45\x6f\x8b\x5d\xd6\x5e\x06\x8a\xcb\x47\x57\xbf\x29\x53\x53\xa3\x4c\xeb\x5c\xcb\xcf\xf3\x94\xdd\x1b\x25\xb1\x7a\xb7\x97\xa2\xcb\x5e\x26\x38\x19\x4c\xe7\xa9\xdf\x0e\x5c\x04\x64\xe6\x22\x16\x57\xf7\x8e\xb4\xcb\xe0\x7d\x92\x64\x52\xd7\x25\xe7\x12\x86\xbb\x9e\x84\x0c\x3e\x03\x04\xb2\x26\x6b\x23\x9d\xf0\x10\x6c\x36\x0e\x81\x65\x7b\xca\x92\xd9\x8a\xe0\xa9\xbb\x3b\x9a\x6c\x61\x13\x1f\xed\x9a\x8a\x48\xa0\x60\x36\x7a\xfc\x91\x15\xe2\x99\x75\x57\x7b\x67\x4f\x6c\x9f\x60\x67\x27\x1d\x63\x55\xef\xc6\x5c\x78\x9e\x46\xcb\x2e\x72\x81\x41\x86\xd6\x7c\x2a\xbc\x46\xfa\x84\xb1\x7f\x58\xe6\xbc\xc9\xea\x72\xc1\xd6\x50\x36\xa5\xbb\x8d\x06\xcd\x34\xc1\xe3\xf4\x12\x75\x78\x90\x54\xc3\xfa\xd2\x6e\xb1\x8f\x69\xfb\x6c\x3a\x93\x58\x7c\xa9\x55\x1d\x6b\x26\x24\x8a\x7a\x32\x1c\x4d\x96\xcd\x72\x14\x8d\x6f\x28\xea\x7a\xf0\x25\x6e\xaf\xf4\xfb\x3c\xe2\xd2\x56\x47\x86\xb5\xc6\x24\x96\xab\x9c\x0f\xc1\xd5\x52\xc5\x59\x99\xec\x01\x61\xca\xdc\x23\xe7\x8e\x9f\xfb\xe3\x1d\x56\xa6\x50\xcd\x49\xf4\x98\x85\x15\x9f\x57\x13\xd7\x86\x82\x79\x4e\x11\xc6\x89\xae\xa4\x3d\x2b\x57\xfc\x4a\x53\x3f\xf4\x96\xe5\x43\x21\x00\xf4\x52\xc4\x88\x78\xca\xfe\x01\x72\xec\x33\x12\x89\x74\xf1\x22\x4d\x4b\xa1\x32\xd1\x47\xfc\xed\xdf\xdf\x33\xdc\x9e\xdf\x7f\xb4\xeb\xbf\xbf\xbd\xfb\xbf\xff\x62\x73\x44\x66\xf9\xd5\x87\x3d\x9f\x24\xb8\xe3\xbe\x83\x92\x26\xbe\x90\x25\x8c\x2f\xcc\xf4\x66\xf3\xd6\x2c\x5c\x11\x94\x1e\x88\xd4\x5a\xa3\xdb\x7e\x06\x3f\x07\xe8\x6f\x76\xb0\xc8\x62\x35\xf7\xb0\x3e\x38\x0f\x75\x81\xe0\xcb\x16\x90\xaa\x0f\xbc\xa7\x82\x32\x20\xc5\xf0\x84\xee\xd1\x8a\x59\x02\xa0\x5c\x77\x6d\x45\x5e\x6a\xe3\x88\x98\x46\x4e\x10\x87\x83\x13\xeb\xf5\x39\x59\x82\x2a\x3a\xa2\x8c\xf9\x77\x3e\x10\x3a\xf2\x16\x87\xda\x55\x4b\x8c\x4d\x6d\x4e\x10\x3f\x34\xa1\x43\x60\x07\x05\x24\x77\xca\xd0\x58\x64\x01\x0f\x25\xcd\x36\x2c\xed\xe4\x27\x3d\x73\x69\xd2\x37\x27\xd5\x54\xfe\x6b\x0f\xa7\x07\x07\xd9\x77\x74\x5b\x5b\xe0\x08\x5d\xfb\x04\xa2\x63\x2a\x92\x8c\x6f\x34\xaa\xda\x81\x4e\x07\x3e\x67\xde\x5a\x54\xdc\x48\xc3\x0e\xe5\x7c\xc8\xf5\xc7\xda\x04\xe7\xd1\x6f\xcb\x40\xc5\x33\x94\xa4\xcb\x50\xf0\x30\x70\x1e\x39\xeb\xc8\x13\x97\xac\x6d\x6c\xe9\x5b\xc8\x88\xd3\x6d\x61\xff\x62\x2a\x34\x11\x09\xd2\xcf\x19\xc9\x12\xd8\x0e\xc8\x53\x3f\xbb\xf5\xfc\x2a\x4e\xaa\x72\x1d\x9e\x45\x31\x6c\x93\x19\xe3\x80\x55\x6d\x9b\x14\xe1\x5d\x92\xcd\xa4\xce\x96\x2d\x38\xa6\x8f\x96\x77\x44\xfd\x30\xbc\x92\x55\x54\xe3\x2f\xc1\xae\x39\x66\x95\x1a\xe7\x82\x84\x3a\x33\x3a\x89\x66\x54\x29\x78\x42\x2b\xcc\xf0\x95\x77\xf8\x36\x94\xbd\xbd\xa9\xea\xa2\x27\x04\x5f\x95\x8a\x82\xd0\x19\x6c\xa8\x7d\xb3\xc3\x33\x3f\x30\xae\x55\x8e\x55\x3e\x8f\xc7\x3c\x79\x04\xe3\xed\xb6\xd8\x34\x6e\x41\x94\x61\x63\x2f\x83\x0a\xa8\x07\x37\xe2\xee\x7c\x46\x53\x35\x30\xb6\x92\xad\xc6\x25\x2b\x9a\x1c\xdc\x83\x0e\xe4\xc6\xf6\x68\xea\xfa\x58\x74\xa2\xcc\xad\xf2\x01\xe9\x7b\x15\x0d\xc4\x59\xf2\x78\x27\x3a\x35\x56\xd6\x57\x09\x98\x0a\x9b\x1b\x89\xff\x1e\x11\x79\xfa\x78\x01\x79\xc6\x53\x7c\xdc\xa7\xdc\x4f\x16\xeb\x81\x2a\x66\x48\x47\x52\xdc\x6b\x76\x6e\x74\x41\x95\xc2\xf5\xd4\xe4\xae\xc3\xc9\xc6\x88\x9a\xb0\x47\x00\x69\x84\xa9\x57\x90\xfb\x34\xeb\x24\xc5\xa5\x4a\x11\xc1\x59\x21\xda\xed\x6b\xa2\x9b\x17\x02\x6d\xdc\xb0\x15\xbf\x05\x39\xc8\xb5\x12\x26\xaf\x4e\x34\x33\x1e\xbd\x42\x8f\x34\xbf\xce\x14\xaa\x86\x09\x63\x09\x6e\x30\xf5\x98\xd7\xd0\x9b\x85\x9f\x45\x8e\x74\xd8\x96\xd3\x03\x6f\x20\xb5\x91\x38\x8c\x01\x45\x57\x97\x44\x08\xe9\x5c\x71\xe6\x35\x42\x22\xa1\x4b\x12\x8c\xe0\xaa\x17\x2e\x06\x9c\xb9\x63\x8c\x9d\xe5\x22\x85\xab\x63\x1e\xad\xec\x4c\xfd\xa6\xd1\x33\xd2\x4b\xca\xea\x69\x38\x5f\xb3\x6f\x0a\x29\x3f\x56\x50\xa2\x2a\x62\x1a\xbd\xea\x67\x46\x2f\xb9\xa8\xb4\x3e\xe3\xcd\x21\xdf\x01\xae\x0d\xd3\x37\xdb\x6e\xa1\x67\x9f\xd1\xbe\x2e\x9f\xbe\x02\xbc\x6e\x97\xa2\x82\xe2\x1d\x83\x3f\x4e\xc4\x06\xac\x72\xa6\x05\xe4\x8d\x30\xe5\x71\x37\x21\x55\xeb\x86\xc8\x7c\xb3\x4b\x61\x77\x21\xad\x71\xc2\x65\x4f\xc1\x1c\xc9\x30\x15\xad\x14\xcf\xc2\xd4\x14\xc4\x7f\x7f\xe7\xc3\xd6\x62\xfe\x83\x05\x3c\x87\xfe\x2f\xd7\xfb\xfe\xe5\xf7\x44\xa5\x2e\xb0\xbc\x4f\xaf\xf9\xe4\x2c\x3c\x0d\xa9\x3e\x8c\xe2\x9e\x92\x7b\x8a\x0e\x6b\x13\xac\xa8\x20\x25\xb4\xe1\x81\x1c\xbb\xb2\xb8\xdf\x17\xe5\xa8\x6b\x5a\xd7\xcd\xe2\xef\x54\x98\x69\xc1\x85\xdc\x68\x86\xd8\x98\x9c\x65\xba\x79\xf4\x52\x3f\x99\xf1\x1c\x60\x61\x4a\xa8\x23\x44\xb4\x8b\xc8\x28\x92\x22\xa8\x9b\x20\xea\xaf\x0e\x5d\x76\x49\x1c\xa5\xb9\x2d\x44\x0c\x3b\x56\x74\xc1\x96\x42\x77\xdc\x6d\x25\xbd\x17\x27\x48\x20\x93\xf5\x83\x54\x43\xbc\x7e\xb0\xf4\x00\x5e\xb2\x93\x35\xa6\x63\x0b\x9b\x55\x1a\x3c\x3d\x4a\x55\x6f\x1b\xe8\x5b\x5f\x0d\x6b\xd9\x78\xd3\xec\x79\xb2\xbb\xa7\x85\x69\x8f\xa1\x69\x7c\x13\x64\xd1\xd1\x0d\xc8\x80\xc6\xf5\x90\x2e\x1f\x26\xfc\x20\xc2\x33\xdd\x87\x44\xdc\x74\x9f\x9e\xf3\xa2\xda\xea\xa7\x74\x21\x33\x48\xed\x8b\x1f\x38\xfe\x69\x9e\x8f\xe5\x57\xa0\xff\x11\x0d\x08\xde\x8d\xcf\xae\x6a\x7c\x04\x9b\xf2\x83\xa8\x3c\xdd\x0f\x8a\xcd\x69\x61\x0a\xb9\x45\xac\x01\x23\x55\xa1\xba\xd4\x6b\x0a\x26\xc9\xcc\x11\x8d\xce\x1b\x2e\x00\xd7\x67\x9b\xa5\x75\x20\x47\x49\x53\xfd\x09\x56\xd9\x6b\x7b\x33\x9b\xb7\x48\xb4\x5e\x07\xd1\x82\x29\x61\xea\x53\x2d\xc2\x40\xb7\x58\x8e\xfe\x70\xd4\xbc\x93\x66\x12\xf2\xb6\xd7\x5e\x46\xcb\xc7\x96\x50\xc7\xd6\x4c\x69\xf0\xc3\xdb\xcd\x12\xd9\x6c\x67\xee\xe0\x8b\x91\x53\xe5\x8a\x8b\x64\x69\xfc\x87\xd1\x2a\x6f\x60\xf1\x50\xe4\x30\xba\x6f\x66\x46\x16\xd4\x2e\xad\x93\x51\x95\xc4\x48\x63\xb8\xc5\x42\x63\x9e\x83\x0c\x3a\x2d\xb5\x7e\x22\x0d\xf9\xbe\xc4\xb3\xf6\xab\xc7\x95\x7a\x1a\xb9\xbb\x69\x68\x25\xb0\x2a\x2a\xa6\xe2\x3c\x5b\x3f\xf1\x32\xe1\x52\x26\x9e\xbf\x00\xb8\x4b\x9d\x47\xcf\x5d\xee\xd2\xa0\x79\xc5\xb4\x79\x8f\xfb\x95\x7b\x4f\x1b\xd1\x20\x10\xeb\x8b\x22\xb5\x5a\xa5\x53\xcd\x09\xe2\xaf\xbd\xc3\x62\xa5\x27\x32\x0f\x7f\x12\x5f\x6e\x47\x67\x80\x38\xd1\x2c\x87\xfa\x7d\xf2\x02\xf2\x68\x1e\xe6\x5a\x60\x26\x8e\x55\x65\xcd\xb3\x8b\xbb\x83\x2a\x14\x59\x33\x1c\xdd\x1b\xbb\xd3\xaf\xe5\x89\x10\x23\x99\x41\x6e\x47\x8d\xf2\x7a\xa2\x3f\xc5\x1a\x8a\xbe\x1a\xce\xa7\x70\xc7\x57\xce\x4c\xe3\xc8\xe1\xa4\x69\x11\x11\x7f\xe9\xa8\x81\xde\x97\x6e\xde\x19\x69\x47\x3c\x49\x54\xa8\x20\x67\x2f\xd0\x9d\xe5\x30\xd2\x50\xf4\xca\x8a\xfc\x10\x04\x38\x40\x06\xbb\x6c\x6e\xd7\xb1\xee\xb3\xa9\x66\xab\x88\xc8\xd9\x68\x45\x83\x23\xe2\x80\x74\xac\x81\x7b\xc1\x92\xe9\x45\xdb\xde\x45\xa6\x9b\xc3\xbd\x4d\x82\xba\x47\xd3\x8c\x7b\xdf\x66\x8d\x34\x2a\xd8\x33\xcc\x90\x96\xf7\x1d\xe5\x50\x5a\x3e\x63\x42\x18\xa5\xae\xd8\x46\xa6\x92\x09\x6e\x10\x7a\x1b\x10\x63\xf9\xc6\xf9\x9a\x13\xed\xeb\xa2\x34\x43\xb3\x35\xf2\x15\xb7\x1a\x11\xb3\xfc\xf7\xb4\x39\x8a\xfb\x0f\xf6\x17\x06\xd3\x7f\xbf\x10\x01\x75\xe4\xfe\x33\x28\x7a\xaf\x40\xfc\x9e\xb6\x62\xe0\x70\xef\xd1\x56\xa2\xca\x16\x24\xf8\x8a\xd0\x32\x4c\x3e\xc9\xdd\xca\x71\xd2\x11\x2a\x0d\xfa\x1d\xa5\x3d\x04\x24\xb6\x0d\x50\x88\xb4\x40\x6b\x90\x5c\x3b\x61\x6d\x7b\xaa\x65\xa5\x29\xab\xa6\x61\x64\xd6\xb5\x0e\x98\x1a\xa4\x72\xcc\x08\x5d\xca\x00\xbd\xe7\x59\x35\xbf\xe3\x17\xa3\xb0\xb7\x04\x32\x02\x21\x46\x0e\x4f\x27\x23\x7a\x6f\x45\x63\xf1\x6f\x7d\x15\x2d\x51\x80\x30\x2a\x75\x06\x41\x50\x1b\x21\xe2\x83\xde\x66\xfc\x55\xaa\x31\xfc\x01\xc0\x1c\x28\x06\xc0\x4e\x93\x2a\x11\x8a\x13\x26\x17\x7e\x8e\xaf\x57\xad\x90\x38\xeb\x16\xd6\x94\x3e\x63\xe9\x90\xb5\x93\xc9\xf9\x53\x33\x05\xae\x2c\xae\x88\x98\xe5\xe3\xba\x85\xb6\x5e\x42\x7d\xa6\x6a\xfe\x50\xe0\xdd\x60\x56\xd5\x87\x1a\xf4\x88\xca\xa6\x72\x59\x16\x47\x84\xc6\xc9\xf4\x15\x48\xb3\x53\x16\x6b\xc0\xd4\x80\xfd\x25\xc7\x06\xf5\x9e\xde\xe7\x6d\x52\x8f\x70\x53\x6a\xa1\xc3\x99\x3d\x15\xaa\xef\xb7\x74\x87\x60\xf3\xf6\x71\xe2\x2f\x03\x59\x8b\x15\x47\x5b\xfe\xb9\x9b\x01\x07\xa5\x07\x27\xb8\x30\x91\xf8\xfb\x54\x42\xa4\xbd\x08\x36\x24\xc3\xb6\x34\x6c\x2f\xe7\x7a\x63\xaa\x6b\x0f\x2d\x69\xbf\x95\x35\xd6\x4c\x07\xca\xff\x3c\xf2\xa2\xc2\x42\x15\xed\x40\x3c\x6c\x71\x76\xa2\xbd\x44\x7e\x53\xec\x98\x43\x8e\x00\x6a\x5f\x6f\x65\xdb\x4a\xc8\xa5\xe0\x2a\xd2\x73\x23\xd3\xc3\x32\x37\xbb\x9d\x0e\x1d\x1d\x02\xa2\x42\x97\xc3\x90\xb8\x9e\x39\x40\x8e\x74\xda\x6c\x01\x97\x79\x29\xa4\x8c\x9b\x17\x9b\x24\x1f\xa5\xcd\x4f\x29\xe6\xfd\x23\xc5\x72\x27\xc7\xdd\x2a\x13\xe2\x53\x8f\x2a\xc5\xc6\xe1\x03\xd0\x4d\x85\xcf\x1f\x40\xb2\xe8\x08\x82\x10\x3a\x13\x48\xda\xdf\x45\xb1\xd4\x02\x91\x0a\x5d\x03\xd5\xb5\x18\xcb\x34\x28\xa0\x9b\x7b\x72\xd1\xd7\x1f\x4c\x89\xe6\x9c\x46\x9f\x90\xfa\x95\x68\xf0\xae\x0a\x2e\x10\xda\xf4\x5b\x91\x12\x42\x13\x9d\x3a\x86\x50\x37\xf1\x99\x99\xbb\x07\xf8\xf4\x95\x2d\xc6\x95\xd1\x7e\x4f\x84\x7c\x27\x27\x64\x49\x26\x56\x38\x5b\x35\xfa\x4b\xe4\x7d\xc8\x57\x7c\x51\x87\x1e\xb4\x9d\x68\xd3\xf8\x6c\x73\x98\xde\xf8\xf6\x95\x0a\xee\x73\xd8\x72\x24\x7a\xec\xed\x3b\x76\xcf\xed\x9f\x92\x25\xd7\xf2\xcc\xb8\x71\x1b\x14\x20\x37\x12\xad\x9a\xe8\x0d\xa7\x7d\x2d\x36\x15\x85\x08\xf2\x9a\xef\xbc\xc7\x25\x45\x65\x66\xca\xde\x61\x32\x5f\xe5\xdc\x73\xe6\x98\x0b\x16\x5f\x6b\xb1\xdc\x8f\x51\x25\xf1\xe2\x19\xf5\x2e\x58\x9e\xeb\xa9\xa3\xef\xfa\xc1\x77\xae\x1e\xec\x13\x69\xbe\x3a\xd7\xc4\xb6\xa8\x51\x47\xa3\xf4\xc7\xc9\xf8\xd2\xc5\xf1\x73\xc0\x3a\x16\x01\xa6\xb2\xc6\xc3\x17\xa3\x04\x0b\x4b\xe7\xee\xe4\x51\x2b\x40\x74\x8c\x9e\xa7\x67\x5a\xeb\x9e\xa2\x19\x59\x1d\x85\xea\x9b\xbb\x46\x0d\x7f\x3b\x45\xc4\x03\xa7\xa4\x0a\x9b\x51\xf6\x41\xb8\x34\x4e\x19\xd6\xc6\x7b\x8b\xc4\xe8\xa2\xf3\xcc\xc2\x5f\x7c\x18\xd9\xff\x4a\x78\xf6\x8b\x4e\xe8\x7e\x4f\x79\x52\xf6\xe7\x1f\x4b\x9e\x0c\xfb\x5f\x7c\x98\xfe\xe7\x5f\x1e\x78\x66\xba\x6d\x5a\xe4\xb1\x61\x3e\x27\x2c\x55\x05\x93\xe3\x56\xf4\x23\x34\x55\x63\x8b\x11\xa0\xb6\xe7\x71\xb8\x2b\x88\xd2\x28\xaa\x9b\x60\x75\x83\x95\x1e\x95\x97\xbc\x25\x23\x64\xb7\x72\x2b\x36\x8a\x1c\x57\x8e\x2c\x0a\xf2\x14\x3a\x1c\xb4\x23\x31\x92\x8f\x39\x01\xbd\xb3\xec\x26\xef\x11\x0f\xca\x6b\xfe\x0c\xee\x0e\x89\xce\x5b\x16\x7b\x23\xed\x8d\x53\x8e\x8f\x24\x88\x1a\xe8\x77\xb1\xcf\x4e\xa5\xde\x26\x32\xc0\x28\xcc\x4d\x28\xe2\x58\x0f\xdc\x81\x91\xfd\xe4\x67\xbe\xe1\xc4\x48\x26\x38\xd2\x01\x82\xed\x8c\x44\x0f\xa6\x79\x85\xed\xf9\x46\x1f\x3a\x52\x17\x20\x76\x15\x1c\x4b\x9e\x5a\xbe\x98\x5a\x25\xcb\x73\x9a\xc0\x63\x73\xdc\x18\x3c\x54\x20\xc8\x2d\xfd\x16\x39\x15\xd2\xbc\xbb\x41\x0c\xd9\xfb\x45\x38\x05\x01\x98\x87\xd5\x2a\x96\x91\xd0\xda\x10\x78\x81\xc8\xb8\xf9\x35\x59\xfb\x31\xe6\xa4\xd0\xc4\xd0\xc9\x60\x53\x43\xa4\x74\x0c\x90\x30\xb1\x2d\xd6\xe4\xab\x40\x86\xf5\xcd\xf6\x69\x7f\x59\xaf\x34\xa4\x52\xe9\x4e\x6b\x43\x9d\x1b\x05\x4c\xdf\x99\x33\x56\xb8\xc3\x49\x1f\x66\x76\xfb\xfb\xea\xfb\xc2\xf1\x8b\x59\xb4\x11\x88\xbe\x8e\xd8\xa6\x18\xca\xe8\xd0\x60\x91\x1d\x7a\x6f\xdc\x24\xeb\xc9\x11\xde\xe3\x12\x19\x1c\x61\x0e\x97\x93\x99\xc8\x27\x87\x1c\x07\x2c\xe8\xa3\xfe\xf4\xeb\xd4\x0b\xb3\xcc\x58\x5f\xeb\x82\xe7\x45\xc9\x97\x8d\xee\xe5\xac\x60\x3e\xb4\xc2\xca\x5d\xc7\x83\x42\xbc\x75\x21\x67\xf9\x76\x78\xe1\x72\x24\x35\x3c\x34\x32\x7c\x96\x98\xa1\xe3\x9c\xca\x28\x5e\x41\x67\x85\x34\x8f\x26\x19\x5d\xa7\xb7\xa9\x2b\xb3\x91\x4b\x57\x31\xe9\x75\x46\xa5\xb0\x40\xbe\x97\xda\xbc\x69\xde\x3f\xa6\xe6\x4b\x84\xa5\x55\x80\xa2\x32\xd1\x3b\x4d\xeb\xfd\xb6\x2f\x32\xd9\xaf\x37\xb9\x53\xc2\x5f\x94\xfa\x18\x64\x68\x05\x18\xcd\x63\xed\x2a\xb8\x38\x9d\xd2\x91\xef\x7f\x6f\x36\x86\xd4\x04\x71\x26\x80\x73\x5c\x7a\xe2\x9a\xa2\xc5\x9e\xcb\x7d\x9c\xb4\xdf\x3e\x06\xcf\x4d\x69\x2d\xf4\x7a\x16\xde\xab\x74\x01\x74\x2a\x7f\xf9\xf6\x1b\x56\x29\xf1\xe0\xcc\x98\x6b\x75\x47\x66\x76\x27\x49\x29\x47\x54\x68\xc5\xd7\x8d\x22\xdc\x5b\x5e\xaf\xdc\x92\x24\x03\x93\x70\xaa\x5a\xac\xa2\xe8\xa8\x97\x29\x53\x9d\x4d\xf1\x31\x9b\x7c\x69\xec\x48\x79\x82\xc6\x36\x52\x16\xea\x6d\xbd\xad\xae\x52\xea\x78\x4a\x40\x08\xbf\x59\xec\xb6\x5f\xf8\x04\x10\xc6\x68\x85\x3e\x5d\x32\xb1\x5f\x8e\x7b\x9b\xc6\xdc\xa5\xce\x08\x80\x67\x5a\xc9\x8b\xd8\xc6\x4b\x19\xc1\x30\xb6\xb2\xd8\x2f\x4c\xa3\xc6\xe7\x22\xaa\xce\x22\xb2\x5c\xf3\x0c\x5a\xcd\x6b\x1f\x3f\x04\xe7\x44\xba\x1c\x1c\xc9\xc1\xc5\xc9\x82\x25\x73\x35\xd0\xc6\x08\x15\xb6\xb2\x88\xad\x9a\x18\x7d\x7f\x87\x40\xda\x8a\xe8\xad\xc4\x2a\xc0\x39\x8b\xb9\xb0\x7e\xd7\x73\xd2\xaa\xf9\x83\x9d\x73\x0c\xfe\x6f\x7c\x92\x5f\x6d\x0e\x70\x5f\xe7\x9e\x5e\x7a\x0d\xea\x93\xe6\x42\xa1\x9b\x76\x98\x87\x57\xe4\x58\x10\xfd\xd1\x39\xdb\x4f\x0b\x54\xc1\xfd\x0d\x95\x85\xf0\xd7\x74\xbd\x04\xa2\xfe\x40\x99\xf3\xad\x75\x5b\x9a\x5a\xfe\xa0\x59\x9f\x51\x07\x09\x77\x14\xeb\x51\x8a\xd0\xbe\xdf\xf7\xa4\xf2\x27\x36\x1b\x76\xff\x62\xbd\x5e\x90\x24\x86\xbc\x63\x49\x61\xc8\x9d\x65\x68\xfd\xee\xdc\x1b\x7f\x00\x16\x2f\x2d\x5d\xa2\xcb\x1c\x05\x75\x46\x10\x81\x19\xaf\xc1\x11\x35\xe8\x82\x9e\xc4\xaf\x3b\x35\x60\x61\x0c\x00\x8d\x41\x9a\x6a\x27\x5a\x8d\x27\xc3\xb4\x3f\xf0\xe9\xcf\x71\x3e\xed\xdf\x30\xcb\x74\x5e\x45\xb4\x2b\xbe\x13\x38\xdd\x38\x27\x5f\xe9\xa5\x30\x4f\x70\xd0\x74\x6c\x77\x72\xfd\x8a\x98\xff\x3f\x7b\x6f\xde\xbb\x38\xb2\x2c\x88\x7e\x15\x34\xd2\x55\xbd\x11\x03\xde\xb7\xf7\xd4\x7f\x78\xc7\x78\xc1\x2b\xb6\xf9\xe7\xca\x1b\xb6\xf1\x06\x78\xf7\xa7\x7f\xb2\xf9\x55\x55\x9f\xd3\xdd\x73\xce\xd5\xed\x91\x7a\xa4\x2e\xf1\xcb\x32\x99\x91\x91\x91\xb1\x65\x44\x60\x8c\xff\x9a\x87\x91\x5a\xe2\xcc\xa9\x01\x05\xa3\x74\xf4\x22\x76\x22\xf9\x2a\x6f\x6c\x73\x82\x31\x14\xe0\x62\x36\x36\x18\x76\x7a\xdd\xfa\x7d\x9f\xbe\x6a\xb7\x71\xa9\x76\xd4\xb0\x24\x7b\xc2\x5a\xd3\xa5\x52\x83\x87\xa2\xe1\x8a\x5d\x60\x91\xfb\xc1\xc0\xae\x54\x00\xf6\x98\xb5\x87\xd2\x3b\xcd\xf0\x79\x49\xbf\x62\x27\xad\x28\xf2\xc4\x8d\x8e\x51\x70\x36\x79\xf6\x1a\x5d\x7f\xed\x99\x46\xc5\x0a\xd6\xaf\x04\x9b\x7a\xbc\xe7\x1a\xda\x67\x05\xdd\x11\x59\xc2\x4c\x64\x9c\x85\xd6\x48\xb3\x95\x4d\x3b\xa3\x9d\xc6\xe5\x0d\x60\xaf\xf2\x39\x50\x6a\x09\x12\x39\xd2\xce\x8b\x5b\xae\x5b\x26\x29\x4e\x79\x48\x46\xd9\x89\xc2\xaa\x9b\x3d\xa5\xa3\x7b\x1a\x4f\xc4\x3e\x15\xd4\x76\x7c\x45\x4d\x21\x99\xe1\x43\xbd\xc0\x27\x8e\xad\x6f\xd0\x75\xa0\xdf\xcf\x07\x5f\xd5\xf2\x2d\x22\xf7\xd1\xed\x7c\xf6\xc5\x56\x69\xd5\xfc\x46\xd2\xe9\xc8\xbf\x02\x1f\x57\x43\xdc\x34\x4c\x04\x39\x0b\x99\xc8\xb3\x0b\x6b\xce\x77\x5a\xf0\xb4\x9e\x1a\xf6\xe6\x55\x33\x6f\xae\xa4\xf6\xdc\x59\xeb\x7d\x95\x0e\xb8\x39\x72\x04\x31\x63\x2f\x69\xd7\xd3\x9d\x70\xe5\x68\x12\x11\x31\x9a\xb4\xdf\x02\x37\xee\x05\xcc\x50\xe9\x89\x96\xcf\xe7\x69\x81\xa7\xda\x45\x4c\xfd\x2c\x86\xd5\xfe\xcd\xce\x8f\xa6\xbb\x25\xdd\x09\xe5\xc4\x25\xb0\xac\x84\xa3\x91\x0c\xbd\x95\xa8\x09\x9e\x2f\xfc\xcd\xb5\x9f\xd2\x22\xa0\x35\x50\x51\x14\x16\x6a\xf1\xeb\x36\x32\x78\x05\xa6\xc2\xbd\x43\xe8\x02\x1f\x96\xbd\xec\xbb\xa3\xd0\x8a\xe5\x4b\x9a\x3c\xa9\xe3\x23\xae\x83\x68\x53\xe5\x3b\x39\xbe\xa6\xb7\x70\x7f\x1f\x69\x50\x84\x59\x38\xf3\x54\xf0\x66\xdf\x34\x33\xb2\xee\x60\x08\x3d\x2b\x2f\x27\x7a\xbf\x7e\x48\x7b\xe5\x1e\xd4\x15\x76\x37\x8d\x56\x26\x19\x69\x92\xa3\xb7\x4c\xe4\x40\x2f\xa5\xfa\xde\x1e\xf7\x42\x69\xf2\xaf\x93\x86\xdd\x27\x60\x98\x1d\xb4\x3f\x31\x3c\xee\x5c\xd0\x94\x73\x5f\x05\x70\x16\x02\xa5\x57\xa7\xc8\x4b\x84\x02\xb7\xfb\x33\x05\x5e\xc1\xd3\xa5\x80\xf2\x9a\x38\x93\x34\xfd\xa8\xd2\x42\xbf\x3f\x9c\x7d\xde\xfe\xa9\xbe\x21\xfb\x6b\x79\x86\xd0\xfc\x79\x8b\x66\x01\x29\x23\x48\x1b\xf5\x1d\x1c\x1b\x19\xec\xba\xeb\xeb\x09\x66\xe3\xeb\xca\x96\x7b\x87\xe1\x4d\x9b\x42\x05\x62\x22\x48\xf6\x8e\x3a\x0b\x44\x50\x9c\x0d\xa1\x02\xe9\x86\xfe\xa9\x33\x0b\xc6\x37\x15\xed\xc5\x75\x71\xa0\xdf\x94\x4b\xd8\x2b\x2d\xa4\x89\xa5\x17\xb9\xdc\xf9\x26\x86\xc9\xbc\x9f\x08\xc3\xe1\x8d\x54\x7a\xd9\x20\xa1\x2b\x98\x2b\x67\x27\x05\x3b\xa1\xf8\x79\x0f\xc3\x2f\x18\x1e\x5a\xf7\x19\xba\x63\x5c\x9b\x68\x73\x26\x41\x45\xcb\x17\x38\x5a\x44\xe7\xc1\x6b\xd9\xf0\x40\xa3\x4e\xe2\x51\xf7\xfd\x20\xbd\x4a\x77\x4a\x59\xa1\x6a\xd6\x8f\x2e\xc2\xc2\x53\x0f\xe8\x22\x5b\x36\x1b\x3f\xe2\x77\x97\x2b\xf1\x9b\x90\xb3\x6b\xba\xf0\xc3\xe8\xe2\xc5\x9b\xa5\x60\x1e\x2f\x50\x39\xa6\xc2\x73\x87\x11\xe7\x2b\x36\x08\x32\x2c\xdf\x4d\xc3\xbc\xee\x4d\x5a\x2d\x96\x29\x2d\x7d\x09\x32\x03\x6e\x86\x63\x17\x7a\x3f\x5d\xf3\x61\x34\xd8\x55\xcc\x23\x5f\x6a\xde\xee\xb5\x69\x84\xc1\xb8\xb2\x2c\xfd\x10\xc9\x4b\x35\x42\x6a\x2a\x92\xb4\x0a\xf6\x16\xe3\x70\x56\xcd\xde\x0b\x40\x12\xd9\xd3\x78\x47\x38\x96\x03\x08\x27\xbb\x28\xcc\x5b\x28\xb8\x3e\x79\x02\x19\xe7\x58\x16\x3b\x40\xb9\xdf\xa0\x6f\xe9\xfe\x12\xc7\xca\xb1\xb4\xf3\xe3\xee\x87\x4c\x64\xc8\xd9\x6d\x04\x03\x46\xa5\x51\x06\x25\x95\x91\xc9\x98\x0e\x88\x2e\x1a\x09\x9e\x2a\x95\xd2\x0c\xfc\xee\xa5\x80\x5b\x16\x3d\x6a\x8f\x95\xe6\x72\x4b\x60\xbc\x96\x93\xb8\x07\x75\x4b\x6e\x62\x2c\x3a\x61\xd7\x0c\x36\x73\x3a\xf3\xe5\x88\xe4\xca\x2b\xe4\xe8\xd6\xdc\x0b\xaa\x38\xa7\xd7\x52\x4d\x21\x40\xc7\x19\x16\xe7\x5e\x9e\x21\x93\x0f\xed\xc6\x79\xb4\x4f\x43\x77\x18\xba\x22\xe8\xa8\x7a\xbe\x10\xe4\xf3\x75\x04\xdf\xe7\x79\x51\xd2\x16\xb9\xaa\xc5\x74\x79\x88\x5d\x3e\x01\x57\xd0\x73\xd9\xec\x06\x46\x12\x9c\x03\xf1\x32\x78\xf1\xdd\x8e\x41\xe3\x4e\x41\x8c\xaa\xbf\xb3\x59\x5b\x52\xf9\x7e\xa9\xa6\xc0\x9d\x9f\xaf\x80\xf3\x4e\xdb\x23\x08\x3b\x56\x21\xbd\xcb\x5d\x40\x89\x3f\xf7\x01\x63\xd9\x5f\xed\x2b\x45\x49\xf6\xeb\xaf\xe8\x0d\x20\x48\x3b\x27\x19\xf0\xe4\x3b\x34\xdf\x62\xde\xba\x9a\x8c\xf7\x30\x2d\x53\x78\xa9\xc6\x95\xa1\x31\x29\xc2\x24\x84\xab\x47\x1e\x48\x9f\xb5\x52\xcf\x22\xa2\xa4\x5e\x5a\x4e\xa8\xc3\x71\xca\xcd\x02\x4d\xb7\xe0\x94\xdc\x9c\xac\xbe\x2d\xa8\x1e\x17\x3d\x2b\xa9\xc2\x4a\x49\xdd\x5b\xe8\x11\x7b\x38\xac\x6f\x25\x05\x57\x29\x98\x36\x0d\x12\x22\xf7\xfb\x05\xa8\xa3\x78\x98\xef\x8f\x53\x72\xc7\x5f\x30\x57\x0e\x2d\x69\xc0\x45\xb7\xbc\x21\x7c\x6f\x29\x38\xf8\xc8\xb2\x1b\x4e\x85\x17\xd2\x23\xd9\x52\x61\x89\x91\xf2\x62\xf9\x7c\x15\xc9\x7b\xaf\x82\x6f\xc8\x7d\x9f\x45\x34\xf5\x1e\xe9\xcb\x81\x38\x50\x15\x23\xb8\x60\xec\xb9\x2b\xf7\x44\x40\x79\x95\x1b\x95\x90\xc4\x00\xd9\x4d\xe6\xb3\x28\x7a\x61\xc1\xf9\x0c\x24\x48\x68\xf7\x84\x9b\x42\xec\xb5\x21\xde\x9a\x52\x9a\x99\x93\xa1\x8d\x5a\x7b\x0d\xd7\xcc\x59\x73\x12\x67\xb7\x72\x92\xbd\xe1\x84\xbc\x22\x05\x84\x4b\xb2\x0f\x5a\x28\xd5\x25\x5e\x92\xa8\x60\x47\x41\x03\x71\xda\xa6\x6b\xd2\xa8\x38\x55\x55\xc5\x52\xed\x47\xb7\x8f\x9e\x0d\x7b\xd2\x12\xf4\xc1\x14\xb4\x9a\xd4\x0f\x7f\x30\x75\x7b\xce\x31\xe4\x3c\xf4\xa3\x47\xd2\xcf\xb2\x4c\xe8\x84\x89\x4c\xe1\x7d\xc2\xdf\x9e\x34\x29\x79\x45\x49\xc0\x33\x47\x0c\x1a\x32\x33\x39\xf0\xa7\xf8\x51\x68\xa4\x34\x06\x25\xab\x4a\xa3\xdb\x52\xe5\x43\x2d\x32\x70\x5c\x8a\x3d\xa5\x12\x23\x44\x50\x2c\xa2\xdc\x34\x6f\x1a\x12\x38\xdb\x47\xc8\xa9\xa7\xa0\x53\x22\x57\x1c\x80\x2f\xa7\x8b\x52\x8f\x24\x92\x97\x0c\x04\x5c\x41\x36\x79\x39\x88\x41\x42\x0a\x0b\x5c\x50\x28\x84\x99\x6e\x82\x35\xf8\x7c\xd5\xe1\x77\x6e\x92\x89\xed\x4c\x55\x0e\xda\x0b\x33\xbe\xe5\x9b\xda\xbe\xd4\x66\x21\xd5\x96\xcb\x00\xce\xed\xdd\xcc\x61\x64\xc7\x54\xe4\xc9\x90\x92\x8b\xea\x36\xcf\xce\xd7\x6b\x0b\x8a\xf6\x92\x76\x63\x8a\x51\xb2\x9a\xea\x62\xb5\x15\x73\xb3\x08\x66\x8f\xb8\x97\xe5\x36\xbc\x65\x71\x29\x54\x3a\x17\x5f\xda\x4c\xa4\x7b\xa5\x32\x0b\xf3\x9e\x14\x4c\x4d\x6b\x33\x0c\xe1\x88\x7e\xf3\xde\x56\xf8\x36\xf0\x21\xca\x20\xca\x5b\xc8\xbb\xce\x9d\x66\x05\xa1\x8c\xa5\x38\x31\x72\x12\x7b\x8f\x7b\xbf\x9f\x11\x9a\x16\x1d\x84\x90\x34\xe6\xdc\x35\x7f\xea\x03\xba\xb6\x1f\x51\xf8\x4b\x19\x5d\xf5\xab\xe7\xd6\x16\x5f\xe1\x6b\xe5\xe3\x20\x16\xec\xb3\xec\x66\x33\x9a\x6c\x72\xf4\x53\x7b\xbb\x92\x49\xa3\x35\xcf\x38\xb7\xb8\x62\x53\x45\xcb\x51\x55\xc6\xee\x7b\x41\x8b\x7b\x24\x14\x06\xe8\x0c\xf1\xde\x85\x63\x4d\xe8\x7c\xb6\x54\x7b\x7c\xbe\x1c\x1d\xd7\x72\xf6\x99\x40\xe0\xed\xb1\x20\xd9\x03\x53\x2b\x24\xb7\xe6\xb0\x44\x88\x47\x7d\xdf\x47\x18\xf2\xa8\xb8\x50\x7b\xe6\x54\x12\xee\x71\xa1\x8b\xf2\x36\x09\x28\x90\x0a\x5d\x6d\xd1\x42\x3c\x1e\x17\xcb\x93\x8b\x4c\xea\x80\x37\x84\xee\x31\x08\x7b\x31\xaf\x8a\xa3\xc9\xd3\xf3\x25\x07\x69\x86\x21\x5e\xd0\x3c\xc3\xf2\x29\x85\xc9\xbe\xa8\xb9\xa7\x40\x67\x7a\x10\xc2\xdc\x08\xda\xf2\x60\xca\x44\x59\x69\x17\x6e\x49\x74\x26\xbd\x95\x32\xd5\x38\xae\xf5\xac\xae\x5a\xfc\x94\x1c\xd2\xde\x3f\x02\xb5\x9d\xd5\x80\x43\x55\x2e\xba\x5d\x83\xbd\x96\x9d\x55\x0d\x04\x47\xb0\xc6\xaf\x70\xad\x21\xb3\x91\xc6\x27\xf7\x16\xa4\x7b\x65\xf1\x75\xbb\xa9\x24\xba\xb3\x41\xfb\x74\xed\x74\x31\xa8\xab\x10\x60\xc2\xc7\xa8\x08\xc5\x50\xc3\x52\xd7\xf9\xa2\xff\x2c\xe5\x99\x5b\xda\x53\x46\xa4\x71\x35\xd3\xee\x3d\xc3\x96\xeb\x0b\x14\xfb\x2c\x45\x4d\xfa\x24\x38\x59\x75\x1f\x5e\xc8\x03\x42\xd0\xc0\x6b\xc8\x30\xde\x4b\x76\xad\x0a\x97\x4b\x33\x38\xd8\x23\x14\xcd\xe6\x36\x6a\x93\x50\x43\xd1\xd4\xd3\x52\xc4\xb9\x40\x7b\xe3\x1e\x34\x10\xa1\xfd\x9e\xd1\xa6\xcb\x79\x9e\x5e\x41\x52\x3f\x25\x64\x21\xc9\x54\xbd\xeb\x35\x75\x1a\x28\xf2\x64\xdc\x2c\xdc\x0c\x16\x17\x2f\x1e\xfc\x34\x08\x39\x69\x8b\x31\x67\xcd\x80\x0b\xf2\xd5\x1d\x55\x2c\xdc\x24\xdb\x01\x82\x98\xea\xbe\x58\x63\xa1\x47\x15\x81\x9e\x1b\x8a\xcf\x41\xf1\x96\x56\xc5\x48\x1a\xec\x25\x68\xc8\x8b\x17\x05\x0b\x80\x0d\xd6\xad\xd6\xe3\xfa\x89\xd0\xcf\x17\xc3\x28\x85\x7b\xe6\x41\x36\x27\x68\x6b\x09\xa5\x8c\x55\x14\x03\xe2\xc1\xfc\x52\x30\x5c\x46\x69\x4f\x27\xcd\x9d\xe4\xd1\x90\x8d\xd6\x9f\xc7\xb9\x06\x7d\x9d\x66\xba\x1a\x83\x1c\x5f\x10\xf2\x41\x44\x66\x46\x64\xb5\x5b\xd1\x73\x5d\x04\xa8\xee\xfe\x66\x48\xc8\xe5\xed\x3f\x99\x80\x36\x59\xb9\xbf\x17\x08\x83\x79\x52\xee\xce\x59\xae\x60\x17\xee\x49\xee\x85\xbb\x70\x3a\xed\xe5\x5c\xb6\x5e\xae\xec\x28\xe4\x9d\x05\xb4\xa5\x16\x4b\x9d\xa9\x96\x3d\x8c\xc6\xb7\x87\x5c\x73\x20\x7b\xe6\x22\xb5\x99\x5d\xd0\x7a\x79\xbd\xda\x9d\x18\x61\x24\xde\x99\x44\x73\x10\xff\xd6\x1c\x2d\xb8\x4f\x32\xa3\x25\x43\xf0\x1c\x7b\x1c\xd3\x9e\xbc\x81\x0a\x2f\x4f\xa2\xf7\xa6\x1a\xe3\xd7\x91\xd1\x91\x48\xb7\x78\x33\xc4\x53\x45\x12\xa4\x17\x0e\xed\x9d\x97\xe8\x06\x42\x1c\xbd\xaf\x1d\x50\x56\x74\xef\x3e\xe8\x1c\x0e\x72\x55\x18\xab\x8b\xdf\x4b\x67\x40\xc3\x55\x98\x1c\x46\x49\xa5\xd5\x46\xe3\xe6\x14\x7d\x47\x0e\xf5\x67\x3a\x85\x3c\xfa\x8b\x7d\xcc\x96\x99\xbf\xf2\x09\xc2\x8f\xef\xf6\xc6\xef\x80\x08\x15\xed\x99\xc3\xf4\x64\x08\x72\x50\x16\xe7\x77\x93\x49\x6c\xee\x17\x9e\x1e\xa4\xde\x7b\x22\x48\xee\x8e\xca\x28\x29\x72\xcc\x52\x19\x89\xae\xa8\x99\x73\xe1\xb4\xc9\xc0\xa2\x9c\x2f\xce\xd7\x17\xd7\x9d\xc5\x4a\x75\xdf\x2c\x6d\x9b\x61\x0c\x27\x51\x63\x61\x3d\x12\x34\x43\x95\x2c\xed\xd0\x53\xdb\x2d\xc9\x7a\x2e\x97\x99\x84\x7a\x0a\x11\xc1\x6f\xcc\x57\x48\x48\x91\x78\x85\x4f\x33\x85\x46\x7a\xa0\x8f\xa7\xea\x54\xeb\xd5\x5d\x74\x01\xb7\x1f\xf6\xca\x73\x1c\xe3\x3a\x31\x7d\x66\x22\xf4\xc4\x95\xc1\xf1\xe2\xfb\x59\xe4\x4d\x73\x54\x88\x57\xe8\x1e\x87\x75\xd8\xab\xad\x17\x15\xe5\x4b\x37\xcf\xc6\x24\xa8\xf2\x82\x9a\x13\xc7\x76\xd7\x0b\xda\x22\x53\x69\x3e\xdc\x86\x01\x05\xff\x51\x1a\x3a\xcf\x33\x79\xc2\x66\xa3\xcc\x9a\xa2\x3a\x61\xbd\xd2\x05\x72\x0b\xe9\x58\x92\x93\x92\x5c\x8a\x01\xe0\x17\x9e\xea\xf9\x5d\x69\xf3\x5c\xd9\xd6\x23\x50\xa9\x5e\xc6\x9c\xa3\xd7\x64\xc9\xf8\x50\x46\xcf\x00\xd5\xf9\x27\xdb\x34\xce\x2c\xbd\x5a\x4c\xc5\x33\x11\x6a\x60\xd6\x19\x5f\x34\x48\x41\x91\x10\xf9\xca\x1d\x68\x1f\x4b\xe4\x11\x18\x9f\x1b\x52\xf3\x90\x28\x82\xa0\x58\xdb\x37\xd1\xc7\x68\x33\xf7\xfd\x9b\x10\xe9\x31\x03\xe9\x89\xcd\x15\xfc\xac\xda\x00\x88\x0e\x06\x41\xf5\x64\x20\xc1\x17\x80\x38\x2f\x29\x4e\x35\xb8\xd8\x90\xc9\x38\x47\x4e\x90\x75\xcc\x93\xe6\xb2\x93\xac\xd4\x32\x90\x5c\xc3\x42\x8d\x3b\xf3\xe2\x4a\x03\x09\x6a\x06\xdc\xea\x59\x1d\xd1\xd4\xa9\x1b\xeb\x3d\x95\xdd\x44\xf0\xed\xe3\xdc\x22\x8c\xe7\x72\x4f\xc4\x59\x0b\xde\xda\xce\x99\xc9\x77\xdc\x8f\xba\x05\x8c\x31\x90\x64\x55\x8e\x14\xe3\x0b\x5d\xec\x53\xee\x3a\xa9\xf7\xdc\xf3\xbd\x42\x0a\x83\x36\x08\x25\x66\xd6\xe8\x44\x5b\x24\x9e\xcf\x12\x5c\xf8\x48\x0d\xaa\x03\x4a\x32\xf3\xfb\x62\x54\x41\x1d\xc5\x39\x29\x81\x72\xf4\x40\x1c\x2c\xef\x69\x98\x9a\xe8\xa4\x94\x59\xe7\xf4\xe6\xa5\x60\x5e\xca\x2e\x48\x45\x98\x47\xa5\xb1\x10\x02\x23\xb5\x58\xbc\xf4\x25\x90\xca\x35\x30\x26\xa5\x0e\xeb\xb5\x2b\x56\x8b\x58\x9b\x9e\x63\xd9\x67\x41\x91\x74\x1b\xfb\x72\x1b\x18\xc9\x12\x34\x9e\x99\xea\xb6\x5f\x38\x44\xf4\xd0\xe1\xce\xb5\xed\xb2\xbc\xe8\x1e\x7c\x14\x67\x83\x4b\x62\x56\x0c\x19\x9c\x76\x53\x0c\x7d\xfa\xa1\xde\xec\x35\xf1\xaa\xc7\x76\x4a\xf3\xf4\xcb\x78\x11\xa0\x3e\x77\x92\xf2\xe7\x7e\x17\x3f\x6f\x9b\xbf\x96\xbd\x3e\x7e\x7e\x2c\x5e\xb4\xdd\xdb\x01\x79\x67\x7a\x03\x05\xf6\x0a\xcf\x4b\xac\xfb\x4f\xb1\x78\xb6\xce\xb9\xa1\xe1\x17\xd4\x28\x0f\x3b\xce\xc5\x5c\x62\xb1\xa8\xf7\x4e\xe5\x34\x50\x0c\x7f\x79\x5b\x9d\x3d\x30\xb5\x31\x98\x6f\x8b\x96\xda\xe4\xc1\xbe\xcb\xd7\xb3\x75\xcc\x17\x9c\xb1\x67\xcd\xd8\xdb\x9a\x52\x61\x7d\x04\x4c\x88\x5a\x2d\xe7\x0c\x41\x2b\x4e\xab\x87\xa1\xd6\x96\x0b\x8f\x8a\xe2\x65\x9c\xc8\x7d\x47\x79\x46\x71\xaf\xc1\x2b\x0f\xfa\x18\x40\xdc\xf6\xc5\xa9\xda\xc7\xc3\x25\xeb\x62\x44\xa7\x22\x60\x1a\xb5\x5b\x46\xd4\x6e\xa0\xfa\x9d\xe6\x54\x1e\x20\x44\x1d\x30\x94\x1a\x01\x90\x67\x2c\x30\xcd\x74\x5e\x2a\x72\x5a\x9e\x26\xf7\x10\x79\x38\xb8\x9e\xd0\xab\xfd\x8a\xeb\xc6\xf1\x53\xc0\x2b\xf8\xac\x9a\xf7\xec\x84\x70\x19\x8d\x75\xea\x12\x0b\x4d\x39\xa4\x98\x3a\x21\xc2\x44\x59\xd5\x09\x3c\x4b\x29\x41\xdd\x1a\xe4\x81\x8a\x34\xa7\x4a\x4d\x71\xb6\xe5\xee\x11\xde\x69\xd9\x73\x50\x1f\x80\xb5\xc1\xba\xcf\x27\x02\xb3\x85\xcb\x14\x50\x6c\xf5\x06\xbd\xba\xd4\x57\xa5\x4e\x2e\x06\x3e\x6a\x2a\xd7\x36\x82\x87\xd3\x7c\xf9\x32\x4a\xed\x0a\xc9\xed\xa5\xd7\x46\x0b\xa0\x45\xe1\xc1\x3b\x12\x97\x55\x35\xb6\x07\x38\x55\x85\x70\x80\xca\x53\xa6\x19\xe9\x45\x90\xa5\x76\xd4\xcf\x6f\x5c\x7d\x94\x93\xa0\x23\xed\x15\x44\xd3\x40\x27\xcc\x45\xd5\x13\x7c\x1a\x5c\x15\x4a\x35\x87\x51\x61\x47\xf6\x4b\x26\xe8\x11\x23\xcd\xc4\x67\x96\xc2\xd4\x19\x49\xb9\x52\x51\xf2\xd2\xd5\x62\x0e\x49\x8b\x41\x92\x38\x33\xe3\xa8\x59\x4c\xe0\x8a\xbd\x82\x57\xf4\x24\x78\x3d\x3b\xd9\x18\x57\x0e\x24\xb7\x20\xad\x54\xd0\x2d\x88\x08\x41\xc9\x4d\x8c\x6a\x58\x1d\xc5\x98\x8c\x9a\x69\x75\xd4\x5f\x88\x78\x76\x60\x32\xa2\xba\xfa\x4e\xb2\x80\x01\xde\x3a\x13\x15\xa5\x2a\x31\xac\x07\x49\xeb\x8a\x79\x22\x08\x98\x71\xa3\x34\x17\x2e\xdc\xfd\xce\x0e\x40\x47\x9e\xa8\xee\x02\x0e\x88\xf9\xb8\x12\xd7\x57\x91\x24\x9e\x52\x2e\xdc\x7d\xf0\x1f\x0f\x92\xec\xbd\xac\x44\xcf\xa3\xd4\xbe\xfd\xa9\x52\x7c\x40\x85\x52\x3f\x2a\xa5\x41\xe4\xa9\xc7\xed\xae\xe9\x6f\x8b\xe5\x10\xc0\x48\x95\x39\x71\x6d\x9a\xbb\xe2\xa3\x4b\xd1\xef\x59\x8a\xd8\x82\x01\x7b\x88\x7e\x01\x0d\xab\xf7\x55\xd9\xdf\x1b\x81\x80\x07\x29\x4b\x02\x85\x7b\xa3\x23\xab\x48\x97\xd7\xdb\xaf\x1d\x85\x86\x50\xdd\x6a\x5e\x4f\xeb\xcc\xd3\x4e\x5e\xde\xde\x1c\x41\x58\x03\xa2\xc8\xfb\x48\x02\xf7\x4c\x42\x46\x74\x18\x56\xf4\xe5\xdd\x84\x60\x90\x76\x1c\x4a\x41\x8a\x7f\x2f\x9a\xd7\x50\xcf\x37\xa5\x75\xcd\x82\x06\xd2\x62\xa4\x19\x05\xb5\x10\x85\x20\x3d\x7f\xfe\x33\xcf\xe3\x47\x30\x04\x7f\x31\x03\xff\xfe\xf0\x9a\x27\xe9\x80\x9f\xcc\xb8\xd6\xf2\x0b\x3f\x27\x4f\x63\xce\x8c\x26\x34\x19\xab\xbc\x4a\x8d\xc9\x32\xbc\x6e\xd3\x0f\xa3\xb5\xf8\x3a\xe1\xf7\x74\x4d\x0a\xea\x6a\xe8\x8a\xd6\x18\x71\x2f\xd1\x3c\xf2\x6a\x9e\xb2\x76\xa6\x25\xe9\xf9\xa4\xe1\xc7\xfb\x62\x52\x48\x10\xe0\x80\x46\xce\xb7\xde\x99\xe6\xa9\x78\x7b\x6f\xe4\x7e\xaf\x96\x68\x09\x6d\xc3\x64\xd2\x13\x4b\x22\xf5\x03\x89\x02\x98\x8c\x39\x04\xaf\x27\xfc\x3e\xd4\xcb\x5b\xd3\xde\xf1\x13\x6d\xf2\x70\x76\xaa\x64\xa6\xee\x3a\x93\x2c\x7c\xea\x5e\x85\xde\x57\xe2\x79\x28\x75\x31\x50\x7d\xf4\x5e\x42\x81\x69\xed\xa9\xe7\x4b\xc7\xf8\x92\x2e\xaa\xa8\x2e\x6a\x73\xec\x2f\x7b\x6d\xee\xb0\x1e\xe0\x6d\xff\x3e\x3f\x28\xf7\xfd\xbc\xd5\xd5\x73\xaa\x61\xe0\x52\x40\xd6\x58\x03\xe2\xd0\xd5\x27\xac\x40\x6d\xa5\x4f\xd0\x42\xbb\x4f\x8d\xd0\x3c\xdf\xa6\x31\x40\xf6\x72\x09\xc9\x88\x96\x7a\x64\x7f\xe3\x88\x86\x03\x4e\x15\xe1\xf5\xd3\xf2\x32\x1d\x8d\xeb\xe2\xa2\x57\x72\xbb\x72\xb1\x4e\x98\xa2\x84\xf1\xca\xda\x4b\x0d\x9b\xbe\x98\x96\xda\xc1\x8d\x98\x2c\xce\xf9\x7c\x7e\xcb\x54\x2c\xb8\x31\x7f\x22\xa4\x02\x8d\x19\x98\x52\x72\xde\x4a\x1c\xfe\xec\xc5\x04\x10\xd3\x36\xa2\xec\xa1\x7c\x28\xd9\xd3\x9b\xd4\xf8\xa5\xef\x3c\x9b\x19\xc2\xb3\xae\x5b\xf1\x05\xa0\x4f\xd8\x38\xb7\x6c\x36\xaa\x00\x74\x5a\x58\xb1\xac\xe8\xe5\xf2\x96\xa7\x1e\x4e\xd8\x3e\xc6\x6f\xf0\xb9\x48\x60\x75\xb4\xb3\xa7\xe3\x29\xb8\x56\xc3\x37\xfa\x2a\xd8\xa5\x36\x12\x60\x28\x83\xb9\x59\x8b\xf4\x8b\x7a\x8d\xa7\xee\x52\xd9\xe6\xb3\x9d\x20\xad\x3d\xcd\xb2\x79\xad\x35\xbd\x6e\xd4\x46\xa6\x8a\x08\x66\x1e\x21\x87\x0e\x05\x76\x16\xaf\x98\x56\x30\x0d\xaf\xab\xa8\x20\xd4\x6c\x97\x9c\x05\xf7\x62\xa1\x75\x77\xe2\xef\xcf\xcc\x98\xe5\x40\xb0\x5d\x41\x19\x09\x10\xa5\xcf\x30\x7e\x13\x26\xe0\xc6\xf3\x39\xe2\xcf\x3e\x78\x81\xb8\xea\x8d\xf2\xb2\xed\x9c\x68\x32\x73\x6a\x0b\x6f\x73\x09\xe4\xf8\x93\xe2\x37\xe9\x3e\x84\x49\x93\x35\x7b\xcd\x33\x81\xdc\x70\x9e\xba\xc3\x1b\x7b\xed\x9a\x75\xb8\xd2\xc4\xf5\x63\xda\x8b\x9e\x9f\x72\x96\x60\xd6\x2f\x8a\xe0\x63\xf8\xe9\x59\xa5\x97\x39\x56\x22\x66\x93\x1f\x61\xad\x5c\x6a\x9e\x8a\x71\xa2\x62\xc2\xb6\x3a\xde\x6f\x57\x9d\x96\xf2\x7d\xd3\x89\x9a\x3b\x43\x77\xfe\xe6\xc8\x49\x83\xbe\x22\x74\x6e\xa5\xbd\x40\x5e\x8b\x56\x91\xce\x77\x3f\xe2\x28\xc3\x4f\x19\x80\xd3\x74\xf5\xd9\xb9\x4c\xd9\xd6\x8c\x64\x91\xf8\x54\x71\xaa\xcd\x34\x80\xee\xc6\xa0\xc2\xe0\xd7\xdb\x3d\xe6\xc3\xb3\xfd\x79\x5e\x2e\x8d\x9d\xa4\xa5\x1c\xa8\xb8\xfb\x53\xef\x5d\x79\x3c\x93\xf4\x7f\x7d\xbf\xfc\x8b\xdd\x7a\xff\xf3\x36\xb7\xd6\x21\xcb\x7e\x7b\x8a\x5d\x8b\xc6\x95\xfa\x2c\xdc\xc9\x6c\x9e\xe2\x59\xd3\xc2\x7c\xcc\x0a\xa8\x93\xba\x50\xec\xbc\xd3\x1b\xcc\xa2\xb1\x1a\xd2\x4b\xec\x96\x31\xce\xf4\x68\xd4\x78\x7d\xd5\x99\x3c\x8f\xdc\xe4\x9e\x14\xd2\x4b\xc9\x42\x85\xd4\x78\x1d\x8b\x3c\xf4\x7b\x1c\x01\xa4\xee\x48\xcf\xa5\x60\x54\x62\xbc\xef\xef\x40\xd6\x76\x2d\x8c\xfa\xd1\xd2\x27\x6f\xd1\x89\xc0\xaa\x61\x4a\xdf\xa6\x7d\x7a\x9f\x93\x6d\x18\x7b\x1d\xbd\x3c\x24\xdb\xec\x5e\x08\x55\xbc\x09\xa4\x05\xc4\x37\xc5\xd9\x8e\xaf\x5f\x92\xa0\x1a\x07\xbf\x3e\xc5\xef\xd8\x04\xad\x9a\x4b\xc2\x9e\x0d\xdb\xf1\x2c\xbe\x9e\xde\xde\xb9\x53\xf0\xe9\x55\x11\xd9\x22\xd0\x22\x80\xda\xa9\xf6\x86\x7a\x76\xe4\xcf\x60\xf7\x8e\x18\x96\x74\x40\x39\x84\x00\xdd\x28\x4e\x1d\x75\x9e\x2c\xa5\x56\x70\x9b\xd9\xfb\xf0\x42\x4b\xea\xe5\xcc\x88\x8a\x57\x75\x6d\xc8\xd3\x3e\xd3\x4e\xe4\xa9\x7e\xb1\xa2\x7c\xb5\x22\xda\x23\xfb\xd3\x1d\xe3\x9f\xaf\x4a\xf4\x06\x88\xbc\x5e\xf0\x2b\xc7\x27\xa0\xee\xb5\x32\xcd\x68\xe4\x9e\xa6\xd3\x3c\x08\x2b\x5f\xd0\xb4\xb3\xcd\x19\xb0\xe9\x08\x11\xb9\xbf\x51\x22\x78\xd1\x4d\x54\x97\xfd\x71\x90\x83\x77\x0e\xaa\x74\x9a\xfb\xc0\xc5\x10\x59\x3a\x78\x64\xaa\x66\xa2\x35\x77\x53\x03\xa9\x7e\xcb\x8c\x58\x12\xa0\xa5\xab\x56\x14\x15\x90\x66\x88\x88\x07\xb0\xb4\xab\xf0\x08\x10\xd3\xee\x15\xcb\x4c\xf3\x2a\x9d\xa7\x8b\xab\x15\xed\x5b\x87\xa8\x56\x48\xd5\xd7\x8b\x4e\x42\x47\xf4\x4f\xaa\x84\x77\xc9\x0b\xa4\xa9\xc6\xbe\xd2\xd9\xab\x87\xdb\x7b\xe8\xfb\x8f\x56\x21\x4a\xf6\x86\xe0\x24\x92\xd2\x04\x68\x23\xb6\x4c\x00\x0c\xca\x68\xcd\x05\x84\x41\x71\x64\x28\xfb\x39\xde\xe9\x85\x54\x52\xb5\x73\x6b\x40\x2b\xae\x24\x7f\x4a\x1b\x86\x84\x22\xa2\xf6\x47\x76\x66\x6e\x25\x7f\x2d\x4e\xd1\x4b\xb5\x65\xa1\x2e\xaa\x24\x3b\xdb\x17\x7d\xe0\xef\x6c\x2d\xe7\xe0\x9d\x9e\x69\xee\x2c\xdf\x3d\x16\xc8\x48\xc4\x0e\x6e\xf6\xf9\x11\x04\x58\x49\x6b\xca\xf3\x22\xbc\x68\xaf\x2b\x79\xba\x79\xd3\xe3\x85\xea\xb1\x76\xb6\x31\x67\x52\xee\x0e\x98\x20\x0d\x24\xa8\x3d\x34\xa1\x3d\x71\xe1\xfc\x17\x08\x33\x32\xad\xd2\x57\xeb\x6d\x69\xca\x5b\x86\xd4\x4c\xd1\x1f\x64\xa5\x09\xe0\x20\x54\x7b\x16\xba\x0d\xa3\xcc\x8c\x9e\xc7\xa3\xb4\x58\x43\x2e\x4d\x5b\xc1\xc2\x5b\xa3\xe3\x22\xcc\xe2\x58\x6a\x72\x86\x1b\x88\x7e\xa1\xad\xde\xbf\x07\xc3\xb7\x4c\x65\x2c\x33\xd3\xc4\x2b\x2b\xf0\xe7\x1c\x74\xcb\x27\x7d\x7e\x0b\xe6\x84\x34\x7d\x86\x01\xa5\xda\x61\xe5\x40\x32\xca\xe8\x3d\x41\x15\x2d\xad\xa7\xaf\x40\x44\x02\xf7\x32\x36\xea\x78\xf9\x00\x22\xf8\xa6\xd7\xb0\x29\xed\x7d\x9b\xbc\x73\xc3\xab\x99\x93\xf4\xaa\xcc\x77\x11\x2b\x18\x39\x30\x8c\xcb\x7d\x10\xe0\xa7\x12\xed\xf3\x3b\x4d\x33\xb9\x71\x42\x74\x3e\x82\x72\xe0\x4f\x75\x15\x7f\xb1\xf4\x7c\x3e\x3f\xaf\x42\x06\xba\x3c\xa4\x5e\x2a\x6d\x08\x2d\x2c\xfb\xc0\x63\x68\xe8\xd1\x9f\x7f\xdc\x08\x24\x27\x26\xf3\xe1\xae\x8c\x59\x26\xbf\xb9\xf1\x33\x7c\x80\x39\x41\xf4\x80\x94\x33\xcf\x1b\x07\xe6\xd7\xe5\xaa\xa9\x3c\x34\x1a\xf0\xb5\x09\x9c\x0c\x8f\xaa\xab\x9d\x14\x98\xe3\x23\xcf\xb7\xbf\x94\x85\xf4\x20\xf7\x12\x37\xa1\x97\x3a\xeb\x22\x11\x2a\x63\x91\x4f\x13\x11\x6a\xc3\x5a\xc5\x13\x0e\xcc\x7d\xd7\x1c\xfc\xca\xc1\xd7\xf7\xa1\x7b\x05\x7d\x8b\xcc\xa5\x53\x8a\x27\x22\x34\xc6\x62\x4b\x49\x85\x50\x84\xf0\xb9\x94\x84\x4c\x73\x58\x86\x0b\x91\x73\x29\x71\x4e\xaf\xce\xd0\x43\xe5\xf8\x49\xe2\x7c\x58\x79\xf0\xa0\x66\xfb\xb0\x6a\x8d\xa9\xfa\xa0\x27\x35\x27\xc7\xf5\x4f\xcb\xc1\x49\xe3\x1a\x48\x7b\x34\xb3\x36\xd3\xa9\xc4\x7e\xfd\x3d\xd0\x54\x3f\x9d\x8b\xdb\xe3\x69\x99\xbc\xff\x83\x9e\xa8\x32\x2b\xdd\x3a\x37\xf1\xc9\x1c\x2f\x39\x39\xc4\x48\x8c\x28\x75\xb4\x28\x15\x35\xdf\x66\x72\xba\xd8\x05\xa6\x2c\xf4\xac\x2c\xd2\xac\x78\xe7\xe2\x96\x43\x4b\xe2\x62\xa0\xef\xa5\x5d\x58\xab\x8f\x5f\xe1\xe5\x6f\x9e\xf6\x88\xaa\x72\x8c\xc5\x72\x08\x73\x66\xbe\x89\x3e\xee\xbb\xe7\x21\xf6\x0c\x4a\xca\xa5\x9f\x3c\x10\xa1\xf1\xd7\x6b\x86\xb5\xda\x7f\xf1\xa4\xf7\x61\xaa\x53\x90\x2c\x8b\x58\x72\x52\x1e\xf4\x20\xe5\x0c\x1a\xba\x53\x1f\x2d\x4f\x34\xf4\x18\xcd\xb6\xc1\x3c\x38\x99\x60\xc4\x35\x83\x02\x63\x8b\x52\x7d\x78\xa5\x6c\xf2\xa4\x50\xdf\xa3\x07\xd5\x42\x47\x05\x86\x3a\x65\xfe\xb9\x66\x84\x98\xd6\xcd\xf5\x29\xa9\xca\xc0\xf8\x44\xe3\xca\x4c\xf5\xd1\xfc\x43\xfe\x8f\x10\x06\x87\x44\x14\x46\x65\xe1\x7b\x95\xa5\x96\xeb\xa9\x1c\x6f\x16\x65\xdd\x3c\x6d\x88\xbd\xf3\x63\xd5\xa5\x5b\xae\xe6\xd2\x29\xeb\x22\xee\xc9\x45\xd5\x35\x8b\x45\x6a\xbe\x8a\xd4\x10\x72\x60\x6e\x7c\xe8\x4f\x1d\x31\x1b\x62\x91\x5a\x02\x91\x1a\x25\x5e\xb3\xb5\x9c\x6e\xae\x70\xd9\xdf\x44\x0a\x89\xe6\xe2\x33\x9f\x87\xb4\x4b\x51\xf6\x11\x62\x66\x61\xa5\x95\x96\x63\x50\xd2\xaa\x2b\x2c\xf6\x0c\x5c\x03\x37\x1d\x03\xbb\x70\x3e\x66\x80\x9a\xa8\xda\x3c\xaa\xda\x82\xa0\xda\x25\x67\x3e\x4a\x4e\x03\xaf\x8c\x61\xfb\x88\x61\x17\xa0\x6a\xf3\xbf\xc2\x67\x0e\x3e\x72\xed\x6e\x2e\x06\xfe\x0a\x5f\xf1\x8f\xf8\xcc\x7f\x89\x4f\xcf\x69\x72\x95\x8f\xed\x80\xb8\x29\x5e\xe7\xc0\xbb\x95\x37\xfe\x36\x87\x30\x98\x7e\xf1\x10\x0f\x5c\x6c\x89\x45\xa1\xf7\xe1\xeb\xd9\xe4\xc0\x7c\x85\x57\xaa\xf2\x79\xe3\x9e\x82\xc9\x15\xa8\xf6\x28\x39\xc3\xf1\x27\xd5\x4e\x27\xd5\x71\xa6\x8b\xa3\x89\x17\x47\x45\x4c\x47\x60\xb4\x47\xcc\x5c\x6c\x63\x52\x2d\xe9\x07\xbe\x9b\x48\x3d\x62\x17\x2a\xc3\xda\xfc\x15\x3e\xf3\x1f\xf1\x15\xff\x12\xdf\xb0\xd2\xae\x20\xbf\xa3\x8b\xab\x8e\xb2\xd4\xa6\x8f\x4e\x61\x8a\x1f\xb8\x8f\xbd\x6d\xf6\x67\xa3\xa9\xce\x51\x68\x24\x0a\x8f\x00\xbe\x82\x92\x78\xed\x57\x3b\x8f\x72\x09\xd0\x1b\x9b\x5c\x0c\x92\xa6\xe9\x73\x6c\x39\x26\x73\x3d\x3d\x82\x58\xd0\x42\x7b\xd2\x4c\x5e\xc7\xe0\x8e\xb0\xc0\xb0\xe8\x42\x59\xa0\x07\xdb\xb9\x06\x23\x0e\xfa\xaf\x82\x9f\x1c\x9b\xc3\x1b\x8e\x40\x5f\x2c\x30\x73\xc0\xf8\x04\xd2\x8c\x24\x31\x8f\xe7\x25\xd0\xa4\x67\xdf\x70\x72\xf5\x29\x31\xa2\x5a\xf8\x26\xde\xc0\x48\x10\xe6\x7b\x02\x49\xe0\x3e\x02\xd1\x01\x52\xcc\x8b\xda\xd5\x37\xdd\xd6\xef\xf7\x41\xd7\x4e\xaa\x38\x2b\x1c\x43\xb4\xe1\x19\x8e\x72\xc7\x2a\x73\xc4\x41\xb0\xb6\x2a\x64\xaa\x23\x26\x6a\x20\x6a\x38\xe6\x80\x94\x94\x9d\xc2\x19\xdd\x57\xa2\x23\x83\xbc\xc0\x88\x36\x9d\xc5\x25\x1d\x2f\x13\x68\xb2\x78\x65\xa5\x52\xb3\x77\xe5\x7e\xd0\x31\x5c\x4d\x9c\x65\x86\xeb\x33\x5f\x90\xba\xdb\x8a\xe7\xeb\xd5\xee\x33\x37\x7c\xa6\xd5\x69\x44\x09\x81\x21\x62\x8a\x74\x53\xb4\xba\xba\x32\x06\x37\x50\x3b\x5d\x52\xe4\x1a\x20\x7a\x25\x3c\xf7\x06\xac\xc7\xce\xab\x0f\x04\x47\xa5\x80\x61\xdc\x5f\xf0\x48\x47\xc2\x69\xac\x50\xdc\x1b\x33\x88\x56\x4c\x04\x18\x14\x28\xd9\x67\xe2\x23\x8a\xa8\xa2\xb1\x22\xa7\xb5\xad\x17\x12\x35\x57\xce\x68\xbd\x33\x32\x2e\x0d\x76\xe2\x5b\x24\x2a\xd3\x9b\xa6\xda\xd7\x78\x82\x6c\x90\x7f\x12\x51\x8d\x03\x80\x61\x1a\xa3\x9a\x2d\x34\xde\xdf\x4e\x0a\x87\x45\x92\xc0\x0b\x96\x2c\x39\x7b\x91\x54\xe4\x7d\x17\x82\x72\x2b\xde\xe4\xc8\x3e\x37\xfc\xac\x83\x24\x1d\x3e\x23\x65\xc6\xdb\x50\x97\x63\xe3\x9d\xa7\x31\x2d\x06\xdc\xe8\x4e\x2d\x77\x82\x7a\x31\x2c\x73\xd6\x97\xd2\x48\x25\x5d\x41\x4f\x49\xf5\x85\xe9\x8f\x25\x9e\x7b\xf4\xe1\x87\x2c\x8f\xa2\x7c\xf2\xf4\xd4\x53\x3f\x7a\xc9\x9e\x26\x27\x44\x96\xfd\xc9\x6f\x1f\x43\xe8\x2c\x55\xa9\x8b\x4f\xa6\xf2\xe3\x54\x82\x1a\xff\x61\xa9\xa1\x82\xd2\x0d\xe4\x7b\x6a\x11\xa9\x30\x17\xc3\x53\x1d\xd2\x41\xa5\x1b\xf4\x2b\x85\xc4\x8b\xa9\xdc\xe2\x39\xaa\x7c\x3b\x3e\xbf\x04\xb9\x80\x39\xdd\x44\xee\xd5\x28\xa1\x0b\xc3\xbd\x53\xca\xa4\xb9\xd7\xa4\xd3\xa1\xce\xe4\x77\xd8\xb5\x2d\x06\x23\x51\x00\x01\x6c\x31\x49\xf9\x4b\xde\xed\x39\x33\x1a\x0c\xf4\x72\x3b\xe7\x90\x92\x8e\x92\x21\x5f\xd9\x14\xce\xf1\x3a\x84\x24\xe2\x84\x30\x6f\xc4\x70\x5f\x36\xf5\x64\x68\x9d\xea\x39\x1f\x9b\x1e\xb1\xa5\x22\xe6\x6b\x4a\x1a\xa7\xb8\x5f\x6b\xfe\xe2\x92\x4e\xa1\xcc\x05\x6f\xda\x9a\xf7\x28\x54\x22\x43\xa4\x11\xd7\xb4\xe1\x34\xe2\xe7\x47\x9f\xd1\xd9\xf5\x1d\x06\xe0\xde\x48\x68\xa5\x59\x22\x89\xaa\x0d\x13\xbc\x0e\xda\x74\x8e\x80\x5b\x35\xb1\x9a\x38\x48\x8c\x11\x3d\x39\x11\xef\x63\x1a\x86\x8b\xd9\x85\xa9\x13\x4b\xc0\x63\x4f\xce\x22\x46\x50\xb7\x26\xb7\xfc\xde\x04\xca\x19\xde\xcf\x14\x4b\xa3\x5a\x94\xb8\x4a\xd5\x10\x10\x61\x43\x39\xe6\x28\xaf\xb3\xd6\x05\x4f\x85\x64\x39\x9a\x6d\x8b\x49\x17\x6e\xe6\xa4\x8c\x7f\xf2\xb7\x6a\x8a\x64\xfe\x6b\xc5\x13\xe5\xed\x67\xba\x01\x7d\xbf\xcb\x55\x25\x7a\x00\xa6\xbb\xb3\xe3\x3a\xf8\x2b\xcf\x2d\xdf\x6f\x30\xbe\xaa\x74\x8e\xe5\x28\xfa\x84\xe2\xed\x44\x46\x7c\xfd\x08\x80\x3d\xcb\x50\x24\xb5\xec\xfd\xbd\x2a\xeb\xa9\x9a\x73\xad\x6f\xd0\x6c\x14\x06\x2e\xc3\x34\xa9\xcf\x51\x70\x07\xdf\xfa\x98\xb8\x95\xc6\xad\x0d\x17\xf9\x86\x84\x25\xb2\x3c\x90\x1a\x91\xc6\x54\xea\x1e\x7e\xc2\x5d\x10\xb5\x74\xab\x04\x0c\x1f\x4e\x97\x91\x09\x09\xdc\x2f\x70\x77\x5a\x26\xc4\x7b\x39\x7c\x81\x81\xfd\xbd\xdb\x6b\x71\x9d\xc5\x55\x84\x58\xe5\x5d\xd3\x8b\xeb\xcd\x26\xd9\x19\x07\x41\xae\x91\x24\x6b\xb8\xde\x65\xbf\x2b\x87\xbb\x07\x3d\x71\xdc\xab\x1a\xc9\x6f\xd5\x5b\xfc\x38\x1b\xee\xc0\x0b\x61\xd8\xb2\x80\x85\xa5\xb0\x91\x59\x85\xec\xc8\xc4\x7b\xc2\x2f\xcb\xb0\xbc\x94\x67\xdb\x0c\x74\x16\xd0\x13\x8d\x70\x0e\x63\xd4\xb0\xed\x08\x6d\x49\xc8\xa3\x7d\xaf\xd0\x1b\xc5\x35\x17\x4c\x71\x89\x5e\xf7\x72\xca\x9d\x9e\xf7\x9a\xb8\xc9\x02\x48\x0d\xb3\x3e\x79\x70\xee\x46\x9a\x59\xc8\xe2\x6d\x01\x2b\xc3\x95\x1b\xad\x25\xe9\x2b\x83\x4f\xd0\x6c\xfa\xf0\xd3\xaf\x23\x58\x51\x9a\x7b\xef\xd9\x93\x9a\xd2\x65\x55\x7a\xd2\xbd\x4e\xd9\x49\x9b\xf8\x45\xdd\x73\xfa\x80\x6b\x46\x00\x33\x73\xaa\xa4\xb7\xd9\xc3\xcf\x36\x89\xd4\xe9\xc9\xd6\x30\x91\x56\x40\xd7\x6a\x1c\xa3\xb0\x8c\xda\x2b\x66\x26\x03\x0a\x50\x4c\x52\x9b\x0e\xca\x58\x85\xc1\xd6\x96\x87\xa4\xdb\xcf\x73\x26\xdd\xe8\x27\xcf\x06\x95\x02\x3e\x1c\x2b\x41\x1a\x81\xcd\x26\xc4\x6e\x9e\x2a\x6a\x27\xbc\xa1\xc3\x69\x84\x33\xa9\x28\x8d\x21\x2a\x8b\x9a\x67\x66\x6c\xa1\x8a\x53\x9a\xc2\xc5\x39\x99\x43\x33\xbf\xa9\x28\xc6\x91\x2e\x0e\xbd\x78\xba\xa8\xad\xea\x79\xb2\x3a\x26\x9b\xc7\x1e\xac\x85\x6b\xff\xb4\x58\x9b\x8e\x54\x94\x67\xc7\x57\xf0\x1c\xf6\x9a\x81\x2b\x16\x75\x16\x69\xa5\x51\x25\xa9\xd1\x7d\xee\x71\xcb\x79\x05\x9a\x4e\x5d\x38\x5f\x10\x8a\x36\x1c\x2e\xa0\x09\x13\xa2\x4f\x30\xc2\x59\x89\x45\xa3\xd9\x80\x99\x22\x70\xa5\xb3\xa9\xa9\x74\x5f\x27\xdb\x91\xa2\x51\x3b\x60\xa9\xfc\x54\x3c\x1c\xb7\x7a\x77\xe2\x10\xce\x2c\x44\x32\x4a\x82\x88\x3a\x58\x21\xae\x8b\x4a\x58\xc6\x33\x7c\xad\x4b\x56\xe7\x2d\x73\x2f\x48\x53\x88\xf2\x85\xca\x9f\x09\xca\x08\x80\xe9\x14\xca\x13\x1b\xab\xc4\x94\xb0\xe3\xe2\xdc\x2e\x8f\x94\x1f\xeb\x7e\xe9\x88\x97\xb2\xe0\x36\x12\xcd\x56\x65\xe8\x28\xd2\x2f\x8f\x44\xca\xed\xb3\x8a\xe7\x0d\xee\x42\x14\x03\x68\x0a\x2b\xab\x57\x91\x5d\x0a\xb6\x51\x4c\x00\x2c\xdf\xf7\x8b\x04\xdf\xb5\x19\xc8\x7a\x99\x85\x04\xbb\x95\x81\x77\x28\x6a\x89\x6a\xb2\x64\x7c\x7a\x9e\x98\xf9\xde\xef\x07\x9a\x56\x69\x05\x00\x1f\x03\x7d\xbd\x19\xe5\x9f\xfb\x31\x42\x99\xfc\xd5\x9e\x27\xfa\x77\x62\xf1\x77\x62\xf1\x7f\x43\x62\xf1\xb8\xf1\xeb\x9f\x66\x9f\x7f\x26\x02\x8e\x34\x5e\xf8\x2b\x6f\x3e\x0c\x4c\xb5\x6f\xbc\x5a\x5c\x19\x93\x77\xfe\xbd\xc4\xe2\x07\x3e\xed\x5f\xe2\xfb\x6f\x26\x16\xa2\x56\x98\xa2\x56\x18\x90\xca\xff\x4c\x04\x8c\x07\x8d\x9a\x8e\x29\x6a\x5c\x31\x69\x85\x31\x9b\x8e\xc0\x9b\xff\x5e\x62\xf1\x13\x9f\xf3\x2f\xf1\xfd\x9f\x49\x2c\x4a\x68\xa4\x08\x69\x4d\x2c\xb2\xef\x89\x45\x76\xd6\x94\x70\x3a\x9b\x82\x7a\x07\x46\x9d\x96\x54\x69\x52\x0b\x47\x22\x3a\x0b\xbc\xfa\xaf\x52\xe4\x14\x31\x7b\xc4\x72\xf1\x9a\x6f\x30\x1a\x9d\x05\x8d\x82\xb1\x38\xd9\x7b\xd1\x45\x3b\x05\x27\xf3\x81\x16\x84\xad\x71\xb8\x25\x36\xd0\xd5\x1d\xab\x27\x5c\x58\x4a\x56\xbe\x54\x2e\x34\x48\x22\x5d\x74\x3f\xf2\x89\x02\x15\xd3\xe6\x8c\x87\x55\x3c\x62\x14\xb9\x0c\xf5\xa0\x02\x14\xf6\x74\xae\xfe\xb5\x0a\xf6\xed\x10\x35\xc3\x44\xce\x6a\x2d\xdc\x4e\xb4\x7a\xd6\xcf\xcc\xf9\xce\x2d\x2f\x6c\x78\x7a\xf8\x1e\x18\x38\xec\xd5\x00\x0b\xc1\x5d\x54\x26\x6e\x80\x18\xc6\x3b\xfc\x21\xa8\x67\x24\xf7\x31\xe8\xc1\x2c\xa8\xba\x57\x74\x7c\x9c\xf8\x11\x05\xc5\x19\x46\x5e\xfe\xc2\x20\xa7\x0b\x71\x7f\x56\xcf\x1b\x7b\xa9\xee\xfc\x3d\x20\xbc\x10\xd5\xa6\xcb\x9b\x45\xcb\x21\xd4\xed\x26\x81\x67\x99\x47\x64\x48\x8f\xf5\x51\xbb\x74\xa7\x78\x22\x28\xde\xba\xbf\xd0\x97\x5c\xe4\x0f\x06\x03\xbc\x34\x19\xa4\xf9\x34\xf1\x2c\x8c\x3a\x56\x95\x8c\xdc\x8b\x83\x69\x66\xea\xc3\x40\x31\x8b\xbb\x8b\x2f\xea\xeb\xe1\x8a\x65\x46\x00\xcc\x3c\xd3\xdd\xe4\xd7\x17\xbd\x56\x40\x03\xde\xa7\xa2\x58\xc9\x66\x30\x92\x8b\xc3\x9c\x03\x3b\xb7\x30\xe3\x72\x81\x84\x73\xdd\x4b\xb4\x4a\x66\x51\x1e\x48\xee\x29\xcd\x49\x2d\xb2\xb4\x6e\x5f\x36\x57\xce\x27\xcf\x8c\x97\xc1\xcd\xe3\x4c\x9b\xd0\x29\xb4\x2d\x4d\x50\x9d\xe7\x95\xe4\xa6\xe8\x91\x82\xb5\xe5\x33\xef\x8e\x99\x62\x25\x7c\x49\x50\x9e\x25\xac\x93\x51\x9e\xa7\x89\xfd\x9b\x1e\xd9\x98\x2f\x42\xca\x98\x19\x4b\x08\x2a\xca\xe6\xee\x8d\x7e\x83\x14\x27\x85\x98\x13\x4c\x4a\xf9\xc8\xd3\xa6\x7d\xa5\x8d\xcb\x12\x09\xb2\x19\x9c\x6e\x4f\xa5\x09\xa8\x60\xf0\x71\x05\x12\xef\x2d\x18\x21\x70\x87\xea\x0e\xee\xc2\xa5\xdb\x5e\x49\x85\x6e\xde\x23\xc8\xb6\x50\xed\xdd\x3b\xdf\xe5\x91\xd7\x4d\x7c\x8d\xee\x69\xf1\x9f\xf0\xb2\x94\x69\xd2\xf5\x4d\x79\x15\x86\x2e\xe7\x94\xd0\x34\x65\xc1\xa6\x5d\x76\x9a\x60\x11\x90\x4b\xb5\xf3\x84\xcc\xd5\x5f\x97\xa5\x75\x4f\xe7\x91\x99\x88\xf7\x24\x0f\xb0\x49\x54\xa3\xb0\x20\xe5\x48\x01\x18\xa7\xb0\x80\x8a\x3a\x2d\x6c\x8e\x57\x30\x45\x1c\x8c\xf4\xce\xb5\x40\xc4\xc3\xbb\x65\x2e\x8d\x07\xd2\x61\x98\x3c\x00\x4e\x90\x4d\x55\x96\x10\xf0\x6e\x5f\x45\x16\x81\x5d\x1a\xae\xb0\x13\x15\x19\xc6\x90\xf9\x39\x38\xf0\x00\xe1\xc6\x69\xb4\xd4\x38\x6d\xd2\x94\xa1\x33\x6f\xa6\x5d\xa2\x27\xe0\x0d\xcf\xf9\x35\x25\xe1\x62\x80\x76\xd9\xbe\xf0\xb2\x9c\x94\x2c\xa1\x42\x0e\x8d\x04\xf5\x4d\x79\xf1\x43\x39\x3d\x95\x61\x6f\x29\x22\xe3\x9f\x68\x3f\xbf\xf6\x50\xa1\x5d\x9e\x74\x60\xda\x6e\xc8\x26\x8f\x34\x1f\xc1\x45\xcc\x04\xd1\x92\xa1\x60\xdc\x2f\x5e\x38\xdc\x65\x80\x61\x52\x5a\x1f\x69\x8e\x6e\x31\xf1\x29\xfe\xb9\xb7\xc0\x97\x4d\xfa\x47\x37\x27\xfc\x8f\x5f\x45\x15\xed\x90\xee\xa7\xaa\xfc\x5f\xff\x81\xb0\xed\x90\xee\xa6\xaa\xac\xdb\x5f\xbe\x65\x5d\xf7\xfc\x7f\x01\x60\x1c\xc7\xe3\x88\x1c\x9b\x77\x0a\xc0\x20\x08\xae\xc0\xdf\x76\x43\x9e\x8c\x4c\x33\xfd\xf2\x0d\xdc\x81\x3b\x0c\x43\x76\x30\x82\x1d\x91\x6f\xff\x81\xf0\xff\x81\xb0\x71\x72\x6f\x3f\x57\xc0\xcf\xcb\x67\xd0\x65\xbb\x7b\x5e\x96\xbf\x7c\xfb\x0f\x18\xb9\x6f\xff\xbe\xed\xe2\x5f\xbe\xa9\x30\x42\xed\x70\x24\x83\x88\x23\x39\x40\x20\x76\x82\x11\xea\x8a\x23\x4b\x85\x60\x47\x7c\x07\x66\x08\x7e\x44\x22\xe2\x48\xed\xc0\x1d\x84\x1e\xb1\x23\xb5\x83\xa8\x23\xbe\x83\x8f\x78\x4b\x1d\xe1\x1d\x7a\x84\x76\x10\x7c\x84\x76\xc4\x11\x0a\x60\xf4\x88\x62\xbb\x4f\xbb\x52\x06\xed\xf0\x23\xbc\x83\xc0\x15\x0e\x3c\x12\xd8\x57\xfb\x19\x82\x8e\xe4\x67\x26\x8a\x1d\x71\xea\xab\xdd\x86\x0e\x5f\x43\xd4\x0e\xc6\x8f\x18\xf9\xd5\x7e\x86\xbe\x10\x92\x3b\x04\x3c\x62\xd4\x57\xfb\x35\xeb\x43\x06\x12\x1d\xb0\xe3\x86\xfe\x00\x41\x47\x6c\x07\x1f\x89\x03\x44\x1d\x91\xf5\x22\x5b\xaf\xa0\x2b\x84\x93\xd9\x01\x22\x8e\xd8\x67\xa3\x2b\x4e\x0c\x0a\x10\xf2\x88\x10\xbb\x4f\x0b\x7e\x70\x42\xc7\x95\x18\x64\x07\xe1\xdf\x9b\xcf\x00\x7e\x24\x0f\xc8\x91\xd8\x41\xc8\x11\x41\xbf\xda\xcf\x08\x72\xc4\x0e\xd8\x91\xdc\xc1\xd4\xba\xd3\x4f\xfb\x85\xec\x40\xac\x7c\xc3\x8e\x38\xf9\xd5\x6e\xfd\x87\xb5\x9f\xd8\x41\xf0\xfa\xfa\xf4\x20\x47\xfc\x80\x1d\xb1\x1d\x44\x1c\xa1\xef\xed\x67\x04\x3f\x52\x07\xe4\x88\xee\x50\x68\xe5\xc8\xa7\xfd\xc2\x02\x1e\xa9\x03\x74\x84\xb3\x03\x44\x1e\xb1\x2b\x04\xa1\xd9\x7a\xb1\x54\x10\x44\x1d\xa9\x03\x06\x0d\x10\x76\x44\xb2\x03\x4a\x1d\xe1\x2b\x04\x92\x19\x8a\x1f\x91\xb5\x0f\xcd\x0e\xeb\xe5\x0f\x9e\x90\x57\x1c\xc9\x70\x62\xa9\xe0\x95\x2d\x04\x7c\xa4\xa2\x23\xb9\xc3\x8f\xd4\x0e\x59\x79\x00\x1d\xa9\x1d\x71\x44\x77\x10\xd6\x42\xe0\x4a\xc9\x4a\x3b\x79\xc4\xd7\x8b\x00\x81\x8f\x38\xb4\xfb\xb4\x5f\x9b\x06\xbf\x38\x08\x83\x47\x0c\xfe\x6a\xbf\xf3\x10\x3f\x20\xeb\x2e\x7f\xee\xfc\x8b\x7b\xf0\xaa\x62\x20\xf9\xd5\x82\x3f\x24\x8f\xae\x22\x80\xbe\xb7\x9f\x7d\x1f\x89\x03\xba\xea\x24\x7c\x24\x89\xaf\xf6\x33\x00\x1f\xf1\x03\xba\xa2\xc7\x57\x0d\xf9\xb4\x9f\x11\xec\x08\xad\x2c\xde\x21\xd8\xfa\xfa\xf4\x91\x47\xf8\x00\x1f\xd1\xf2\x00\x21\x47\xf4\x00\x1f\xb1\x80\xa4\x8e\x04\xbe\xfb\xb4\x5f\xfa\x85\x6e\x13\x89\x1d\x82\x1c\x31\xe8\xab\xfd\x1a\x02\x8f\xe8\x47\xec\xf0\x11\xfe\xde\x7e\x27\x1b\x39\x90\xab\xbe\xae\x96\xb2\x35\x9f\x7e\xf8\xb8\x69\x2c\xb1\x83\xf1\xf5\xf5\x65\x13\xd0\x11\x39\xc0\xf0\x11\xdd\xad\x66\x87\x7d\xb5\x5f\x63\xf0\xa6\x16\xf8\x0e\xc7\x8e\x24\xf5\xd5\x7e\x0d\x61\xab\xb2\x1f\xc9\x88\x38\xae\x9c\x5c\xf5\x71\xb5\x20\xf2\x08\xef\xd6\xad\x20\xe8\x11\xc5\x77\x9f\xf6\xc7\x3a\xd4\x0e\x5f\x8d\x83\x3c\xc2\xd0\x57\xfb\xdd\x62\xa9\xdd\x6a\x2d\xe8\x66\x9a\xf0\x77\x7a\x77\xc8\x2a\x16\xa8\x3c\x40\xf8\xba\xcd\x23\x1e\x1d\xa0\x6d\xcf\xab\x42\x12\x2b\x03\xe0\x03\xb1\x6e\x09\x39\x42\xed\x81\xdc\xc4\x82\xac\xc0\xd0\x7a\x11\xa0\xc8\x91\xda\x6d\xcd\x0f\x75\xc5\x76\xd0\x6a\xa6\xd4\x11\x25\xbe\xda\xef\x3a\x4e\xee\x90\xe3\x46\x23\x8e\x7c\xb5\xdf\xed\x82\xd8\xa1\x47\x7c\xf5\x43\xab\x76\xa0\x3f\xb4\xe3\xb0\x62\xc2\x8e\x68\x04\x7e\xc6\x8f\xf0\x6e\xc5\x41\xac\xea\x87\xb4\xeb\x8e\x36\x23\x85\x77\xd8\x11\x29\x57\x2f\xb6\x83\x8f\x64\xb4\x5a\xf7\x0e\xfe\xd0\xb0\x0e\xe1\x9b\xe7\x5a\xe7\x60\x2d\xf1\xdd\x39\xad\x17\x30\x74\x44\x03\x04\xda\xbc\x03\xf4\xdd\x3b\xac\x12\x44\x57\x18\x64\xb5\x66\x98\xf8\x6a\xbf\x5b\x3a\xba\xa3\xd6\x7d\x6c\x9e\x0b\xf9\x95\xff\x82\xd6\x59\xf8\x11\xdf\x61\xdb\xeb\xab\x93\xd8\xdc\x13\x1a\x6d\xea\xb7\x2a\xef\xaa\x83\xe4\x01\x81\x8e\xf8\x81\x3c\x62\xed\xea\xc9\xa8\x55\x01\xd1\xc3\xa6\x06\xab\x6d\x66\x10\xb9\x7c\x03\x7e\xcf\xbb\xa3\x38\x95\x04\xf0\xc7\xbb\x23\xe0\xe6\xb9\xd0\x92\x44\x77\x28\x79\xc4\x76\x24\x7a\x58\xff\xbf\xe2\x44\x79\xf8\xba\x3e\x7c\x8d\x0d\x14\xf1\x07\x18\xf1\x20\x0a\x62\xe8\x83\x11\x02\xb1\xd5\x06\xc0\x23\x54\x1e\x56\x6b\xc7\x8e\x70\x00\x91\x47\x88\xda\x7d\xda\x8f\xba\xac\xb6\x8c\x94\x38\xb8\xfa\x8d\x0d\x02\x3d\x62\xd8\xee\xd3\x7e\xe9\xe0\xba\x69\x70\x03\x39\xfc\x11\x92\x03\x72\x44\x14\x08\x46\xb6\xe5\x7e\x8b\xe3\xc3\x38\x70\xa9\x3e\x1b\x80\xbf\x13\x84\xaf\xa0\x04\xb2\xfb\xb4\x1f\xd0\xd5\x47\x41\x58\xb9\x8a\x14\x0c\x20\xec\x88\x11\xbb\x4f\xfb\x59\x0a\x5e\x05\x7e\xc4\x7f\x4d\xce\x3f\xa3\xd8\x91\x47\xfc\x00\x61\x57\x82\x3a\x52\x01\x0c\xee\x60\xf0\x87\x22\xac\xd6\x87\x2f\xd5\x01\xc2\xc0\x23\x79\x44\x7f\x8b\xff\xf0\x85\x7f\x20\xc0\x75\x18\x3d\x22\x9b\x02\x23\xe4\x4f\xd4\x2b\x75\xbf\xe2\xd7\xef\x51\xb8\xae\x32\x1c\x7e\x1f\xc5\xe1\x43\x9d\x82\x90\xab\x87\x26\x8f\x7f\x24\xca\x5f\x2b\x07\xb4\xce\xdf\xc1\x54\x49\xac\x27\x26\x8a\x1c\xd1\x81\xc4\x8f\x44\x79\xf8\xf1\x7e\xbb\x3a\xac\x57\x57\x02\x5e\x65\xf1\x35\xa3\xda\x4c\x18\x29\x7f\xa5\x3a\xff\xac\x61\xc3\x81\xfa\xa9\x62\xff\x26\x31\xd4\x0e\x42\xd6\x23\xec\x08\xd3\x10\x76\xc4\x57\x9e\xac\xed\x87\x01\x14\xb9\x83\xd6\x33\x78\x58\xc7\x83\xdf\x8e\x43\xd8\xea\x88\xb0\x23\x91\xfd\xf1\xf8\xd6\x0c\xbf\x3b\x7e\xf8\x31\xbe\x54\xe0\x0e\x47\x8f\x58\xf6\x63\x21\x6c\xf7\x69\xbf\xbc\xcd\xea\x5a\xc8\x72\x63\xc5\xea\x63\xd7\x8b\xf5\x04\xf9\x03\xd0\x03\xb9\x54\xe4\x7a\xb2\xad\x8c\xc8\x0e\xab\x76\xfe\xd3\xda\xe0\xe1\x37\xb4\x41\xc8\xee\xd3\x7e\x94\x0c\xde\x11\x47\xbc\xfc\x5a\x08\xb9\x42\x28\xb9\x6a\xdb\xf6\x96\x5a\xc1\xd7\x03\xf9\xf8\xfd\x4c\xdc\x80\x7f\x77\x93\xe0\x4f\x26\x64\x47\xfc\x8a\x13\x47\x58\x81\xc8\xf5\x50\xc2\xa8\xa5\x3a\xe0\xd4\x91\x3c\xa0\xe0\x2a\x67\x10\x5c\xc3\xae\x0d\x37\xb1\x91\x42\x7c\x27\xe5\xb3\xfb\x23\x94\xfd\x2e\x73\x76\x9f\x1d\x97\x87\xef\xb4\x2e\x2a\xba\xfa\x64\x8c\x3c\x52\x9f\xce\x1d\xb9\x06\x1e\xf8\x11\xc9\x7e\x8f\x13\x3f\xa5\xf8\x25\x66\x7c\x3b\x05\xf0\x9f\xa7\xc0\x7a\xce\x10\xcb\xea\xd8\xa8\x1d\x84\x92\x2b\x43\x57\x74\xf0\x77\x79\x20\xff\xcc\x8f\xdd\x3a\x03\x1f\x7e\x57\xab\xc0\xdd\x77\x3c\x7f\xa0\xa1\x20\x89\x84\x18\xfa\x6d\xeb\x38\x34\xcf\x20\xca\xbb\xf9\x97\x6f\xe0\x11\xc2\xfe\xc1\x84\xd6\xd3\x65\x55\xf8\xd5\x29\x7e\xd7\xff\xf5\xdd\x7f\x11\x2b\xf8\x1d\x2b\x45\x6e\xd1\x0e\x72\x24\xbf\x9b\xd1\xee\xb7\x38\xd7\x5c\x60\xbd\x02\xe9\xff\xf1\xdf\xc9\x52\xaa\x3c\xfe\x87\x24\xe5\xbf\x3a\xbd\xf8\xa3\xe7\x84\xfc\x4e\x8e\xf3\xff\x45\x59\xf0\x6e\x93\xee\x97\xbe\xbb\x93\xdf\x13\x9e\x3c\xfe\xe5\x9b\x12\xcc\xc9\xfb\x3f\xe1\x6f\xff\xe5\xec\x87\x58\xf3\x01\xf0\x2b\xf5\x69\xbb\xb9\x4c\xbe\xb8\x53\xe6\x75\x12\xbc\xc5\x77\x10\xe7\x49\xdd\x6d\x8b\x58\x57\x51\xe2\xfe\x13\xfa\xcf\x6f\xbb\xf4\xab\xdb\xa9\xf3\xae\xfd\xe5\x5b\xdf\x26\x6f\xeb\x19\x44\xc9\xa5\x76\xda\xe4\xdb\x6e\x82\x7e\xf9\xb6\xa6\x05\xdf\x76\x33\xf4\xcb\x37\x08\x84\xbe\xed\x26\xf8\x47\xd7\x7a\x75\x04\x57\x59\x7d\x47\x63\xbf\x83\xba\xbd\x37\xef\xea\x97\x6f\x55\xd0\xbd\xf3\xe9\xff\xf9\x84\x4d\x07\x68\x8b\x81\xe1\xff\xf9\x83\xbe\xe6\xb9\x6b\xee\xf7\x95\x03\xdf\xc0\x6f\xbb\xf5\xfd\x21\x6a\xca\xe6\xbd\xa9\x45\x02\x47\x71\x82\x7e\x17\xef\x3f\x00\x1f\x21\xe2\xb7\xe0\x60\x14\x24\xf0\xef\x83\x23\x10\xf2\x1b\xf8\x38\x8c\xc0\x38\xfe\x7d\x78\x14\xfd\x2d\xfe\x18\x0e\xa1\xf8\x0f\xc8\xc1\x08\xec\x37\xf0\x11\x41\xc5\x11\xf1\xfb\xf0\x38\x45\xfe\x06\x3e\x0c\x48\x34\xa4\x7e\x1f\x9e\x84\xa8\xdf\xc0\x07\x21\x4e\x06\x7f\x00\x4f\x21\xe8\x6f\xe0\xa9\x08\xc5\x28\xf2\x77\xe1\xa1\xdf\x02\x23\x70\x40\x26\x3f\x4c\xeb\x1f\xb5\xe7\x57\x36\xbc\x9a\x27\xba\xe5\x28\xe5\x1a\xf4\xe1\x47\xe2\x4a\x51\xa7\x35\xa9\xca\x50\x6c\xf9\xf6\x65\xe3\xab\xfa\xff\x07\x8c\x7c\x57\xb8\xff\xf9\x0f\x6e\xe0\xdf\x41\xf1\x2b\xaf\xb0\x92\xfa\x6e\x8a\x64\x23\x93\x24\x61\x84\x44\xbe\x77\x1d\xc6\x3c\xee\xb2\x5f\xbe\xc1\xbf\xc1\x4f\x1c\xb1\x1d\x05\x1d\xa1\x2b\xb1\x26\x85\xf8\x11\x2a\xd7\x94\x07\x5a\x13\xae\x35\xbd\x5c\x2f\xd6\xde\x2b\x05\x65\x07\xe4\x48\x5e\x09\x6c\xcd\x7e\x36\xb7\x89\xaf\x3d\x54\x79\x40\x57\x37\x8c\x5f\x29\xe8\x44\xac\x89\x24\xbc\xce\x05\x3f\xf8\xd0\x2b\x09\x96\x6b\xce\x44\x1e\xc9\x0c\x3b\xa2\x0a\xba\xc6\xd2\x04\x55\x7e\xa2\xe6\x6c\x4d\xe2\xca\x35\x87\x3d\x50\x47\x64\xcb\x58\x91\x23\x32\xe0\xd9\x01\x5d\xaa\x35\x4e\xde\x81\x0a\x4a\xed\x08\xe8\x88\x64\xe8\x11\x55\xb0\x2d\x6c\xc0\x4b\xf4\x13\xe4\x12\x19\xba\x86\x16\xc4\x27\x11\x24\xb3\x35\x83\xf8\xc1\xd9\x4f\xf5\xe2\xdb\xbf\x32\x72\xf8\xdf\x33\xf2\x35\x47\xfa\x18\x39\x06\x1e\x41\x18\xf9\xd8\xf9\x57\x2f\xfc\xb3\xf7\xbf\x65\xe8\x1f\x5f\xf1\xcf\xfa\x86\x23\x28\x05\xfd\x9b\xca\x49\x80\x10\x82\x87\xff\x5b\xe5\xfc\x43\x4e\x20\xff\x26\x27\xa0\x23\x06\x41\x5f\xbc\x80\x8e\x04\x84\x7f\x78\x81\x63\x47\x78\xeb\x87\x7f\xf6\xff\xf5\xb9\xf1\xc3\x0e\xf0\xf5\x78\xc6\xb0\x23\xb6\xe6\xab\xc4\xe1\x08\xaf\xda\x78\x38\x22\x5b\x15\xe0\x88\x1c\x88\x23\x72\xf8\xa4\xad\xc8\x1a\x9f\x1f\xa0\x2d\x57\x3f\x12\x16\x4c\xad\xa9\xf6\x6a\x34\xf0\x3a\x86\xa3\xd1\x3a\x73\xcb\x72\x91\xc3\x27\x2d\x5b\x33\xc0\xc3\x16\x95\x23\x87\xad\x20\x84\x1d\xa0\xc3\x1a\xbe\x6c\x89\x3a\x71\xd8\xf0\xad\xab\xae\x70\x6b\xaa\x72\x24\x0f\x47\x6a\x07\x7f\x95\x44\x56\x42\xa0\xe3\x56\x4c\x39\x42\x5b\xaa\x4e\x1c\xf1\xdd\x9a\xb9\x13\x47\xe8\x53\x5c\xc2\x0f\x47\x74\x07\xaf\xf9\x2d\xb6\xc3\xd7\x7c\xfa\x53\x6d\x5b\xb3\xc3\xcd\x36\xd6\x0b\x7c\x43\x74\x84\xd7\xcc\xfd\xf0\xa9\x8e\x21\x3b\xb0\x3a\x50\x6b\x5c\x83\x1d\x91\xe8\x88\x6d\xdd\xdb\x7e\x77\xd0\x06\xb4\xb1\x81\xf8\x6c\x7f\x45\x0b\x1d\xe1\x03\xbe\x75\xaf\x89\xe6\x6a\x85\xc4\x0e\x5e\xdf\xef\xd0\xdd\x11\x5d\x93\xe0\x75\x2a\xbc\x43\x37\x0a\x88\x6d\x4b\xd8\xa7\x22\x01\x1f\x89\x0a\xde\x6a\x6f\x19\x74\x84\xa2\x95\x94\x95\x4b\xd0\x07\xdb\x56\x94\xc2\x56\x86\x6c\x35\xbd\x4f\x31\xed\x48\x2d\x15\xb2\xd1\x91\x41\x47\xec\x8a\x90\x6b\xa0\x8d\x44\xe0\x6e\x65\x1d\xfa\xb5\x8b\x35\x0c\x47\x77\xe0\x46\xfd\x3a\x17\xfc\x70\x69\x13\xde\xaf\xf1\x6f\x73\x87\x0d\x7c\xab\xf7\xad\x71\x25\x15\xfd\x06\x6c\xab\x56\x6c\x0c\xdf\xea\x03\x1f\x4e\xae\x84\x1c\xd6\x1d\x46\x47\xe2\xb8\xe6\x57\x1b\x75\x2b\xbb\xd6\x68\x91\x88\x3e\xb4\x7f\xa4\x84\x6f\x42\xf8\x4c\xd9\x3c\xe8\x11\x5a\x29\xc6\x0f\x1b\x22\xf4\x43\xf2\x11\x3b\x7e\xa6\x7c\xd8\x0d\x6f\x2f\x7c\xd5\x94\x0f\x1a\x6a\xdd\xcb\xaa\x33\xeb\x28\x75\x44\x57\x5c\x2b\xcd\xe4\x46\x30\xb4\x6d\x71\xa5\x0f\xd9\x81\x87\xd5\xdb\xae\xaa\xb9\x92\xb5\xd1\x7b\x58\x89\x5c\x77\xfb\x5d\x11\x8e\xd0\x52\xc1\xe4\xaa\x7c\x68\xb4\x6e\x17\xf9\x88\x79\x63\x15\x75\x5c\xe5\x89\x7f\x76\xf4\x87\xa4\x20\x1f\x61\xad\x88\xb7\x6d\x7d\x0a\x23\x1f\x96\x7f\x89\xe1\x3b\x08\xb9\x4e\xdb\x3a\x57\x76\x64\x87\x23\xf5\x59\xf3\x43\x36\x72\xd8\x14\x18\xda\xca\x86\xd4\x56\x8b\xda\x2a\x5c\x5b\xc5\x6c\x1d\xdc\x0e\x83\x15\xcf\x7a\xfe\xac\x81\x39\xb1\x62\xc4\x76\xd0\x47\xf3\xd1\xad\x60\x80\x6f\x65\x1c\xf2\x88\xa8\xc8\x57\x95\x13\x8f\x8e\xd8\x71\xab\xd1\x6c\xda\xb8\xb1\xf8\x8b\x51\x1f\xf2\x56\x66\x6f\xd2\xa0\x56\xe2\xe0\x8f\xb0\x56\x26\xad\x92\x3d\x7e\xf2\x20\x2a\x3a\x52\x1b\x30\xfc\x99\xb3\x6d\xe2\x27\x3f\x37\xaf\xb0\x11\x8b\x7d\xf1\x17\xfa\xd8\xe5\x52\x1d\xb0\x23\xb2\xd2\xb0\x1d\x7d\xab\x7f\x58\xcd\x71\x35\xce\x55\x25\x3f\x62\xc6\x7e\x20\x3b\x6c\x72\x81\x7f\x60\xdb\xe4\x76\xa4\xb6\xde\x0f\x83\xd7\x43\x19\x3e\x41\x44\xb4\x0d\x7c\xe4\xf0\x13\x1e\xdd\xd6\x85\x3f\x68\x90\x55\x7a\x1b\xe6\xdd\x77\x1f\xb1\x59\x0d\xba\x83\xa2\x35\x37\x5f\x05\xb4\xd5\xe9\xa0\x23\xfa\x95\x92\xed\x56\xd8\x95\x78\xf8\xb8\x55\xd4\xe0\x03\xba\x52\x87\xad\xa7\xf9\x11\xda\x6a\x72\x2b\x6b\xe0\x8f\xad\x7f\xbc\xdd\xca\xda\xcd\x4e\x56\x6f\x81\x2c\xd5\x3a\x81\xfc\x61\xc8\xd8\x47\xda\xf0\x56\x4e\x85\x56\x4b\xc3\xa2\xcf\xee\x7f\xf2\x62\x63\xd2\xe6\x22\xa2\xad\xf8\xb8\x51\x8e\x7e\x8c\x6d\x5b\x71\xc3\xb2\x8a\xf6\xb0\x21\xfa\x68\x13\xba\xb2\x74\xb5\x83\x95\xf9\x9f\xff\xb0\x4d\x8d\xbe\xd4\xe1\x63\x79\xeb\x32\xd8\xb6\x0c\xba\x85\x10\xe4\x07\xdd\x4a\xc1\x2a\x63\x6a\xb7\xb9\xc9\xe3\x56\x45\xdd\xe6\xc3\x3b\xf4\xbb\xd2\x6e\x75\xe1\xcd\x6c\xc8\x4f\xe1\xe4\x93\x8b\xaf\x5e\x0d\x39\x6c\x6e\x1b\xfb\x18\x21\x75\x24\xb7\xcf\x33\xb0\xcd\xf1\xe3\x2b\x89\xbf\xa2\xf3\xf0\x63\xbf\xc4\x97\x8a\xaf\x7e\xf3\xb3\x27\xf4\x48\x55\x5b\x72\x8b\x6c\x9e\x0c\x8a\xd6\x75\x3f\x5e\x07\xfa\x6e\x26\x3f\x9d\xd3\xba\x27\x74\x58\x1d\xdd\xba\x9b\x0f\xba\xd5\xa5\x80\xc3\xc6\xd7\xc3\xb6\xf4\x87\xd9\xeb\xae\xe1\xa5\x22\x36\x5f\x80\x66\xd0\xa7\xe6\x81\x7d\xdc\xe4\x11\xfa\x28\xe3\xa6\x90\xd8\xe6\xf5\x0e\xd0\x8a\xf7\x57\x24\xa0\xdf\xd5\x7a\xfb\xef\x37\x2e\x67\x95\xdd\x8a\xe7\xcb\x3d\x7c\xd4\x8b\x58\x37\xfd\xb5\x33\xea\xbb\xc3\xc0\x36\x54\xe4\xe1\x3b\xc6\x8d\xb5\xf8\x47\xaf\x3f\x2e\x03\xdd\xad\x8b\x63\x1f\x0f\x8a\x7f\x6c\x02\xf9\xdf\x4e\x27\x3f\xd3\xd1\x45\x85\xb0\x1d\x46\x44\xbf\x16\x3e\xb1\x19\xc3\x2a\xbe\x8d\xe6\x4d\x49\x37\xb6\x23\x9b\x67\xd9\x0e\x90\xe8\x23\x13\xf4\x48\x7e\x38\xf8\xf9\x6c\x6a\x73\x6f\xbb\xcf\x07\x36\xc4\xe1\x4b\x7b\xc9\xcf\x8c\x0f\xa9\xeb\x01\x1b\x41\xdf\x61\xc9\x2f\x58\xea\x87\x2b\x43\x7f\xe5\xca\x7e\xfa\xf9\x4d\x66\x44\xf4\xdd\xd1\x23\x3f\xdc\x0e\xb9\x49\x6c\xb7\x91\x8d\x7f\x4e\x38\x64\x7d\xbf\xaa\xfd\x77\x5e\xab\x10\xbe\xc3\xc1\xd5\x19\x7e\x59\x03\x7c\xd8\x3c\xcc\xba\xee\xaa\xb6\x9f\x53\x7f\xf7\xe3\x54\x84\x3e\x21\x42\xb4\x49\xf8\x08\x7d\xb9\x2d\x64\xdd\xc7\x4f\xf7\xb5\xee\xee\xeb\x7c\xda\xbc\xf8\xba\xfe\x67\x2b\x47\xf2\xbb\xd7\x5b\x8f\x26\xf2\x1f\x9c\xc7\x76\xa2\x7c\xef\x5b\x6d\x71\xd3\x94\xaf\xa3\x65\xd3\x39\xea\x8b\x42\x68\xb7\x61\x5b\x55\x50\x85\xa8\x1d\x0e\x7f\xd4\x6f\x5d\x6e\x3b\x92\xf0\x8f\x38\x3f\x42\x86\xbe\x4e\x9c\x8f\x8f\xfe\xda\xc6\x6a\x4c\xab\x45\x20\xdf\x1d\x1d\x72\xf8\x3a\x84\xbe\x1f\xd8\x9b\x0c\xbf\x9c\xf2\x17\xbb\x7f\x37\x75\x42\x7e\xa6\x4e\x7f\x18\xe0\xa2\xff\x5e\x80\xbb\x66\x5c\x38\xf5\x09\x70\x09\xf4\x08\x83\x5f\x01\x2e\x46\x1e\x89\xad\x1f\xfe\xe5\x1b\x49\x1c\x09\xf0\xbf\x1b\xe0\xfe\x36\xaf\xbf\x53\xc9\xfd\x8e\xff\x41\xa2\x4e\xfc\x36\x31\xbe\x93\x49\x7c\xc7\xfe\x20\xf1\x86\x7e\x1b\x3d\xdf\x91\x04\xbf\xff\x7e\xf4\x7c\xc4\x21\xf8\xb7\x85\x83\x28\x0e\x93\xf0\x8f\x12\xf5\xdf\x82\x23\x51\xf4\x47\x75\x06\x02\xfb\x9d\xba\x01\x11\x92\xf1\x1f\xd4\x01\xc8\xdf\xa9\x63\x44\x41\x00\x45\x7f\x54\x07\x20\x7e\x1b\xff\x87\x11\x49\x86\x7f\x40\x3e\x05\xff\x16\x3e\x48\xf0\x28\xf8\x23\x78\xfc\x77\x92\x91\x3b\x1a\x53\xbf\x0f\xff\x67\xd6\x0d\xb2\x03\x4c\x5c\xa1\xdf\xd7\x7b\xf4\x5f\x96\x0c\xfe\x61\xf6\x7f\xb5\x5a\xf0\xbd\x63\xa5\xf6\xd1\xe4\xf5\x2f\xdf\xc2\x64\x48\xca\x7f\x2a\x2c\xfe\xf7\xaa\x8a\xcd\xdf\x65\xc1\xbf\xcb\x82\x7f\x97\x05\xff\x5a\x65\xc1\x35\xc3\xfa\xd3\xca\x82\xf8\x96\xef\xad\x51\x1f\x75\x24\x23\xf0\x00\xef\xb6\x62\x1f\x71\xa4\x0e\x9f\x3c\x18\xfa\x1e\x63\x6d\x49\xd7\x1a\xef\x90\x9f\xc0\x6b\x8d\xde\xd7\xb0\xfe\xab\x2c\xf0\xc9\x0b\xe1\x35\xfc\x20\x77\xe8\x16\x23\xee\xd6\x58\x6a\xcd\xbe\xa8\x1d\xb1\x7d\x4c\x4f\x7c\x6e\x18\xda\x6e\x3e\x20\x76\xe8\xe7\x7e\x9e\x1d\xb1\xc5\x60\xc8\x16\x66\xec\xb0\x2d\xbe\xc7\x77\x9f\x1c\x61\x03\x3e\xa0\x9f\xc9\x87\x2f\x24\xed\x9a\xac\xac\x21\x09\xf1\xc9\x93\xa2\x2d\x3c\x5d\xff\xe0\xaf\x5b\x16\x3e\xc0\xe8\x52\xa1\x5b\xc4\x12\x81\x5b\x21\x04\xdb\xad\x41\x14\xbe\xdb\xee\x2c\xda\x7d\xcf\x59\xd7\xa0\x79\x6b\xdb\x2d\x64\xc6\xb7\xfa\x08\x11\x6d\x69\xdc\x16\xba\xc2\xdb\xd6\xf1\xed\x9e\x16\xf0\x13\xd8\x62\x87\x4f\x72\xb3\x66\x1f\xd0\x16\x16\xc1\x9f\xc8\x77\xeb\x27\xda\x03\xb2\x3b\xe2\x87\x0d\x6b\xf4\x95\xe6\x6f\x61\xfc\x6e\x03\xda\x6d\x89\x01\xbc\x09\x0d\xdc\x4a\xa4\x87\xad\x44\xfa\x55\x45\x25\xfe\xae\xa2\xfe\x5d\x45\xfd\xbb\x8a\xfa\x77\x15\xf5\xef\x2a\xea\xdf\x55\xd4\xbf\xab\xa8\x7f\x57\x51\xff\xae\xa2\xfe\x5d\x45\xfd\xbb\x8a\xfa\x77\x15\xf5\xef\x2a\xea\xdf\x55\xd4\xbf\xab\xa8\xff\x17\x56\x51\x9f\xc8\x5f\xeb\x5b\xe9\xf5\xf4\xf3\x07\x96\x48\xea\xf3\x34\xea\x77\x40\x78\xee\xf4\xb4\x5a\xc1\x97\xc2\xab\x71\xa7\x4c\x5e\x60\x4e\x85\xcf\x98\x92\x7e\xce\xd0\xf1\xad\x21\x5c\x7b\x43\x55\x5d\xd4\xc9\x10\x18\x1d\x56\x3a\xf1\x23\xc6\xfb\xe0\x08\xa2\x0d\x25\x29\x91\xc9\x8b\xd5\x78\x4d\x03\x2f\x0c\xbd\xb8\x8e\xe1\xd0\xd3\x26\x3d\xc8\xc4\x39\x5a\x92\xb0\x5b\xde\x0b\x32\x24\x14\x45\xa0\xa0\x6b\x9a\xa7\xc2\xad\xb1\x28\x09\x7b\x34\x3a\xe1\x96\xea\x13\x09\xf8\x30\xe9\xd3\x9b\x8a\x10\x77\x6a\xaf\x43\x94\x54\x55\x38\xb7\xd4\x6c\xe3\xfb\xfe\x74\x26\x9b\x40\x4f\xee\xf3\x33\xd6\x39\x0e\xf3\xab\x0c\x1b\x61\x7c\x54\x0b\x3e\x6b\xc8\x73\xc7\x75\x3d\x7f\xb9\x09\xec\x7b\xd0\x00\xb4\x3f\xdf\x34\xf1\x04\xda\x18\xc5\x61\xa4\x07\xb0\x30\x11\x08\x1a\xad\x20\x5e\x97\x55\xed\x38\x62\x22\x3b\x6b\xe8\xbe\x5f\xfa\xfd\x45\xe9\x8c\xd6\xd1\x27\xdd\x98\xf0\x9b\x4a\x37\xc6\x83\xa1\x47\xe2\xb2\x0f\xf9\x2b\xab\xaa\x46\xfa\x9a\xd3\x76\xaf\x08\x2d\x94\xed\x63\x31\x26\xc3\x3a\x00\x8d\xca\xbb\x50\x17\x05\x3f\xfb\xe9\x48\x0f\x17\xe1\x26\xcb\xcd\x8c\x5c\x51\x94\x4d\xb5\xfb\x40\xf8\x13\xd9\x28\xa7\x7d\xe9\xf0\xe9\xb0\x08\xa4\x1f\x67\xcb\xbe\x46\xa1\xb6\xa6\x45\x53\xc4\x52\x87\x1f\xd9\x72\xc9\x4e\xf1\xd0\x75\xc2\x74\xd7\x66\x5f\x06\xf9\xfa\xdc\x2c\xb2\x8c\x25\x62\x74\x87\x5e\xa7\x06\x12\x2f\x53\xf7\x18\xa5\xfd\xf3\x3e\x54\x68\x0a\xb8\xd0\xab\x3b\xa7\xc9\xdb\xe7\x61\xcb\x3b\x5b\x92\x42\xed\x5d\xf0\x51\x80\x15\x6b\x65\xf4\xc4\x79\xa9\x21\xa7\xa1\xe6\x4d\xb7\x17\x82\x0d\x86\xcc\xe6\xb2\x51\x58\x8e\x17\x47\xd0\x3e\x8d\xa2\x0c\x12\x4e\xa2\x5e\xc9\xbd\x94\x32\x6c\x1c\xe1\xf8\xeb\x6c\x9c\x54\x91\xda\x43\x9a\xf4\x74\xe6\x72\x9a\x4e\x5d\xef\xe2\x29\x9f\xdb\x52\xbf\xd7\xd0\xf9\x11\xbb\x69\x37\x83\xb3\x5d\xc5\xda\x43\x58\xa2\x51\x7e\xf8\xa0\xea\x10\xaa\xd2\xed\xa5\x47\x63\x05\x31\x84\x0b\x8d\x34\x21\x21\x40\x83\xdc\x8d\x10\x7c\xaf\x6e\xe3\x27\xfd\x70\x54\xee\xf2\x90\xb0\x45\x4f\xef\x0d\xd3\x9a\x4d\x9c\x65\x62\x76\x3b\xdd\x19\xc6\x01\x6a\x91\x16\xcd\x6e\x72\xa5\x4b\x8a\x95\x36\xac\x75\x6f\x09\x8b\x15\xd0\x62\x30\xf9\xbc\x28\x4d\x5c\x36\x2f\x2f\xb8\xf0\x41\xa7\x8b\x4b\x27\xbf\xb0\x54\x44\x2c\x8c\xd3\x1e\x3d\x2d\x63\xda\x43\x3e\xdf\x75\x5f\x96\xc0\xa6\x60\x0a\x2b\x4e\x2a\x36\xb7\x52\x0b\x78\x17\x86\xa6\x58\x89\xde\x4d\xcc\x03\x55\x2c\x76\xbc\x0b\x1d\x0f\x16\xef\xd7\xcb\x23\x6e\x57\xb5\xee\x29\xaf\x54\xbd\x19\x2e\x09\x95\x07\xe3\x85\x46\x72\x5a\x33\x66\x1f\x1f\xdc\x89\xc5\x21\xc7\x47\xa1\xc5\x9e\xb5\xc8\xcf\x70\xc0\x60\x35\xcf\x18\x96\x1c\x8b\x4d\x84\xaa\x4f\xd7\x17\xc4\x38\x73\xaf\x8a\x34\x6d\xb6\x02\xde\x85\x61\x82\xe6\x32\x07\xbd\x89\x4b\x85\xe5\x02\x13\x57\x2e\x64\xb5\xdc\xbd\x54\xf2\x9e\xc1\x5b\x8f\x02\xf7\x34\x6d\x70\x27\xda\x25\x62\x17\xf4\xeb\x25\xfd\x73\x1f\x6d\x53\x3d\xd1\xbf\x98\xef\x60\x7e\x3c\xda\xa6\xa0\xa8\x37\x08\xd1\xce\x44\x50\xcf\xf6\x6d\xbf\xfb\xc7\xb5\x0b\xa3\x24\x08\xeb\x5b\x8b\x72\xbe\x79\xb2\x1a\x35\xc3\xb9\xf4\x45\x10\xef\x7a\x4f\xdf\x1b\x1a\xd8\x4b\x77\x94\x69\x8a\x3d\x0b\xb2\xf7\xe9\x6a\x72\x4c\xb6\x97\x60\xed\x75\x5b\xde\x4f\x0b\xe2\xae\x43\xd8\x39\x88\x75\xd6\xa3\x8a\xb4\xac\xb2\x3d\x97\x49\xd4\xd6\x54\x6c\x13\x48\x7d\x21\xb1\x2b\xc0\x50\x27\xf0\x44\x90\x17\x25\xee\x00\x85\x2b\x0d\xa8\x57\xfd\x39\x94\xe8\x54\xa2\x6a\x8a\xba\xb8\x53\x93\x90\x48\x5d\xe4\x0b\x95\x71\x5c\x90\x20\x08\x78\x1e\x26\x05\x25\x2f\x18\xe4\x4d\x15\x90\xd4\x5a\x27\xeb\xe1\x75\xa4\x33\x90\x8f\xf0\xc2\x7f\x7a\x41\x47\xe9\x75\x09\x8b\x0c\x0b\xc2\xa7\xf7\x43\xc5\x7c\x22\x43\x75\x72\x4f\x08\x9d\x24\x5c\xcf\x28\x75\x79\x4f\x4e\x5d\x12\x7d\x24\xc5\xf7\x6c\xd8\x33\x12\x37\xec\xef\x4c\xf4\x20\x9e\x40\xe7\xa9\xfa\xbb\x85\x4d\xef\x6a\x8f\xe8\xc5\x83\x9d\x5a\xb0\xdf\x1e\x1b\x86\x3e\xd1\x3d\xd5\x96\x86\x10\x81\xb3\x38\xfa\x62\xa0\xe9\x99\x17\x9d\xb3\xd2\x82\xba\x9e\x51\x6c\xc1\x5b\xad\xfe\xae\xa6\x89\x5f\xe0\xf2\x1d\x20\xef\xfa\x49\x77\x88\x88\x07\x71\x1a\x1b\x19\xf3\xac\x12\xa5\x10\x9a\x58\xab\xda\xc7\xf3\xa2\x37\x1e\xf3\x36\x6c\x2e\xaa\x04\x41\xb3\x88\x1c\x51\x4d\x6e\x59\x74\x76\x04\x86\x21\x20\xf3\xc2\xd9\xb3\x17\x63\xaa\x20\x94\x61\xb2\xe1\x1c\x9d\x14\xf1\x29\xea\xf6\x85\x3e\x4f\x53\xa2\x84\x6f\x33\xa5\x0b\xbf\x7f\x30\xf1\x09\x15\xb1\xc6\x3d\xbb\x9e\xe3\x42\x94\xaf\xa0\xde\xab\xaf\x69\x55\xc8\xea\x17\xc4\xbc\x5c\x3f\x0d\x7c\x48\xa5\x4f\xb4\x65\x5c\x72\x87\xc2\x17\x79\x29\x1c\x02\xaf\xc6\x24\x0b\x2e\xc3\x84\x67\x54\xaf\x0e\x84\x2c\x68\x88\xd9\x3c\x15\xb4\xb1\x69\x09\x3d\x99\x19\x3a\x5a\x25\x42\x51\x53\x19\xec\x41\xd0\x0f\x4d\x64\x7e\x4b\x8b\x4a\x59\x8b\xf5\x4a\xcf\xe7\xba\x91\xa3\xa2\x14\xdf\x27\x90\x64\xa3\xf3\xa3\x66\x3a\x45\x61\x5b\x8b\x17\xc5\xa7\xe5\x9e\x87\x53\xc7\xc9\x5a\x23\xe4\xcf\x67\x7b\x06\xfb\x52\x6a\x39\xce\x61\x59\xda\x56\x4b\xc6\x28\xb4\x3e\xc8\xf8\x39\xbf\xd9\x91\xd2\x56\x02\x23\x07\xc6\x14\x5c\x0a\x0c\xb1\xcb\x53\x22\x17\x2a\x01\xd2\x0f\xba\x69\xd8\x34\x63\x2e\x05\xd5\xca\x9d\x34\xbc\x3a\xfd\x65\xa1\x02\x13\x98\xf5\xd9\x32\x3d\xb2\x7b\xc0\xdc\x25\x43\x4a\x81\xc1\x8c\x11\xbe\x69\x82\x8c\x29\x66\x83\x8f\x68\x2b\x77\x70\x9a\xd2\xcb\x3c\xe6\x31\xad\x6a\x00\xd5\x4b\xba\x75\x4b\x4b\x46\xe1\x2e\x98\x20\x20\x95\xc9\x21\xe3\x89\xa7\x5e\x57\x73\x68\x4e\x6f\xe7\x79\xaf\xf7\x0e\x6f\xc8\x20\x40\x58\x59\x37\x86\xcd\xe9\x8c\x3f\xe2\x13\x69\xde\x26\x8b\xc5\x88\xcc\xba\xf2\x76\x48\x24\x18\x00\xf7\xa0\x30\xbd\xf4\xd3\xb9\x19\xf7\x64\x7e\x43\x4b\xdf\x87\x0d\xb1\x47\xf2\x38\x93\xa6\x0b\xe1\x13\x4f\x92\xa6\x47\x5a\x61\xc5\x9b\xcc\xeb\x8c\xc8\xfe\xe9\xbe\xe2\x2f\xf6\xd4\xdd\x9f\x71\x46\xfb\xe3\x87\x1c\xfb\xd0\x8c\xcb\x57\x55\x3b\x4c\xd8\x04\xa0\x93\x38\x06\x97\x3b\x22\xcb\x42\xfb\x73\xf5\xce\xa6\xc6\xeb\x80\x94\x19\xbc\x73\x4e\xa0\xd2\x1d\xa5\xaf\xa0\x8f\xb4\x9a\x2c\x80\xbe\x13\x48\xec\xab\x91\xee\x8f\xf4\x6a\x65\x7c\x2e\x0a\x68\xc7\x5d\xe2\x0b\x70\xbf\x24\x97\xc0\x92\xbb\x3c\xc1\xc4\x5b\x4f\x3c\x97\x05\x49\x80\x88\x58\x3a\x59\x94\x02\x09\x1d\x6a\xea\xb9\x07\x74\x24\x43\x13\x34\xc0\xf5\x01\xe7\x1b\x83\xe1\xf2\x99\xd0\xb1\x77\x04\xe9\x90\xd7\xe1\x9e\x4e\xaa\x58\xf2\xf0\x1a\xdc\x39\xef\x63\x37\xec\x93\x2a\xb1\xc5\xf8\x39\x68\x71\xae\x25\x94\x3f\x18\x4a\x82\x32\x39\xaa\x57\xf6\xd3\xac\xe6\x17\x59\x11\xd0\xfb\x49\xa0\xcc\x24\x0b\x70\x37\x4a\xa7\x81\x6e\xf6\x77\xa0\x84\x6c\xd8\x7f\x82\x4b\x94\x9c\xf2\xe5\x7e\xb9\x05\xc0\x64\xd6\x77\xc6\xcc\x44\x94\x35\x5e\xb4\x9f\x37\x8c\x9b\x78\xdc\x4c\x93\x5c\x8e\x27\x39\x14\x25\x1e\x0b\x79\xcc\xf8\xb6\xbd\x93\x7e\x82\x07\x17\x8f\x22\x86\x61\x54\x09\x67\x5a\xcb\xe1\x8d\x25\x28\x44\x05\x9f\x18\xb0\x1b\x1e\x33\x33\x99\xda\x14\xb3\x5d\x04\x7b\x77\xd2\xa4\xec\x39\x70\x6d\xee\x92\xc2\xf6\xe3\x7e\x8d\x47\x3c\x7b\x49\x0d\x4f\x31\xb0\x38\x15\x3c\xe7\x96\xca\x89\x68\xd1\xa4\xeb\x12\xb8\xb0\x9e\x60\xc3\x99\xc9\xf2\x36\x46\x56\x92\x68\xa4\x11\x4f\x6f\x10\xa8\x64\xb5\xe2\x31\xe4\xd5\xc0\x88\x8b\xee\x47\xcc\xda\x1b\x58\x93\x35\x21\xe5\x21\x5d\x7a\x4a\x2f\xa4\xa3\x18\x34\xcb\x12\xa9\x3a\x51\x95\x6c\xe8\x08\xc8\xbb\x78\xc5\x9f\x9e\x7e\x4e\x4e\xd1\x99\x8f\x17\xb5\x8f\x1e\xf7\x42\x8e\xde\xf6\xbd\x7a\x55\xb9\xe0\x33\x13\x2b\x00\x52\xbc\x4f\x83\x59\x3e\x8f\x8d\xf1\x38\xc5\x6f\x1a\x1b\xd0\x93\x4c\xb0\x2f\x14\x95\x1f\x37\xcd\x7d\x06\x69\xf0\x7a\x12\x06\xcd\x16\x2d\x78\xa2\x96\xda\x45\x70\x2c\x0f\x60\x94\x5b\x1a\x9e\x6b\x96\xcb\x39\x3c\x91\xc9\xb5\x13\xad\xcc\x3b\xd9\xa3\xf6\x0e\xa2\xba\x15\x89\x17\xae\x2c\x2d\xdf\x07\x74\xa9\xe9\x15\x95\x11\x9c\x65\x5d\x1f\xca\xcc\xaa\xc5\xf3\xc9\x49\x7b\xd1\x82\xad\xce\x70\x69\xc8\x2c\xe5\x06\xf4\x30\xbc\x86\xbd\x3d\x6e\x9c\x8a\xaa\xe0\x82\x62\x12\x28\x57\xbd\xbe\xdc\x59\xde\xb7\x00\xf3\xee\x32\xff\x3e\xb8\x0b\xe4\xa4\xfb\xc5\xe1\xa2\x87\xaa\xab\x15\x98\x21\xcf\x89\x7f\x08\x55\x80\xb0\xa1\xd4\xb3\x7d\x4c\x34\x6a\x04\x2a\x0a\x74\x4b\x2b\xbe\x7c\x8a\xe7\xce\x45\x98\x3d\x84\x9d\x24\x51\x93\xec\xb7\xea\x4b\xe5\xe5\x44\xe4\xa0\x83\x42\xda\x5b\xaa\x4d\x7e\x2e\xfd\xb0\x47\x4d\xec\x65\x84\x06\x13\xd0\x19\x85\xdd\xaf\xf2\x8d\xad\x9f\x06\x5b\x87\x14\xf7\x76\x6f\xf3\xdb\xe4\x4d\x0b\xd7\xb8\xc4\x19\xf7\xf3\x29\xf0\x32\xe2\xdd\xa1\x2c\xca\x90\xf3\x9e\x1a\x8a\xb1\x26\x8a\x51\xd6\xcc\x27\xd7\x04\x54\x90\x0b\x32\xe3\xd7\xc2\xde\x8c\x4c\xfe\x65\xc0\x09\x54\x21\x26\xc9\x30\x29\x3d\x53\xc5\x42\xcd\x2d\xcb\xe3\x7f\xf2\x23\xf4\x9a\xf8\x2f\xf6\x23\xb0\x39\xf6\x33\x47\x29\x3e\xbf\xc0\x01\x54\x61\x8f\x08\x77\x1e\x92\x4d\xd3\x79\xba\x7e\x96\xd0\x8a\xc6\x38\xa6\x73\x9d\x89\x68\xa6\x9c\xe2\x82\xcb\x2e\xb0\x57\xc2\x0e\x94\xf4\x56\xe8\x73\x34\x55\x98\xd0\x79\x09\x81\xd3\x7b\xbc\xed\xc8\xac\x1f\x80\x0f\x0b\x9b\x6f\xf0\xed\x82\x61\x44\x88\xa9\x95\xed\x3d\xd3\x8a\xd3\xeb\xfb\x25\x22\x1e\x4b\xad\x8a\x92\xe6\xeb\x39\x18\x27\x98\x33\x54\xcf\x8b\x39\x3d\x1f\x3c\x50\x84\xda\xcb\x05\x41\x8c\xbb\xf6\xa4\xed\x8e\xd0\x89\xc0\xc8\xdb\xbd\x10\x52\x2d\x3d\x57\xdd\x3c\x59\xba\xf9\x38\x4b\x0f\xd0\xb0\x5d\xc0\xe4\x72\x5f\xf4\xc4\x90\xe0\x4a\x04\x06\x12\xef\x7d\x6d\x63\x30\xb5\xd8\x89\xaa\xf2\x17\x0b\x36\x0d\x1b\x3f\x71\x2a\xc5\x0c\x20\xc3\x2f\x8a\x06\x76\x33\x36\xd7\x52\x31\x2e\xea\xe8\x8c\x19\x2c\x8c\x6a\x1c\x85\x5c\xce\xde\x0c\xaf\x2c\x5e\x02\xfb\xe4\x1b\xdd\x06\xc6\x3c\x83\xfc\x87\x22\xd5\xb4\x16\x71\x7b\xc0\x09\xa8\xb0\x47\xc6\x73\x29\x0e\x6f\xe6\xc6\x56\x49\x07\xef\x2d\x5c\xe5\xb1\x14\x6d\xc4\xf2\x46\xd1\x80\x44\x80\x1e\xcb\x65\x19\x97\x4c\xba\x66\x0b\x55\x3b\x9e\x99\x31\xaa\x7b\xaf\x10\x48\xfc\x6a\x69\xb7\xe9\xda\x83\x7d\xa1\x58\x62\xcd\x44\xaf\xb2\xd6\xd0\x53\xc3\x1a\x52\x20\xf5\xd2\x40\x28\x4e\xd3\xa8\x97\xd4\x20\x5e\x04\xa6\xd0\x74\x88\x51\x0c\x95\xb2\xcc\xc9\x92\xd3\x57\x52\x99\x6f\x0a\xad\x54\xb9\xe2\x60\x94\xbd\xab\x64\x1d\x12\xf6\xc9\x17\x0d\x4d\x79\xd2\x85\x53\x44\x21\x8e\x9f\x67\x91\x11\x04\xde\x35\xaf\x0a\x46\xa4\x02\x7f\xc2\x5e\x0f\x52\x99\xc6\x28\x80\x5f\x16\xc2\xdf\x82\x3e\xad\x16\x7a\x84\xd1\xd8\x04\x3c\x23\x1d\xbb\x96\xb5\x98\x87\x2e\xc5\x6e\xe8\x34\x3c\xec\x9c\x15\xa6\xbe\x92\x74\x04\x44\xb9\x7b\x6a\x65\x0a\x48\x4b\x57\xa9\x39\x5c\x86\x87\x54\x6f\x97\xf6\x12\x5f\x8c\xf8\x9e\x18\x50\x04\xd8\x99\xdc\xd8\x29\x57\x53\x34\x22\x3b\x3c\x07\x60\x70\x8c\x62\x53\x94\xdd\xda\xa1\x79\x73\x38\x73\x07\x6e\x38\xf8\xce\xaf\x88\x41\xdd\x00\x30\x0c\x45\x07\xea\x9b\xa7\x2f\x16\x77\xde\xb4\x0c\xe4\x1a\xb6\xea\x58\x82\xaf\xf2\xd5\x48\xb4\x59\x59\x8d\xee\x7b\xee\x0c\xc6\xcd\x9b\xa0\x94\x3b\xa3\xf2\x7c\x4c\x3e\xc4\x16\xe8\x0d\xc4\x2f\x09\xfd\x2c\x68\x42\xd8\xf3\x5e\x7e\x85\xdf\x39\x7b\x27\xc9\x7b\x33\x78\x19\x13\x36\xc0\xf0\xd2\x91\x0e\x84\x81\x9b\x5f\x9d\x85\x97\x5d\x2c\x3e\x84\x83\x62\x43\xf5\xbc\x1a\x0a\x32\x99\x99\x80\xf6\x8e\xbd\x4e\xe8\x9d\x6b\x55\x57\xb3\x75\x15\xd3\x0b\x3a\xa0\x8a\x4a\xd3\x0f\x33\xad\x2e\x7b\xeb\x7c\xce\xff\x74\x9b\xfe\x8b\x3d\x0d\x2f\xe9\x7e\xfe\x7c\xeb\x03\x92\x4e\x3c\xef\x00\x39\xd1\x13\x37\x18\x49\xc8\x4e\x4c\xeb\x44\x34\xf4\x11\xc9\x6e\x5c\x51\x64\x46\x6e\xf5\xa3\x6a\x98\x7c\x18\xa0\xbd\x93\x3e\xaf\x25\xfb\x1e\x78\x23\xeb\xdf\x05\xdb\xb8\xaf\xc8\x30\xc0\xc6\xa6\x03\x5f\xd6\x5e\xe7\x39\x15\xf9\x31\x3d\xb1\x16\x83\xcb\x75\x4d\x24\x5e\x14\x7b\x80\x58\xc5\xa7\xab\xee\xfa\x82\x8e\xa4\x23\x41\x42\x04\x02\x0c\xd5\xe0\x17\x86\xd1\xd2\xa3\x36\x44\xc5\x8b\xc2\x9d\x7a\x96\xf8\x8c\x00\x62\xb4\x23\x7a\x27\x06\xc8\x79\x4f\x62\xfa\x3e\xf4\x2c\x0f\x4d\xdf\x45\x26\xe1\xf5\xd9\xd7\x5d\x42\x79\x7b\x4f\x46\x86\xfd\x29\xb7\x1a\x2b\xcb\x7a\x94\xe9\x5f\x90\xa6\x37\x77\x2e\x79\xc5\xef\x1b\x72\x43\xa3\x92\xe0\xd0\x33\xe2\x74\x34\x76\x9d\xaf\x74\x59\x9d\x9b\x77\x4f\xd1\x77\xf8\x46\x3f\xa1\x32\x62\x0d\xa4\x7e\xa5\x79\x2f\x57\xa1\x8f\x94\x00\x73\xda\xab\xf5\x49\xa5\xc4\xab\xa2\x83\xee\x88\xc8\x1a\x8d\x20\xac\xd1\x18\x46\xad\x90\x08\x2a\x3c\x08\x54\x77\xc4\x82\xd6\x78\xa9\x60\x2d\xab\x0d\xc8\xd4\x78\xa5\xbe\x2d\x45\x0c\xa8\x5f\x5b\x8f\x41\x20\x52\x94\x6a\x33\x67\xaf\x2e\x5b\x3c\x4d\x81\x6e\xf7\x0f\x2c\x95\x4b\x1a\xed\x60\x4a\x4c\x33\x34\x06\x3b\x10\x15\xe4\x8e\xd2\x8d\x97\x80\x3a\x42\xda\x57\x16\x4f\x93\xf4\x33\x09\xf8\x32\x2f\xdd\xd0\x37\xaf\x33\x50\xb6\x75\x0b\x68\x90\xc1\x14\x53\xc7\x6b\x02\xfa\x98\xf4\x29\x4a\x23\x06\x62\x6f\xd7\xcb\x7b\x50\xbb\x44\xc6\x24\x83\xeb\xce\x67\x49\xcc\xf6\x7b\x3d\xf2\xa8\xdc\x1f\xdd\x87\x27\x23\xc4\x7e\xd0\x41\x37\xf6\x0b\xf0\xd4\x51\xd4\xa3\xf3\xc8\xf3\x3c\xba\x42\x61\xb0\xd9\x88\x76\xd1\x3e\xba\x45\x43\x29\x10\x6f\x75\x49\xf6\x7d\x18\x4e\x1a\x0a\xde\xd5\xa0\x34\x55\x4e\x07\xf0\x6e\x0c\x72\x27\x91\x89\xb1\xbc\x81\x36\x07\x06\x58\xa6\xd8\xee\xd4\xac\xc6\x2b\xcb\xcf\xf7\xeb\x24\x9f\xdb\xd2\x6e\x67\x18\xa4\x5a\x78\xac\x55\x81\xb1\x7d\xed\xf6\x88\x80\x46\xe9\xa8\x54\x1f\x94\xcb\xb4\xcf\xa6\xeb\x59\x92\x2d\xd8\x77\xb1\x27\x1b\x5a\xf3\xd9\x16\x55\x99\x20\xb0\x0b\x79\x9d\x99\x91\x3b\xc7\xb0\x62\x73\x25\xe0\x61\x39\x39\x20\x16\xa1\x5d\x47\x6a\x38\x87\x18\xd4\x49\x36\xc7\x3b\x23\x2f\xd2\x1a\x3b\xc1\xc0\xdb\xe3\x79\x41\xf8\x33\x9f\x6e\xdf\xc4\xdd\x5f\xcc\xee\x9e\x3f\xec\xae\x58\x20\x49\x82\x78\x63\x02\xf6\x04\x1b\xe0\xe7\xe2\x35\xfb\xf9\x99\x8c\x64\xfe\x49\x1b\x21\x63\x08\x5c\x05\xb6\xd7\x4b\x2b\x30\x16\x35\x76\x98\x7c\xb1\x53\x5e\xc4\xba\x71\xba\x96\xb7\xbd\xc7\xd7\xb2\x96\x4b\x69\xe6\xcb\xd3\x84\xd5\x23\xff\x94\x24\x2f\xc8\x2d\x3a\x95\xc5\x4a\xcd\xc1\x18\x46\x7a\x72\x8f\xd8\xc4\x25\xb8\x9d\x79\x55\x11\xa9\xaa\xd2\x6b\x0d\x18\xa1\x81\x71\x9a\xa7\xa2\x6b\x5a\x66\xba\xde\xe9\x32\x73\x29\x58\x4f\x24\x6c\xe7\xe7\xee\xa6\x97\xfa\xb5\xd1\x9e\xf7\x2e\x82\x23\xbb\xe9\xa2\x53\x37\x4d\x20\x5e\xc4\xde\xd3\x32\x00\x66\x58\x64\xde\xba\x2d\x12\x57\xd1\x0b\x3e\xef\xb5\xe6\x71\x79\x3c\x39\xf5\x96\xbf\x4c\x5d\x4a\xb5\x46\x98\x5d\x95\xe4\xde\xb2\x73\x25\x82\xe9\xb2\x4f\xa3\x27\x9a\x12\xf4\x52\xbd\x7a\x3a\xbe\x6a\xaf\x4b\xaa\xc0\x0b\x2c\xa1\x79\x0c\x31\xe0\x98\x26\x73\x7a\x99\x3b\xe0\xad\x28\x58\xd8\x2b\x23\x2d\x71\x29\x4d\xc5\xfe\x5e\xd9\x73\x45\xcf\x19\x17\xf6\x5d\xa8\x29\xd3\x9a\x69\x19\xa9\x97\x17\x2d\x8e\x52\xdb\xa9\x29\x49\x17\x62\xdb\xdf\x54\xcd\x51\x4d\xb5\x50\x5e\xfc\xde\x10\xcb\x26\x2d\x87\x92\x26\x7a\xe9\x42\xcb\xc3\x2d\x78\x98\xe0\xeb\x5c\x38\x0f\xc0\x3b\x25\x20\x63\x4b\x51\x79\x95\xe5\xf2\x7d\x97\xdb\x07\xf5\xa2\xc9\x94\xc6\xc7\x97\x75\x5e\xf4\xc0\x2b\xdf\x44\x31\x03\x40\x17\x2b\xbc\x73\x0f\xc6\x96\x79\xf0\x93\x23\x88\x57\x37\xb4\x09\x7a\xb2\x02\x14\x3e\xc1\x8a\x7a\xbf\x70\xd5\x10\x23\xa3\x1c\x12\x26\xad\x2a\xfe\xa8\x92\x75\xd7\x92\xd3\x19\x78\xf2\x09\x01\x20\x7a\xa5\xc3\x89\x38\x20\xdc\x9e\xea\xdb\x10\xc1\x5c\x30\x94\xb4\x86\x26\xcc\xea\xe1\x59\xa7\xf6\x04\xde\xb1\x1b\x50\x39\xd6\x0d\x94\xde\xf0\xb9\x6a\x99\x8e\x23\xc1\x96\x04\xde\xe2\xbc\xb8\xad\x22\xd8\x1c\x36\x3b\x06\x1b\xde\x1d\xe6\x54\x52\x31\x42\x2a\x43\x11\x73\xb6\x27\xf5\xa7\x2b\xd3\x80\xc5\x3e\x0c\x3b\x10\x7f\x5d\xf6\x33\xad\x8b\xff\x3f\x7b\xff\xad\x6b\x31\xd2\xac\x09\xa2\x0f\x44\x83\x5a\x99\xd4\x5a\x6b\x7a\xd4\x5a\x2d\x6a\x3e\xfd\x45\xd5\x7f\xee\xa9\x6a\x60\x06\xa7\x07\x53\x03\x94\xd1\x06\x8d\xbd\x91\xeb\x63\x22\x33\xc4\x17\xc1\x88\xcc\xf8\xae\xc0\x82\xc1\x6e\x8b\xb6\x4d\x0c\xeb\x35\x5e\x22\x21\x69\x39\x1b\xe5\xeb\x90\xc3\x81\xa0\x69\x27\x41\x74\x5c\xef\x99\x65\x9b\x3e\x45\x49\x6d\x28\x61\xaf\x6d\x0f\x3c\xfe\x58\x45\x1c\xc1\xb3\x16\x8f\xb9\xf3\xc1\x51\x6c\x18\x81\x09\x40\xb0\x21\x86\xab\x94\x58\xe3\x1f\x3d\xa9\x6d\x39\xfe\x65\xd7\x2f\x17\xea\x5f\x7a\xb7\xef\x17\x03\x0b\xc1\xf3\x03\xd2\x7e\x28\xf3\x5f\x2d\x6a\x21\x0f\x23\xc2\x2f\xf1\x5c\x41\x4f\x90\x7a\x90\x01\xd6\xd8\xf5\xc2\xc9\xbc\x7b\xff\x79\x5f\xda\x61\xa4\xd0\xab\x82\x33\x08\x6d\x32\x88\x63\x9b\x78\xe1\x21\xae\xe5\x66\x6d\xeb\x40\xc2\xe4\x88\xf6\x5a\x3a\x75\x1c\x80\x4f\xe9\xf8\x5d\xe0\x4e\xd2\xf8\xfd\x71\x67\x51\x38\x73\xf1\xa1\x49\xe5\xb2\x3d\xa6\xc9\x1f\x04\xba\x3f\x2b\xad\x10\x73\x4f\x6d\x1b\x81\x16\x04\xc7\x3f\x07\x15\x98\xe7\x13\x18\x0e\x20\xce\xcf\xbf\x61\x54\xc2\x7c\xd1\x61\xb2\x81\x01\xb9\xe8\x50\x92\x3c\x81\x34\xd6\xfa\x3d\xa4\x72\xdd\xbc\xb3\x8d\x72\x08\x2f\x68\xf2\x68\xbe\x75\xbd\x4c\x70\xd5\x0e\x57\x6f\x13\x83\x56\x58\x37\xbc\x1e\xf8\xb9\x8c\x76\x59\xcb\x41\x56\x8b\x27\x0b\x4d\xaa\xc8\x3f\xae\x76\x98\x9a\xdd\xd8\x4c\x73\x1c\x5e\xf3\x0a\x87\x11\x9e\x92\xaa\x26\x96\x31\x1b\x00\x09\x10\xee\x32\x8d\x61\x68\xbc\x8d\x9d\x7e\xdc\x23\xb2\xd4\x74\xf6\xd5\xa2\xb2\xd1\x2d\x6c\x8c\x5b\xec\xbb\xe6\x33\xaa\x20\xfd\xa6\x4c\xfa\xf5\x9b\x06\x7f\x97\x39\xcc\x32\xc6\x1e\xef\xa3\x8d\x48\x18\xac\xee\x33\xf5\x78\x04\x3c\x24\xba\xd1\x8c\x90\xa5\x3f\x17\x34\x79\x58\x50\xc7\x53\x59\x3d\xb4\xa3\x55\xa7\x63\x80\x0c\x68\xbd\x8d\x92\x6f\xb5\xf7\x77\xfd\xe7\x66\x51\x77\xd8\x3e\x67\x8d\xad\x90\xce\xb8\x49\xe2\xbb\x01\x6f\x5d\x33\x8d\x26\x50\xb2\xe8\x09\x00\x4e\xb6\xe0\x11\xe6\x1f\xb9\x10\xc7\xca\xde\xed\x9f\xa4\x63\x36\x03\x41\xdd\xe1\xef\x27\x11\xcf\x4e\xb4\x40\x7e\x6f\xf8\x8c\xba\xd5\x06\xff\x80\xbf\x97\x55\x8b\x2c\xfc\x3c\xd3\x93\xb1\x3a\x82\x1c\xe0\x37\x28\x35\xfe\xdb\x7b\xb7\xeb\x4a\xf2\x7d\x4d\xf2\x5c\x62\x0f\x4d\x67\xa8\x6a\x04\xc8\xec\x2c\x97\x31\xe9\xdc\x81\x60\x92\x87\xf5\x5f\x47\x72\xfa\x68\x23\x02\xff\x43\xdd\x9a\xe4\xc0\xee\xf8\x42\x24\xaf\x63\x06\xec\x1a\x9d\xcf\xdc\xee\xa9\xe7\x46\x6c\x3d\x6e\x59\x64\xe4\x09\x6d\x2e\x62\xc7\x5b\x2b\x18\xe6\x66\x63\x78\x3f\x19\xe2\xa8\x80\x3f\x05\xf3\x9f\xe4\x8c\xc7\xbf\x8c\x33\xd6\xe9\xdf\xaf\xfc\xff\x09\xb0\x10\xd8\x1e\xf5\x4d\x59\xae\x96\xbc\xc6\x22\xcd\x28\xdc\x09\x2d\x3c\x6a\xd2\xb1\x81\xe0\xac\x21\x82\x6f\xcd\xc1\xc6\x75\x93\xaf\xc2\x11\x9f\x67\xaf\xd5\x00\x53\x0b\x9a\x5b\x96\x56\x69\x49\x32\x37\xe6\x49\xc8\x5d\xaf\x16\x65\x5d\xef\x23\x53\xdb\xaf\xed\x40\x7a\x25\x69\x54\x24\x91\x5a\xe6\x0a\x09\x7b\xc7\x26\x51\x6e\x5d\x75\x45\x51\x00\x41\xb7\xb2\x65\x31\x02\x5d\xa3\x9f\x1f\xce\xbc\x66\xca\x57\x3b\xee\xf5\x66\xdf\xe0\xcf\x80\x96\xeb\x8d\x76\x57\x2c\x63\x55\x58\x79\xe5\x75\x67\x6f\x0c\x3f\x48\xf3\x86\xe9\xca\xf2\x4c\xad\x62\x4f\x65\x85\xb6\x61\xd4\xcf\xe7\xcd\x37\x9f\x8e\x60\xf6\x70\x7b\x6a\xc0\xf1\x67\x42\xa4\x8c\x9b\x06\x58\xc3\xa8\xb8\x18\xcd\x1a\xf3\xde\xd9\x76\x4a\xa7\xa1\x4e\x47\xe8\xc1\xd9\xc4\xa4\xc8\xe4\x99\x6d\xef\xea\x56\x2b\xb2\xac\x71\xde\xb1\xb9\x7b\x1c\x8a\xb6\x73\xa6\x0d\x4f\xb3\xec\xd3\x77\x83\xd7\xb9\x1b\x06\x33\xcc\xd0\x70\x0e\xfb\x85\x35\x04\xb0\x91\xc0\xc6\xa4\xc4\x4e\xd0\xd3\xc8\x72\xb0\x0d\x70\x90\xb3\xa7\x50\x28\x6f\xf9\xbd\x5c\x3a\x5a\x0a\x9d\x08\xd2\xc9\x3f\x77\x79\x72\x5c\x77\x78\x68\xdc\xa2\x57\xc7\xa5\x58\xff\x2b\x36\xcc\x56\x09\x5e\x97\x4b\x82\x3c\xfa\xe3\x64\x98\xb8\xcb\x71\xac\xe4\xec\x50\xa8\x1d\x3c\x56\x8a\x6e\x00\x21\x10\xe9\xf8\xca\x4a\x3e\xb4\xa8\xb8\xe7\xd7\xed\x46\x47\x43\xd8\x0b\xc5\x9d\xe1\x88\xf5\xc0\x92\x63\x43\x3c\xa2\x7c\x8b\x8f\xb0\x05\x46\x08\x65\x73\x60\xb2\x7a\xa4\x4d\xd4\x53\xa2\x1d\xf6\xb1\x91\xf5\x4d\x8c\xf7\x40\xc1\xde\x45\x14\x0a\x4f\x0c\x4e\xc7\xfd\x04\xb4\xa4\xcc\x59\x6f\x53\x9e\xb1\xbc\xa9\xd9\xf1\x31\xa4\xbd\x54\x2f\xed\xcc\x71\xef\x9f\x4b\xc8\x83\x3d\xb8\xbb\xc5\xc4\x5b\x91\xde\x6c\xb3\xce\xe1\x0c\x72\xdf\x9e\x0f\xd8\x33\xe5\x13\x08\x3d\x66\x7f\x28\x0b\x42\xc3\xf9\x7d\xd2\x31\x43\x5e\xc5\x8b\x4e\x08\xd0\xf8\x59\xe0\xc2\xd8\xd1\xfe\x06\x9a\x8d\xb3\x3d\x2f\x3b\xab\xf7\x2a\x74\x9e\xec\xf5\x7e\x77\xe8\xf1\x3a\x50\x5e\x73\xbe\x44\x73\xc5\xe1\x88\xf2\x01\x37\x34\xcd\xdd\x1c\xec\x29\x56\xe8\x50\x7b\xc1\x0b\x5f\x5d\x65\x85\xe6\x58\x93\x17\x32\x00\x90\x5e\x9e\x35\xe9\x3f\x4f\x1d\xbd\x6b\x7e\xe4\xc2\xc0\xc9\x4c\xe6\x1f\xf6\x65\xff\x32\x0e\x59\x8a\x7f\xe9\x21\x45\xff\x20\x84\x49\xea\x55\x85\xba\x70\x22\x85\xad\x0d\xad\xe7\x26\x4b\x9e\x15\xca\xb5\xe3\x04\xd8\x5d\x84\xd4\x2d\xcb\x2b\x68\x72\xa5\x7a\x40\x77\x27\xab\xaa\x5d\xd7\x57\xc4\x74\xeb\x73\x4e\xcc\x78\xee\x64\x85\xe4\xc6\x6b\x95\xf3\xbe\x83\xd0\xe3\xc2\x63\x84\x76\x18\xcd\xea\x11\xf0\xbe\xaf\x58\xdf\x34\x99\x5e\x91\xc4\x2a\x13\xa7\x50\x70\x07\x6c\x0b\xb0\x3d\x41\x51\x2a\x35\x2d\x7f\x87\x13\x2a\x30\xcd\x35\xd3\x00\xda\x2d\x4a\xe7\xeb\x38\xc6\x1b\x85\x34\xe4\xde\xe8\x4f\x58\xbc\x9a\x99\xae\xca\x43\x05\x3d\x7e\xe2\x9f\xd7\x17\xb4\xb4\x5c\x54\xda\xb5\x9c\xcb\x51\x3c\x40\x5a\x33\xa6\x16\x5f\x75\x49\x95\x2f\x79\x82\xc2\x61\xc5\xa1\xa9\x07\x0b\xf3\xbe\x1d\x77\x70\xc7\x71\xc2\xa0\x4c\xb0\x20\x8e\x1c\x22\x4c\x50\x77\x1f\x51\xdd\xcd\xf1\xa0\x7c\x7d\x67\x41\xfd\xd8\x1f\x3c\x87\xfb\x47\x3d\x4a\x8a\x14\x38\x06\x0b\x4c\x75\x9f\x81\x8b\x7d\x21\xee\x43\x1b\x46\xbf\x1a\xa5\xfa\x58\xf1\x1b\xfb\xf7\x50\xdc\xca\x50\xdd\xf5\xe6\xc0\xce\xe1\x98\x2c\x4a\xe1\x5f\xa1\xc0\x98\xf8\x3b\x9c\xea\xd9\xbd\x9c\xf0\xdc\x77\x4f\x31\x31\xaf\x01\x91\xa8\xe4\x9b\xf1\x0b\xba\x51\x25\x93\x99\xf0\x8e\xf3\x75\x7c\x06\x75\x2e\x74\x25\x86\x37\x97\x2a\x93\x16\x79\x7b\xb3\xb8\xc7\x9b\xcd\x19\x7d\x8b\x5f\xae\xe2\x36\x07\x9c\xe9\x89\x3b\xde\x42\xaa\xe2\x16\x52\xe0\x5b\x63\x99\x05\x79\x8d\x80\x32\xe5\xc8\x26\x90\x68\x8a\x47\x9b\x6a\x21\xaf\x21\x87\xe0\x96\x2e\x98\xcb\x2e\x0f\x92\xb0\xa4\x17\x7e\xe6\x23\x28\xd1\xbc\x0f\x1e\x66\x40\x81\x11\xd9\x65\x15\x14\x9b\xe3\xe7\x43\x46\xa0\x9a\x35\xef\x4d\x50\xde\x3b\x20\x89\xc8\xdf\xf3\x2c\x80\xa9\x01\x2d\xca\x92\xb1\x6b\x5a\x58\xf0\xbb\xdf\xc9\x39\x0c\x65\x28\x7d\x36\x80\x26\x60\x67\xad\xec\xd5\xf7\x99\xd2\x32\x92\x9a\x1c\xbe\x7f\xc0\x8a\x22\xe5\xd8\x1e\x72\x18\x08\xf6\xda\x46\x49\x80\x99\x52\xb8\xb6\xc1\xfd\x1c\x66\x36\x27\xe6\xaa\x0e\x9d\xb8\x1f\x21\xc2\x7f\x8c\x51\xad\x23\xcd\x8c\x7e\x80\x76\x51\x7e\xc2\x30\x43\x70\x56\xd5\xa3\x8a\x18\xf9\x0f\xe7\x44\xd6\x7f\x5b\x9e\x73\x6a\xff\xca\x73\x42\x7f\xe6\x39\x13\xdb\xb7\x51\x7c\x4b\x9e\x2c\x22\xfc\x91\xcf\x56\x53\x8b\xa4\xbc\x59\x10\x71\x10\xa9\x1f\xe3\xb2\xc4\x2f\x5f\xe2\x73\xaf\x21\x11\x6c\xdf\x0d\x09\xb0\xe1\x27\x6e\x67\xb3\x79\x6c\x75\x32\xaf\x8e\x79\x82\xcb\xee\x87\x9c\x41\x9d\x4b\xab\x5a\xaa\x92\xd3\x75\x02\x06\x74\x6c\xa9\x34\xc8\xe8\x43\xd1\x14\xd9\x7f\xfc\x3c\x4f\x88\xe8\x79\x5b\x8b\xcd\x3b\x14\x06\xf0\x9b\x8b\x5f\x4f\x90\x58\x94\xa1\x67\xd4\x45\x79\xbd\x8b\x4e\x0e\xf4\x3f\xa9\xa7\xe2\x2b\x9f\x20\x79\xbc\x92\xd0\x7d\x5a\x75\xfd\xad\x93\x3f\x4a\xd3\x39\x01\x96\x31\xe1\xa7\x69\xa7\x66\x7e\xf4\x03\x3a\x52\x48\xf5\x52\x00\x40\x2d\x11\xa6\x5e\xa0\x0c\xde\x25\x83\xe1\x44\x83\x0c\x97\x4c\xd3\xe2\x2b\x9b\xdd\xc9\x7c\x48\x79\xd7\x63\x6e\x52\x49\x44\x7d\x86\x86\x4b\x0b\xc8\x19\xb5\x33\x30\xed\x2a\xed\xaf\xd3\xb8\xdc\x31\xae\x02\xd6\x2b\x81\xfe\x72\x74\x2d\x7f\x27\x69\xd8\xb6\x30\x82\x78\x97\x13\x91\x25\x40\xaa\x6a\xba\x9d\x2c\x37\x44\x4f\x11\x93\xd1\xdf\x20\xd2\x48\x58\x3e\xe4\x09\x66\x47\x58\xd2\x23\x3d\x81\xed\x03\x83\x8b\xbe\x5c\x66\x82\x61\x77\x8c\xba\x7f\x07\xbc\x6b\x50\x89\xed\xa7\x3a\x25\xd8\x00\x01\x0a\xcf\x4b\x6e\xbd\x4d\x2d\x74\xe2\x4d\xd5\x3b\x05\x50\x4b\x54\x95\x70\x4a\xd6\xba\x0e\x27\xd4\x8d\x33\x2b\x67\x2b\x0c\xcd\x61\x99\x02\x50\x4a\x4f\xf2\x08\x7c\x0f\xf3\x6d\x27\xbc\x45\x0a\xc0\x49\x5c\x06\xab\xcc\x6d\xbe\xa1\x2a\xc9\x2b\x08\x1e\x9e\xc5\xb1\xb3\x77\xc8\x90\x8c\x92\xd0\x65\xb8\x74\xc8\xa1\x36\x03\xd9\x64\xb3\x15\x77\x1e\x76\x53\xeb\x8c\x6e\x9f\xe1\x09\x3c\x7c\x68\xdf\x88\xe0\xbc\xa2\xd0\xcb\x7c\xd3\xe6\x6b\x62\x4e\xf0\xab\x85\xe1\x9c\xf4\xbe\x55\xfd\xaa\x75\xc6\x04\x22\x76\x26\x5d\xf2\xec\xc1\x1e\xac\x38\x62\x7c\xc3\xe3\x8b\xde\x11\x06\x26\xdb\xac\x93\x00\x3a\xf0\x57\x14\x8c\x7e\x88\x3a\x8e\xea\x0a\xfa\x83\xcc\x0d\x4e\x79\x0c\x34\xe2\x54\xcd\xa2\x44\xac\x7e\x80\x1d\x77\x6a\x41\xec\xa8\x22\x34\x09\x0a\x9c\x76\x92\xca\x3e\x53\x30\xb2\x01\xf0\xbe\x40\x35\xb3\x01\x73\xde\x9b\x71\xe7\x78\x01\xd2\xcf\x7d\xa9\x33\x79\x85\xb1\x38\xb1\xb8\x6e\xf5\x70\x1d\x56\xf3\x98\x41\x5e\x62\xf0\xe0\x84\xb2\x5c\x94\x51\x22\x9a\xbf\x8f\xcb\xde\x88\x19\xa6\x44\xbd\xa2\x8a\x1b\xea\x9c\xf6\xee\x04\x30\xf9\xdc\x5b\xac\x07\xcb\x93\x4d\x15\xa9\x5f\xba\x85\xae\x1b\x87\xa0\xdc\x7e\xd1\x11\x78\x53\x74\x4f\xd1\x08\xb9\x93\x89\x5d\x24\x61\x05\x9b\xc4\x78\xbf\xc9\xb0\x86\xf9\xf0\x64\x91\x32\xac\x9d\xc6\xb1\xd2\x87\xa8\x08\xc1\xa8\xfb\x4b\x76\x95\xb7\xce\xde\x65\x99\x6c\xdb\xba\xc1\x5f\xdd\x05\xdc\xb6\x12\x02\xcb\x8b\x26\x0b\x54\xcf\x0e\xba\x66\x9c\x84\xc1\x3e\x2a\x8f\xe9\xd9\xdf\x73\xea\x1f\xf5\xbb\x6b\xfb\x2f\x8b\x21\x5b\xf3\xaf\x18\x72\x3c\x7e\x02\x24\x04\x0f\x08\xa6\x39\x9f\xc5\xe6\xef\x4a\xbf\x52\x19\xf2\xc4\x8a\xa5\xe6\x49\x9c\x91\xd3\x10\x45\x49\x08\xe1\xac\x1f\xa9\x64\x29\xe6\xc2\x30\xa6\x74\x29\xc6\xc6\x30\xd5\xb2\x59\x17\x10\x9a\x05\xb2\xb9\x31\xd0\x7c\x3f\x76\xbc\x69\xf0\x93\xc3\x1a\xa6\x33\xf7\xd4\x9f\x03\x57\xa8\x8c\xbc\xaa\x27\xa8\xa6\xc2\xef\xa8\x3d\xd9\x40\x4d\xd1\xeb\x9b\x16\xe5\x84\xf0\x45\x19\x5d\x33\xa9\x7f\xc3\x23\xca\x13\xa7\xfc\x32\x72\x9e\xe8\x73\x6c\xa8\x57\x4f\x21\xfa\x8d\x2d\x13\xc7\xf9\xa6\x3f\x60\xdb\x40\x3a\x7b\x87\x80\x2c\x02\xeb\x5f\xd9\x52\xf9\x17\x22\xa0\x77\x39\xec\xcc\xe9\x9d\xb0\x15\xe2\xa3\x6b\x9e\xb7\x94\xe3\x2f\xa0\xc7\xaa\x93\xec\xae\x8d\x2a\x9b\x1d\x9a\x4a\x48\x2d\xc2\x6b\x39\xa4\xe4\x98\xd4\x3c\x6b\x82\xe1\x73\x60\x2c\x1d\xdc\x0e\xec\x07\x63\x39\xb1\x68\xe2\xba\xbc\x37\xcc\x6e\x61\xfe\x28\x71\x2e\xed\x30\xf3\x26\x3d\xa7\x33\x4a\x2e\x1e\x46\xe2\x0d\x95\x17\x74\xd8\xa8\x29\x02\xe0\x7d\xc0\x78\xd7\x35\xa4\x28\xe5\xb9\xdc\x46\x0d\x1c\xd3\x47\x06\xad\x55\xb5\xc8\x7a\xde\xa3\x04\xfd\xc0\x84\xd9\x80\x06\xf2\x27\x79\x5d\x02\x19\xb9\x58\xdc\x8e\x3b\xca\xe5\x69\x71\x81\xa1\x8c\x99\x78\xd5\x6f\xa2\x57\x39\xad\x73\x9d\x34\x94\xfa\xed\x76\x61\x5d\x9b\x6a\xa1\x68\x1c\x09\xd7\xad\xab\xfb\xa4\x3d\xb2\x1b\x0a\x77\x0d\x1a\x5a\x34\x82\x6f\x60\xd4\xd4\xa4\x8c\x4b\x64\x52\xbf\x1b\xd8\x6d\x88\x27\x6c\xd9\x99\x92\xf3\x93\xcc\x86\x73\x3b\x23\x0d\x19\x98\x54\x9c\x10\xb3\x94\xcc\x57\xa8\xfc\x94\x41\x46\x35\xc4\x12\x42\xfc\x61\x85\x70\xdb\xc2\xfa\x39\xba\x0a\x9c\x14\x78\x46\x31\x0f\xf2\x84\x63\xca\xce\x69\xad\x51\x00\xfd\xc9\x2f\xb4\x10\x5d\xea\xe9\x1f\x82\x71\x80\x1c\xf0\x9f\x1d\xdc\x74\x5a\xab\xec\xb1\x6b\x11\xce\x60\xb9\x8d\x46\xda\x06\xd9\xbe\x03\x66\x96\x90\x94\xf1\xe4\x29\xdb\x72\x6b\xe5\xcf\xcd\x9b\x62\x15\xab\xad\x0c\xd6\x71\xbd\x9c\x08\x13\xdb\x89\xe9\x9e\x14\xdc\xef\x1d\x63\x97\x88\x33\xc0\x6d\xda\x05\x3c\xde\x04\xb4\xe4\x1d\xee\xb7\x49\x4c\x12\x95\x55\xbf\xa5\x8d\x46\x48\x01\x4f\x01\x4a\x48\x87\x4d\xcb\x8a\x26\xec\xa6\xea\x85\xee\x3e\x5e\x76\xec\xcd\xc1\x78\x33\x17\x4d\xc3\xd9\xaa\x26\x42\x11\x67\x9b\x54\x79\xce\x38\xde\x3b\x65\xb8\x7e\x68\x32\x8f\xf4\x58\x31\x8c\xc3\xa8\x6d\x27\x65\x07\x4f\x33\xd6\x3f\x5c\xf3\xb0\xce\xff\xb2\x9a\x87\xe9\xf8\xab\xe6\x81\x3e\xac\x3f\xe2\xd5\x38\xb6\x57\x88\x63\x82\x68\x52\x73\x0e\xc2\x1e\x96\x31\x4d\x5f\x04\x06\xad\x95\xa8\x5a\xe1\x89\x6c\xd3\xc1\xc6\x16\x7a\x5a\x80\x46\xa5\x26\xf8\x1e\x85\x64\x1d\x42\xef\xc7\x39\x42\x85\x83\x1c\xed\x17\x3d\xa6\x04\xf3\x03\x9d\x22\x56\x0f\x7f\xcf\x0c\x4f\xd0\xa2\xa4\xfe\xac\xbc\x29\x05\x56\x15\x80\xc0\xf0\x87\xcb\xfb\x04\xe5\x49\x83\xd0\xb5\x2e\xad\x4f\xa4\xa8\x11\x9b\x48\x1e\xae\x30\xd4\x5c\x68\xad\x4f\x47\x57\x8d\x25\xdb\xfa\x3b\x4e\xe0\x46\x37\x0a\x8f\xc9\x9a\x76\x9e\xbd\xe2\xc1\x75\x4a\x8d\x74\x7f\x4c\xba\x9e\x0b\x5c\x35\x6f\x88\xe1\x24\xe9\x22\x0e\xdb\xbb\xde\x4b\xe0\x35\x61\x89\x52\x3c\xa1\x2c\x59\xb6\x72\x6d\x3d\x8b\x1b\x63\xa1\x03\xcd\x9a\x79\xc4\x38\xd5\xde\x91\x64\x70\xc2\x13\xdb\x09\xd8\x72\x33\x76\x33\xd4\x82\xe2\x78\xb6\x53\xdc\xb6\x0d\x0d\x3a\x8f\x93\x32\xdc\x12\xa6\x90\x29\x03\x35\x1b\x0f\x3a\x1c\x67\x17\x8b\xba\xd4\x64\x21\xbf\xc6\x1f\x11\xbd\x99\x0b\x86\xc4\x69\x6b\xf6\x4b\xb2\x18\xef\x93\x63\xb0\x61\x46\xd0\xad\xc6\xa8\x22\x86\xcd\x07\xda\x11\xd6\x5a\x8a\xcc\x33\x88\xb3\x8b\x99\x0f\x96\xf9\xc4\x55\x4e\xe9\x49\x5c\x81\x0c\xcd\xa8\xba\x19\x71\x4f\x53\xb6\xa9\x9a\x35\xbc\x42\xf3\x69\x43\x6f\xca\x20\xbc\x87\xeb\x0d\xe5\xe6\x7b\xa2\x73\x48\x8a\xee\xe5\x4d\x41\xe9\x61\x67\x00\x47\x01\xbd\x76\x7d\x0e\x9f\xf2\x5a\x2a\x8a\xd3\x03\x9d\xb8\x50\xe5\x94\x2c\xa2\x4d\x6c\xbe\xde\xf1\x62\xa0\xfc\x52\xc2\xde\xc0\x03\x7b\xb1\x0a\xd9\xca\x29\x38\x5f\xae\xbb\xda\x2a\x6a\xd1\x67\xbd\x93\x66\x4d\xd1\x2b\x00\xbe\xe8\x15\x16\x0e\x95\x33\xbf\x5d\xda\x94\x8a\x8c\xc4\x04\xab\x92\xa5\xb7\x39\x7a\xfd\x6b\x9a\xfe\x86\x18\xe7\xb6\x01\x50\xaa\x1a\x4e\x91\xd7\xd5\x5c\x44\xa6\x11\x0c\x0b\x76\x53\x6d\x21\x59\xa7\x71\x3b\xf4\x35\x21\xbc\x98\xef\x92\x81\x58\xc7\x60\x1a\x11\xe5\x88\x75\xce\x4f\xb3\xa1\x11\x83\x66\x44\x1f\x2e\x3b\x8f\x6b\x89\x21\x07\x44\xe9\x5a\x10\xe3\x99\x59\x96\x5e\x8a\xf4\x59\x31\x63\xde\xe1\xa2\xac\x10\x18\x65\x29\xb8\x22\x9f\x9b\x29\x46\xac\x1f\xb2\x0c\x52\x02\xaf\x0f\x4a\x5d\xbd\x07\x1d\x12\x7a\x22\xf4\x2e\xe6\xc7\x1d\xe4\x48\xc1\xdd\x70\x12\xd2\x4f\x9b\x13\x21\xa0\xe8\x50\x1d\x3d\xd5\x9d\x5c\x88\xcf\x1e\xa0\x56\xe8\xfd\x4c\x1e\x6f\xc1\xe4\x31\x52\x6e\xc2\x40\x45\x76\x9c\x79\x3a\x69\xbb\x38\xcb\x5f\x6b\xb7\x2a\x65\x93\x48\xff\xe3\x2b\x25\x59\x08\x81\x97\x56\x20\xb5\x73\x64\xd0\xb4\x4d\xa6\x5a\x60\x1a\x9e\x4e\xc1\x41\x1e\x06\x61\x5a\x45\xf3\x3b\xb1\x2f\x3b\x8a\x37\x64\x1f\x86\x4e\x0d\x9f\x6a\xdf\x0e\x28\xfe\x9a\x76\xd5\x0c\x6a\x76\xc3\x10\xd1\x2f\x64\xa3\x2b\x5d\xb9\xbc\x9a\x61\x0c\x26\xcb\x8a\x79\x1c\x0b\x91\x9d\x92\x7f\xd6\xa7\xaf\xff\xb2\x58\x7a\x68\xff\x7e\x3d\xe0\x9f\x3e\xdd\xf6\x0d\xf2\xf5\xd2\x75\xfa\x7c\x9a\x37\xb3\x29\x62\x0e\xb1\xf6\x3a\xae\x6b\x7e\x00\xf3\x88\xf4\xa7\x1d\x17\xd8\x5e\x35\xc8\x0c\x1d\x20\x0a\x1d\xb1\x5c\x98\x72\x44\xb2\x2d\x75\x77\xc7\x06\xda\x12\x6c\x9b\x1f\xa8\xca\x34\xb9\xa8\x41\x1a\x1f\x7a\x40\x83\x59\xc1\x13\xa6\x2b\x77\x01\x10\x38\x4e\xe3\xdf\xf8\x8c\xbd\xa0\x7e\xa5\x8b\x9f\x35\x3e\xeb\xd3\x7e\xa5\x0f\xd1\x78\xd7\x51\xd2\x11\x9d\xf7\xad\x48\xf6\x0d\x5e\xca\xf4\xec\x16\xe0\xbd\x51\x49\x9c\xf9\x9e\xba\x1e\x39\xf4\x0c\xe3\x43\x2a\xe9\xa2\x05\xc2\x07\x7f\x2a\xc2\x07\x01\x41\x83\x28\x79\x89\xc9\x8f\x7f\xaa\x46\xa5\x03\x68\xe4\x00\x66\x51\x94\x50\x6a\x68\x4e\x07\x2e\xc5\xca\x6d\x8c\xd2\x78\x67\x26\x1f\x68\x8f\xba\x70\x56\x7f\xb3\xc0\x37\xa4\x26\x0d\x40\x07\x32\x05\xd6\x05\x06\xe8\x92\xec\x3e\xfd\x3c\xef\x39\x62\xa3\xce\xd0\x98\xac\x46\x0a\xd0\xfa\x1a\xd5\xea\x40\x05\x3a\x57\x75\x6e\xec\x86\xfc\x82\x62\xdd\x37\x92\x5c\x26\x4d\xd0\x1f\xeb\x82\xe1\xc8\x01\xb1\xc0\x23\xd9\xcb\xb7\xe9\x1b\x8f\x10\x0a\xb4\x26\x83\xfa\x8f\xe9\xec\xed\x28\xe9\xcc\x2c\x60\xd8\xc7\x29\x3a\xdc\x2c\x71\x7a\x77\x86\x79\xb1\x70\x47\x7c\x39\x07\x69\x27\xb3\x3f\xa6\xe2\x47\x77\x63\x1a\x89\x5d\xe9\xa1\xda\x89\x82\x45\x33\xbf\x5e\x66\xba\xeb\xc7\xf4\xe6\xc7\xfe\xb0\x1a\xbb\x6e\xa5\x29\x25\x1e\x4b\x02\x86\xdb\x53\x4e\xa0\x98\x23\x91\x22\x1f\xef\xb9\x5d\x72\x6e\xfc\x16\x12\xf5\xb3\xc1\xb5\xc7\xdd\x3b\xf1\x19\x38\x87\xc8\xca\x99\xea\x94\xb2\xa1\xbd\x29\x33\x03\x11\xc7\xe4\x8e\x06\xa3\x31\xd6\x91\x30\x1d\xc6\x42\x51\x49\x33\xa0\x7b\x77\xa2\x7a\x1c\x5a\xf8\xdc\xa4\x70\x0a\xa3\x7c\xdc\x3b\x7e\x70\xde\xed\xb9\xeb\xac\x41\x71\x6f\x2b\x86\x23\x13\x22\x3f\xf0\xe5\xc4\x7c\xb0\x4e\x0a\x40\x0e\xa1\x01\xf6\x8a\x31\x7d\x3d\x41\x8e\xfc\x92\x46\xec\xab\xc6\x4b\x08\x34\x7a\xbd\x5d\x7e\xe3\x7b\x4d\xe4\x00\x82\xba\xea\x84\x72\xc6\x3a\xd5\x9c\xf5\x99\x1f\x3b\x74\xb1\xd6\x65\xcc\xe4\x7f\xc5\xe5\xaa\x41\x48\x0b\xd4\xcf\x6a\x36\xf6\xde\xc6\x84\x62\xbc\x1d\x64\xb2\x32\x77\xf5\x9c\xe2\xbe\xca\xef\x43\x6e\xdc\xea\x83\x10\x4b\x16\x26\x0f\x9d\x7c\x2b\x2e\x17\x5d\x36\x59\xf4\x1f\x71\xb9\xa0\xdd\x79\xc2\x88\xb3\xa9\x9a\xb1\x3c\x04\xba\xc8\x3c\x58\xe9\x56\x3b\x48\xbd\x6b\x07\x00\x79\x82\x03\x48\xba\xa7\x08\xc1\xa5\x4e\x00\xd1\xe7\x59\x8b\x00\xab\x87\x64\xcb\x0c\x60\x0d\x98\xd5\x25\xe6\x25\x6a\x78\x32\xe4\x75\xc5\x25\x07\x2a\xb2\x73\x78\x8b\x3f\x6b\xc0\x5b\x33\x8c\x22\x64\x4a\x09\x4f\xc0\x75\x96\xff\xe4\x37\xd8\x75\x2f\xff\x5d\x3a\xbf\xfd\xbd\x16\x12\x36\x04\x48\x48\xea\xfc\x28\x35\x2d\x92\x8e\x45\x39\xdc\xa8\x51\x65\x66\xe5\x58\x01\x51\xa0\xe4\x5c\x3a\x2f\xcb\x2a\x5e\xad\x2c\xb5\xc5\xe0\xc4\x44\xfd\xda\xef\x9e\xc2\xbd\x8d\x5a\x18\xa8\x8a\x57\x25\x06\x10\x1a\x28\xf1\x7d\xd7\x35\x1a\x08\xd1\x34\x71\x59\x38\x36\xf7\xc7\x41\xd5\x3d\xb2\x26\x6d\xe0\x44\x35\x3a\x5e\xa8\x2e\xf2\xd1\x74\xc6\xf1\x1d\x26\x51\xf0\x94\x0c\x08\xf2\xc3\xf1\x4e\xeb\x4f\xfd\x0e\x9e\x46\x3a\xcd\xc2\x97\xf3\x72\x24\xc7\x96\x0b\x87\x37\x51\x0a\xba\x46\xde\xfe\x11\x78\x5d\xea\x3d\x66\x65\x18\xdc\xd1\xbb\x78\x00\xef\xd1\x98\xe4\x42\xde\x8b\x64\xfd\xb6\xe6\xba\x56\x9d\xcd\x44\xea\x8a\x7a\xd8\x0c\x98\x5b\xf2\x43\xd3\x35\xd0\xa9\xc6\xaf\x00\xfc\xb2\x00\x88\x5f\xcf\x39\xfd\x4d\x11\xe3\x8f\x6e\x9f\x49\xd2\x87\xc5\x23\x7f\x40\xf2\x5c\xe1\xfc\xfb\xa4\x6f\x6c\x62\x9b\xb7\xbe\x20\xb5\x7d\x6c\x42\xf9\x03\xd4\x46\xe5\x94\xe9\x25\xe8\xe3\x44\x90\xd3\x14\xbc\xad\x46\x72\xd2\x0e\xf3\xd3\x42\x52\xf0\x56\xcf\x01\xd1\x02\x00\xdf\xb3\x3c\xad\xd0\x8f\xc2\x60\xa0\x52\x81\x04\xfb\xb7\x62\x80\x7c\xcc\xb5\x84\xef\x43\x17\x54\x05\x2f\xdd\x8e\x80\x18\x3d\x73\x77\x52\x34\x8a\xa1\xc9\x7f\xc0\xa1\xbc\xdc\x32\xa8\xad\xad\x25\x5e\x4c\x4a\xe5\x87\x28\x10\xdc\x5a\x6a\x39\x27\xf4\x4f\x05\xc9\xe0\xb6\x25\x5f\xe8\xb6\xfe\xc8\x27\xf5\xb8\x31\x23\x79\x48\xca\x03\xb1\x28\x43\x5b\x3c\x58\xac\xe4\xb6\x4b\xc5\x5a\x91\xb8\x03\x0f\x98\xfa\x8d\x62\x53\xf0\x37\xb1\x00\x6f\xd9\x45\xa1\x7b\x5b\xec\xcc\xad\x3a\xb4\x58\x8c\x31\x99\x42\xab\xa7\x4a\xe3\x55\xcb\x73\x4b\x5e\x54\x08\xee\x32\x83\x06\xcd\x2f\xec\x30\xfb\x4a\x69\x3a\x26\x63\xcc\x16\x66\x2b\xa1\xb4\x2a\x62\x5c\xdc\x73\x39\x32\x88\x75\x48\x05\x66\x30\xcf\x34\x22\xe4\x8a\x31\xca\x39\x46\x9e\x92\xd1\x4e\x98\x95\x5d\xe2\x2d\xea\xd3\x6e\xac\xda\x5d\x5a\xd3\xe2\x59\x89\x0e\x74\x93\xdd\x84\x5a\x8e\x7c\xb6\x6d\xe4\x86\xdf\x8a\x99\x60\x22\x82\xc8\x99\x2e\x7b\x7c\xea\x0c\x6c\x44\x22\x16\x5d\xb0\x89\x28\x5c\x1d\xab\x04\xae\x23\x93\x19\x69\x98\xd0\xc9\x77\x7b\x10\xc1\x48\x9a\x16\x99\x34\x4e\xe5\x86\xf1\x37\xb7\x55\xfe\x02\x7f\xe6\x91\x9e\x11\xd9\x06\x9b\xa4\xdc\xa4\x61\x6e\x5e\xe0\x21\xca\x64\xee\x9a\xb0\x7a\xa5\x70\x1f\xf8\x28\xb5\xb5\x53\x32\x83\xc3\x0a\xcb\x99\xa3\xa6\xf9\xe3\xd5\x9a\x51\x2a\xf6\x74\x7f\xc5\x2f\xc1\x1f\xc9\x41\x5c\x51\x65\xfa\x11\x82\x14\xca\xe6\x8a\x41\x0d\x38\x96\xde\xe0\xc0\x65\xe7\x01\xa5\x62\x41\x15\xce\x01\x83\x8f\x49\xba\x53\xa6\x26\x88\x1d\x0e\xad\x16\x19\xaa\xed\x5e\x82\x39\x59\xc5\x47\x96\xb1\x4e\x53\xba\x67\x30\x51\xf9\x0b\x1d\xcd\x46\x3b\xc7\x05\x71\x89\xd7\x8c\x33\x99\x04\xb4\x05\xea\x07\x35\xe4\xad\x85\x77\x23\xab\xbf\x43\xd6\xcf\x8e\x6b\x20\x91\x19\xa0\x53\x2c\xf5\xad\x58\xa5\x04\x77\x84\x38\xf7\x39\xb0\x27\x27\x25\x0b\xfb\x02\xa6\xf8\xe7\xac\x83\x83\x55\xc1\xab\x68\x9a\x1d\x40\xbb\x3e\xfc\x40\xc8\x4b\x18\x76\x57\x65\x3b\x38\x4e\xd0\x4a\xee\x7f\x38\x26\xf9\xb7\xdd\x46\x1c\xfe\x65\x7a\x86\xe3\x12\xa6\x3f\xe8\x86\xfd\xf9\x81\x38\x35\xaa\x86\x04\x5b\xec\x88\x12\xba\x32\x84\xc5\xea\x3f\xe7\xc9\x26\xb5\xc8\x92\xfb\x3c\x51\x7e\x85\x46\xba\x8b\xf5\x2b\x3c\xdc\x93\x5f\x9b\x03\x55\x95\x24\xf3\x43\x2f\x7b\x0e\x57\xde\xd5\x0d\x79\x04\x95\x95\x9b\x78\xea\xea\x2a\x37\x5a\x81\x8b\x3f\x2d\x9d\x2a\xa0\xaa\xfe\xa0\x1c\x30\xd1\x22\x00\xc2\xcd\x48\x91\x23\xe1\xfd\xca\x23\x8c\x80\xe0\x65\x23\xe0\x67\x39\x99\x88\x9d\x3c\x29\x45\x26\x41\x57\xa0\xbe\x34\xb5\x39\x91\x43\xb0\xdb\xac\x98\xc5\xc9\x2d\x1b\x95\x06\x59\xe3\xea\x08\x2a\xb3\xca\xaa\x7f\xbe\xc3\xa7\xd1\x54\x29\xd0\x94\x05\xe5\xba\x01\x06\x66\xf3\xc3\x2e\x14\xe1\x7b\xb8\xbe\x3d\xc7\x3d\xe8\xd2\xdb\xeb\x29\x2d\x8c\x0c\xfa\x29\x17\x6d\xf1\xd9\x96\xfc\xec\xf0\x39\xed\x59\x87\xb9\x13\xce\x84\x5c\x3d\xc9\xfa\x52\xd2\x40\x59\xb0\x7c\xab\xc2\xc4\xfd\x8a\xf7\x02\xa9\x02\xf5\xec\x64\xbd\x05\xee\x00\xcb\xe9\xc4\x2c\x13\x15\x4a\xcc\x7f\x27\x05\x68\x9d\x02\x4e\xb7\x45\x00\x44\xe0\x74\x74\x7e\x9f\xe5\xf1\x1e\x34\x63\x2f\x54\xbf\x19\xb1\x4a\xb5\x3a\xba\x7e\x52\xbd\xb2\xcd\x56\x7a\x88\xd4\x71\x5d\x71\x93\xb1\xb0\x4f\x33\xc9\xbb\xa0\x84\x28\x9c\x42\xd5\xd7\x5f\x06\xa5\xcd\xa9\x44\x55\xb3\xf1\xdd\x4d\x8e\x09\xcb\xa6\x21\xf1\x74\xd2\x40\xf3\x0e\xaf\x7f\x1a\x9e\x0b\xaf\x88\xc9\x1d\x1d\xea\xc6\xbe\x24\x0a\xa9\x12\xc2\x8e\xdb\x7d\x25\xf7\xb3\x35\xe2\x67\xbe\xc9\x59\xa6\x4a\xac\x30\x7c\xf9\xb3\x8e\x0e\xa3\x29\x0d\x3f\xb1\x72\x35\xf0\x7e\xa3\x00\x9b\xa6\x6d\x9a\x7e\x99\xcc\xda\x4c\x42\xf3\x6e\xa7\xbe\xc3\xdc\x22\xce\x48\x82\x15\x4a\xa5\xab\xeb\xd0\x2f\x9c\x3e\x44\x73\xe0\x29\x22\xaa\x3e\x8a\xa7\x04\x3b\xd7\x33\xcb\xd3\x46\xa6\xaa\xb3\x8a\xba\xa3\x49\x15\xf7\x20\x44\x2d\x49\x3a\x58\x5a\x42\xe0\xf2\x38\x0a\x60\x3e\x18\x53\x82\x43\x58\x12\x94\x18\x24\x07\x1b\xa2\x7a\xde\x1b\x11\x5d\x68\x4f\x7a\x17\x0b\x60\x6a\x24\x0e\x17\x00\x6d\xac\xa1\x2d\x7c\x2c\x5b\x69\x9a\xd0\x2e\x58\xf9\xab\x1d\xdb\xc1\x3b\xc4\x10\xf3\x77\x91\x95\xbc\x87\xf8\xec\xef\x5d\xb1\x39\x46\xe4\x27\xee\x77\x55\x23\x72\x7e\x4e\x15\x26\xad\x26\xc2\x5f\xf1\xc4\x30\xa6\xae\x98\x71\x8b\xc3\xc6\xef\x30\xa3\xe3\x62\xe9\xa2\x01\x5a\x87\x61\x8f\xa8\xd7\x74\xa4\x97\x41\x1f\x95\x1a\xb6\x48\xf8\x58\x10\x88\xa9\xe0\x0d\xc2\x1b\x33\x95\x91\x8c\x68\xe8\x2e\x9d\xe5\x70\x2c\x6d\xe6\x2e\xcd\x78\xd9\x53\xb0\x9f\xe9\x6d\x33\x09\x1e\xf0\xd5\x0c\x92\x6a\xdf\x69\x5c\xd7\x5e\xc5\xf5\x03\xd2\x05\xd1\x47\x03\xb3\xe7\x3b\x26\x55\x11\x55\x4d\x09\x12\xc3\x8d\x41\x07\x6e\x4b\x67\x15\xe8\x3f\x6c\x06\xb6\x7f\x59\xd4\x31\xff\xcd\x0c\x50\xc7\x09\x41\x4c\x60\x07\xf8\xbe\x62\xb0\x39\x7c\xee\xb3\xd6\x5e\xba\x75\x50\xa8\x28\xce\x26\x08\x6a\x90\x26\xb1\xc0\x5d\xf9\xcd\x45\x4f\xb2\x9f\x2c\x0f\x30\x6c\x20\xfe\xf8\x1f\x37\x47\xac\x23\xa8\xa5\x12\x75\x0d\xeb\xfd\x88\x75\x73\x55\xb8\xca\xdb\xe7\x27\xd0\x06\x99\xa5\x93\xf7\x73\xb0\x05\x87\xf0\x5a\x36\xe6\xd8\xb6\xed\xa8\x94\xba\x4c\x51\x92\xdf\x43\xd1\x92\xb6\x9a\x7c\xf9\x4c\xf1\x10\xa0\x99\xb0\x70\xbb\x0f\x7c\x54\x04\x7b\x13\x02\x03\x3d\xb7\xaa\xc5\xe1\xf8\x57\x56\xfd\x7a\xc0\x8f\xc9\x28\x9f\x55\x00\x2a\xd6\xfa\x8c\xa9\xc9\x39\x66\x4a\x6a\x54\x8c\x49\x0f\x45\x4c\x10\xf9\x43\xeb\x85\x0f\xdd\xa2\x79\x0f\xa0\x70\xe5\xc2\x83\x14\xc6\x6d\x01\x1e\xa4\x24\xc8\x5e\xa7\xb0\x23\xf7\xa9\x84\x4a\x7d\x07\x18\xa5\xbf\xfd\x50\xe8\x18\x53\x48\x12\xe7\xe6\xe4\x51\x48\x5f\xb5\x51\x1c\xad\x5e\x62\x0a\x6b\xe8\xd3\x4e\xa1\x42\x4e\xb1\x24\x9a\x04\x7a\x3e\xcf\x3a\x80\x6e\x86\xe5\x3c\x4f\x99\x8c\x3d\x12\x9a\xcd\x3b\x97\x8d\x01\x51\x1a\xdc\xef\x54\xf4\x23\xfd\x25\x2f\x67\x21\x4b\x7e\xae\xed\x2b\x8a\x9c\x8c\x92\x4e\x2b\x44\x95\x44\x57\xe3\xe9\xfd\xf8\x4f\x42\x40\xae\x4d\xd1\xf5\xce\xe5\xd2\x41\x08\x92\xd5\xd4\x25\x39\x7b\xd2\x13\x11\xc3\x69\x3b\x91\xd2\x4f\x5e\x03\xa5\x1a\xe2\x35\x9f\xd5\x14\xf3\x83\x95\xdc\xcf\x05\xe3\x0b\x60\xc6\xe4\x23\x52\x67\x6a\x41\x71\x34\xa5\x61\x77\x56\x1c\x99\x87\xd0\x13\xeb\x23\x0c\xa6\xb8\x16\x9e\x3b\x98\x50\x92\x6c\x6d\x64\x3a\xe5\x04\x45\x1c\x17\x51\x54\xe4\x19\x22\xa2\x51\xc1\x62\x2c\x23\x33\xac\x91\xcc\x3b\xcd\xbe\xdd\x83\xa7\xc4\xa5\x3a\x7a\x7c\x4f\xec\xda\xe7\x8f\xa7\x1f\xe1\x1a\x0d\xf2\x05\xef\x07\xa7\xab\x1c\x8c\xe1\xbc\x80\x47\x3a\x01\x8b\xf9\x95\x29\xf3\xa0\x8b\x68\x9e\x0c\xf6\xce\xa4\x23\x73\x48\x9b\x27\xeb\xef\xbc\x84\x74\xe9\x3b\xd0\xa1\x62\x54\x3b\x28\x60\x13\xf7\xc2\x4a\x30\x7d\x88\x59\x10\x56\x0b\x09\xe7\xbb\xc7\xb4\x72\x59\x4f\x63\x92\xb6\x42\xb3\x44\x2e\xd2\x68\x26\x47\x58\xa8\xfb\xd7\x7e\xd7\x42\xa3\x75\x47\xca\xa8\x8d\xbb\x22\xba\xa7\x01\xe3\xca\xb2\xdd\xb1\xe4\xcc\x6d\xa5\xa8\x6c\x77\x53\x77\xa9\xf6\x5e\xca\x24\xaa\x09\x16\x3b\x92\x9e\xef\x3d\x6b\xb9\xdc\x6d\x43\x91\x9f\x97\x6c\xe0\xf8\x1e\x37\xc6\x90\xe4\x02\x87\x88\xe0\x76\xcc\xf1\x25\xf8\x30\x04\xbf\xdf\x2e\x03\xa8\x23\x22\x5a\x42\x91\xcc\xcf\x3f\x9c\xd3\x21\x66\xa6\xc6\x1e\x42\xe4\x42\x98\x87\x20\x18\xb8\x92\xea\xb7\xb3\x06\x72\x31\xd8\x0b\xbb\x13\xc2\x93\xa0\x9b\x15\xa0\x9f\x2a\x37\x56\x82\x84\xf1\x2b\x24\xc6\xae\xe9\xf6\x30\xa1\xa9\x53\x5b\x52\x7f\xcf\xe5\xbd\x7e\xd4\xcf\xa9\x6c\xba\x0b\xd5\xe2\xe7\x69\x8d\x0a\xf8\x3f\xb1\x78\x93\x2a\x8f\x7d\x1b\x74\xc5\x86\x11\x9d\x25\x9f\x14\x8b\x7d\xf2\xfd\x9f\x8c\x58\x7e\xd9\xef\x5f\x66\x2f\xd6\xbf\xd3\x86\xff\xea\xde\x22\x28\xab\x79\xc7\x34\xee\xa0\x36\x65\x38\x27\x80\x75\x41\xd3\x38\xa3\xc8\x0e\xb2\xf7\xdd\xd9\xd9\xe3\x67\x77\x8e\x0b\x13\x40\xcc\x20\x31\x1b\xee\x7e\x5d\x90\x99\xdc\x0d\x8b\xcd\xb3\xf6\x9c\xea\x68\x1a\x13\x10\x10\x30\x51\x93\x3a\xff\x26\x6f\x1c\xb1\x98\xf3\x0b\x0a\xa0\x71\xfa\xfb\xd0\x8a\xa2\x24\xab\x28\xa8\x6c\xa3\xab\x8b\x6b\x2d\x79\x04\xc7\xcb\x58\xce\xfc\x8a\x62\xf0\xc3\x00\xf6\xf6\xc7\xfc\xba\xc9\x3c\x2e\x1b\x2a\x27\x5b\x42\x17\xe0\x46\x8a\x00\x8b\xa2\x38\xd7\x38\xb0\xd8\x1f\x5d\x02\xfc\x25\x4f\x51\xe1\xf1\x85\xf6\xa3\x2c\xc3\x74\x6d\x0f\xec\x09\x34\xd1\x8b\x4f\x63\x21\xe6\x68\x34\x83\xe7\x54\x69\x96\x60\xa8\x22\xce\x91\x0f\x27\xe6\x07\x43\x97\x6e\xdc\x8b\x4b\xa2\x49\x9d\xef\x32\xa3\x2d\x05\x21\x9c\x69\x01\x6d\xa1\xe1\x6d\x3a\x24\xc6\x50\xbc\xc3\x28\xe9\xb3\x31\x27\xd3\xb2\xb6\x62\x88\xc9\xea\x84\x4c\xc8\x62\x9c\xed\xa5\xbd\xf0\x5d\xf0\x5d\xc9\xf8\x91\xf3\x8e\x09\xa8\x0e\xc2\xe4\x27\x46\x51\xd3\xfc\x29\x39\xc3\x30\xe8\x02\x86\x1a\x62\xdf\xbc\xba\x90\x3f\x5c\x7c\xc9\xd4\x3d\xaf\x0e\xb3\x45\x8f\x00\x36\x25\x2e\xc3\x84\xa7\xd4\x86\x60\x83\xe2\xb4\x78\x8a\x5d\x3e\x4f\x1f\xdd\xe8\xed\x8a\x26\xd4\x06\xdf\x70\xa2\x3b\x18\x45\x11\xb2\x96\x0a\x17\x15\x7b\xc0\x49\x96\x27\x25\xc8\xeb\xde\xfb\xed\x79\x2a\xe7\xf8\x57\xde\xad\xa1\xaa\x2a\x17\xf5\x82\x47\x18\x5c\x6b\x0a\x08\xb6\x76\x12\x51\x35\xe4\xba\x8d\xe2\x90\xaa\xea\x21\xf8\xe5\x30\x1a\xda\x86\xbf\xff\x0a\xdf\xf1\xbe\x27\x05\x81\x19\x92\x42\x86\x10\xa4\xdc\x93\xca\x46\xa2\xaf\x05\xc6\xeb\x06\x99\xc5\x26\xb7\xa8\x81\x84\x3c\xb7\x2c\x81\x29\x6b\x79\x9f\x82\xaf\xe0\xf1\x53\x77\x54\x59\xd7\xd8\xfb\x8d\xa2\x39\x48\x88\xb9\xcb\xab\x49\x5f\x61\x53\x18\x25\x92\x34\x50\x85\x4e\x20\xf5\x46\x45\x4a\x13\x82\xd9\xf4\x14\xa0\x72\x50\xda\x47\x20\xb5\xc2\xf1\x35\xd8\x09\x7a\xa0\xb8\x19\xe1\xfd\xd9\x29\xa0\xbc\xe5\xe7\x2e\x6f\xd6\x02\x93\xfe\x22\xdd\x9e\x47\xec\x5d\x09\x9e\x2a\xcc\x2c\xbd\x01\xb0\x6b\xd0\x41\x4e\x4b\x8e\x15\x0d\x0c\xdb\x50\x72\xef\xfe\x90\x92\x4e\x5a\xa8\xf5\x47\x76\x74\xf7\x7a\x06\x78\xec\x6a\x20\xf6\x0a\x38\xfa\x97\x6e\x02\x17\xa8\xe7\x40\xfa\xdf\x0f\xfe\xb2\x96\x4b\x46\x96\x90\x55\xc6\x15\xec\xbb\xce\x73\x83\xfd\x74\xf6\xdb\xf3\x40\x0b\x15\x68\x63\x1b\x67\x28\x00\xef\x69\xa2\x20\xc9\x14\x66\xb3\x56\xed\xd6\x62\x95\xc8\x1b\x69\xcc\x32\x3e\x04\x93\x4b\xce\x44\xf3\x77\xf0\xbb\xe6\xd7\xa1\xf7\x53\xab\x4d\x69\xc0\xdc\x35\xef\xbe\x18\x45\x85\xd1\x2b\x1b\xdd\xb3\x37\x6f\x4f\xca\xe3\xb0\x90\x95\xef\xb9\x65\xe3\x58\xd1\x96\x22\x71\x63\x9e\x76\x3e\xb6\xc3\xe2\xa6\x68\xa7\xa1\xa4\x01\x1d\xe0\x7c\x86\x31\xb6\xfb\x05\xd2\x6f\x3c\xd9\xe6\x1f\xcd\x6e\xfe\xf2\x7f\x97\xd9\xe8\xfe\xff\x89\x8e\x4d\xf8\x33\xda\x18\x85\x00\x9c\xb2\x06\xaf\x91\x57\x6d\x63\xfd\x7e\x94\x03\x1a\xba\x6d\x0f\x85\xf8\xec\x6d\x80\xa1\x11\xbc\x38\x61\xbb\xa8\xd0\xe8\x88\xc3\x23\x39\x55\x4e\x24\xb5\xc3\x4f\x20\xf3\x17\x3a\xca\xea\x86\x5a\x15\xfb\x83\x51\x58\xb4\x48\x01\x74\x1a\x2e\x8b\xaa\xe2\x43\x31\xe5\x53\x6d\x55\x24\x8a\xd6\x16\x9c\xe4\xbc\x12\x79\x14\x00\x36\x70\xf9\x16\x61\x4c\x46\xe0\xf3\x5a\xe8\x55\xee\x67\xa8\x6d\xd7\x2c\x90\x72\x8a\xa0\x10\x49\xa1\xbf\xf1\x5d\xc8\x3c\x64\xbb\xc2\x93\xde\xba\xdf\xc3\x7b\xf9\x96\x29\xcc\x15\xbb\x02\x0b\x40\x9c\x76\x5b\xae\x17\x57\x53\x4b\x58\xf6\xc9\x36\x96\xd9\xb4\x0f\x73\x06\xcb\x18\x18\x33\x67\x9e\xce\x39\x24\x74\xa9\xe6\x3e\x1f\xbb\xc3\xbd\x07\xa5\xb9\x15\x30\xa0\x38\xb0\xa1\xac\x6d\x6d\xb8\xd7\xdb\x88\x94\x45\x1e\xfb\xbe\x0a\xcd\x69\x54\xd1\x8f\x38\x79\xdf\x50\x1b\x5d\x0a\xc4\x5b\x31\x9f\x2f\x8b\x6e\x8e\xf1\x27\x79\xbd\x25\x02\xd6\x1a\x0f\xc9\xd5\x45\xef\x42\x4d\x9c\x87\xb9\x44\xbe\x59\xd8\x4a\x11\xd7\x84\x5e\x58\xcd\x61\xfc\xcf\xae\x6f\xec\x9c\x7b\x38\x36\x09\xf5\x62\x33\xe7\xe8\xb9\xf6\x0b\x62\x0d\x43\xf7\x30\xc0\x6e\x53\x54\x19\x0c\xf5\x2f\x90\x25\xd1\xaa\x74\x6e\x7f\xaa\x95\x96\xe9\xb9\x50\x27\x82\xd2\x66\x7a\x58\x09\x45\x4f\x6b\xb9\x92\x29\x18\x85\xfe\xcd\x3d\xdb\x31\xfd\xc1\x26\xc2\x89\x4a\x42\xd5\xc2\xbb\xa6\x42\x49\xec\x12\xd4\x1e\x2a\x67\xff\x29\xed\x77\x27\x14\x2f\xb0\x72\xba\x75\xba\xab\x0d\x5d\xe1\xf0\xf5\xc5\xb0\x4f\xd6\x39\x7e\x81\x25\x20\x47\xe0\x2b\x67\xc5\x77\xd1\x17\xd3\x78\xa9\x8d\x7c\x8c\x77\x87\x55\x6b\xd2\xd5\x9d\x13\x35\xd3\xa2\xa7\xb7\x1d\x11\xb2\x23\x41\xa4\xde\x14\x56\xa3\x59\x50\xd0\x8c\x8c\x66\xf9\x07\x28\x00\x10\x5d\xdf\x4c\x17\x44\x01\xe9\x30\x02\xfd\x04\x1a\xda\xe7\xd7\x32\xed\xdd\xbe\xa6\xa1\x6c\x84\x02\xef\xa5\xa5\xbc\xd0\x3f\x2e\x05\xb1\x50\x31\x34\xe6\x84\x62\xa9\x5f\x03\xb2\x44\x3c\xaa\x1d\xa0\x95\x13\x74\x59\xf8\x7e\xbd\x36\x73\x8e\x95\xa8\x0b\x0f\xf0\xcf\x09\xbb\x6f\x77\x07\x13\xae\x67\x06\xbf\xd0\xa6\x78\x20\xc5\xc6\xeb\x57\x82\x2d\x8e\xb8\x82\xce\x5a\xfb\xa0\xf1\x9b\x14\x5c\x1c\xa2\x2a\x3f\x00\x73\x8d\x8e\x05\xea\x11\x67\x72\x06\xab\x4f\xe9\x76\xbd\xdb\xad\x8f\xd3\xcf\x00\x01\x52\x0f\x80\xa2\x20\x47\xf7\xd7\xc7\x2d\x05\x8e\xa1\xee\x6a\xf8\x72\xe9\x51\xdc\x8c\xd6\xde\x59\x4f\x79\x50\x20\xe3\x24\xcc\x77\x51\x5b\x3e\x9d\xc4\xd5\x08\xff\xac\x3a\x1f\xff\xb2\x02\xa5\x0a\xff\x4b\x9f\x21\xd8\xfe\x33\x71\x39\xa7\x53\x89\x8b\xde\xd5\xe8\x89\x78\xde\xd1\x41\x0b\x8d\xfc\x0a\xd9\xf2\x10\x54\xc5\xab\xd5\x25\x5f\xb7\x0a\xb6\xbe\x2d\x5f\xb0\x09\x3a\x4d\x8a\x98\x1c\xd6\xa0\x43\xc0\x38\x9a\xa8\x49\x6d\x1f\x6a\x9b\xfb\xbb\xf2\xd9\x1d\xe7\xf6\x40\x08\x44\x94\xeb\x17\x78\x29\x8a\x24\x6d\xdb\xa0\x3e\x12\x5e\x39\x4e\x6b\x31\xf0\x8f\xdd\xfa\xa9\x75\x2c\x7c\x08\x11\xf6\x35\x32\xcd\xbb\x89\xff\x6c\x4d\x8b\xf2\x70\x7d\x48\xa0\xd2\xf0\xf8\x44\x86\xd7\x38\x4c\xbf\xc4\x4b\xca\x28\xdb\x4e\xa5\x59\xcb\x22\xb3\x43\x54\xe8\xac\x7f\xe1\xe0\x65\x36\xcf\x56\x5c\xc3\x25\xd2\x69\x31\xab\xd6\x94\x0d\x83\x25\xeb\x18\x0c\xa2\x4b\xd0\x44\x23\x4f\x34\x81\xe2\x6b\x67\x66\xda\xdb\x9d\x26\x75\xc8\x1f\xc2\x20\x3c\x1c\x88\x26\x0d\x11\xae\x73\x45\x0a\xfa\x0d\x06\x64\x9e\x35\x06\x8a\xc3\xc2\xeb\xa4\x98\xa9\xe0\x01\xcf\x2b\x1b\xee\x00\xcc\x15\xb9\x78\x9b\xed\xf7\x66\x41\x46\x0b\x3f\x0d\xc5\xdc\x5e\x36\x93\xb1\x09\x35\x4e\xc6\xa1\x9b\x14\x58\x76\x69\x72\x3f\x03\x99\xd0\xc0\xbd\x86\x2d\x67\xa8\x29\x10\xc6\xe0\x7b\x7b\xcf\x45\xfb\x43\x9e\xb7\xa2\xb3\xfd\xae\x3c\x62\x06\x4c\x3f\x97\x28\x96\xe3\xea\xe0\xd0\xfb\xba\x46\xa2\x25\x9c\xc3\x95\x91\x89\x8f\x68\x8d\xe0\x50\x05\x54\x78\x87\xa4\x5e\x45\xec\x0a\x3a\x1d\x75\x4c\x8f\x14\x8d\xca\x63\x1c\x97\x95\x23\xf4\x07\xcb\x1b\x0d\xb3\x40\xb8\xb0\x8e\xdb\x77\x18\x20\x3c\xe2\x7e\x7d\x84\xfc\x91\xfd\x44\x26\x37\x6e\xc9\x34\xc2\x14\xaa\x16\xd1\x12\xe6\x2d\x72\xfb\xb5\x2f\x38\xc6\x39\x4b\x53\xce\x34\x21\x0b\x17\x9b\x78\x94\xdd\x7b\x88\xf8\x0c\x27\x2c\x6a\xbc\xdd\xbe\x66\xed\x39\xca\x1e\x2e\x72\x16\x53\xfa\x30\xe6\x6a\xb3\x94\x1a\xb4\xaf\x3d\xcb\x11\x9f\xf1\x6b\xad\xc2\x55\x2a\x32\xfa\xa7\xaa\x98\xa1\x59\xb8\x21\x1c\x17\xe6\x7b\x31\x4b\x86\x60\xfe\xa3\x3a\x47\x37\x3e\x20\x1b\x27\x37\x8d\xf2\x6b\x59\xf0\x8d\xde\xdc\xf1\xb9\xab\x9b\x6b\xaa\x38\xaf\xd0\xed\x17\x5a\x78\x3a\x04\x3c\x48\xf7\xaa\xe4\xea\x76\x66\x4d\x04\x67\x75\x34\xe2\x07\x30\x9f\x3f\x49\x45\x9f\x93\xcb\x43\xfc\xef\x77\xa8\x16\x10\xdf\x8a\xc1\xb0\xd1\x4a\xcf\x1e\x20\x36\xd9\xf2\x4f\x52\xf0\x3d\xdb\xff\x65\xd5\xef\xaf\xba\x86\x62\x0b\x45\x02\x6c\x58\x93\x79\xe5\x1e\xde\xfe\x67\x3c\x8e\xe5\xf1\x7f\x2a\x8e\x19\xfe\x06\x2b\x99\x6d\x13\xe4\x18\x4b\x8e\xed\xd2\xa8\x5c\xf3\x1e\xea\x48\xf2\x04\x95\x8e\x5d\x53\x1e\xea\xc2\x2f\x34\x0d\x01\xbe\x1d\x24\x5c\xb2\xa0\x25\x8a\x29\xf4\xab\x01\x0f\x12\x74\xfd\x25\xdf\x38\x28\x3d\x05\x28\xfc\x83\x59\x73\x7b\x14\x12\x3c\x96\x92\xd0\x54\x12\xbc\xe7\xb3\x41\x54\x3c\xd4\x25\x91\x7b\x25\x53\x40\xfc\xf1\x77\x1e\x85\x50\xe2\x51\x9d\x22\x37\x44\x25\xc1\x77\x29\xed\xb4\x32\x88\x43\x8e\xa8\xa3\x22\xb6\x66\xc0\xb1\x7c\x8e\xaa\xa3\xc2\x07\xa7\xf1\xc2\xbd\xc1\x0b\x8f\xc2\x27\x88\xde\x0b\x90\xe9\x27\x88\xe1\xdd\x8d\xd1\x33\x8f\xd1\x51\xf7\x1f\x8f\xd9\x41\x8f\xc9\x2f\xb0\xd9\x2f\xaf\xf9\x32\x8d\xc2\xfd\xd7\xd3\x63\x8d\x2d\xab\x43\xda\xaf\x9e\x2b\x24\xff\x3d\x9f\x62\x72\x27\xdb\x53\x97\x52\x76\x6f\xab\xa3\xae\x12\x2d\x51\x7d\x2e\x3e\x7d\xa2\xdf\xf4\xa5\x1e\xcb\x1f\x70\xfd\x63\x5e\xfd\x53\x5e\x3d\x56\x87\xb4\x83\xbf\x2a\xc2\xa1\x24\x6e\x8e\x7c\x36\xfa\xbf\xe1\x0a\x69\x6c\xfe\xe1\xc8\xee\x52\x1a\xaf\xbc\x63\xdf\x54\x4a\x88\x24\x52\xaf\x32\x76\x68\xa5\x53\xfe\x5a\x03\x09\xbe\xff\xfe\xce\x7c\x36\xce\xff\x5a\x93\x33\x41\xe8\x43\x47\xdb\xb6\xe0\xa8\x47\xef\x99\x4b\xe9\x58\x2c\x8f\x9e\xb3\xf8\x56\x2c\x8f\x59\xd3\xf7\xa1\x2e\x93\x5d\xa8\xe0\x97\x4b\x47\xf0\x4f\x9f\xfe\xb3\x56\xfa\x9f\xfb\x49\x63\x49\xcc\x5c\x86\x87\xdd\x3a\x02\x1f\xfa\xfb\xd7\x3b\x0b\xd4\xf5\xd2\x28\xa1\x95\xa9\x85\x4a\x99\x21\xf4\x97\x3e\x8b\xf7\xbf\xf7\xbf\xcf\x11\xe8\xaa\x24\xf1\xd6\x3f\xe1\x34\x38\xfa\x0b\xe5\xf1\x4e\x3d\xda\x4b\x63\xf3\x2a\x63\xb5\xff\x43\x96\xd2\xce\xe8\x14\xb9\x3d\x0a\x7e\xe5\x8b\x29\x6c\x4b\x89\x7e\x43\x89\xbe\x72\x1e\xea\x9c\xff\xcc\xbf\x09\xa4\xf6\x2a\x25\xfa\xcb\x24\xfa\x56\x04\xd3\x37\x3b\x66\x09\x91\xf1\x4c\x25\x1a\x2d\xde\xe1\x3f\xbf\x17\x60\xd3\x1a\xc6\xb3\x40\xdd\x36\x9f\xcc\xd1\x0b\x1c\x5a\xf9\x43\x56\x38\x7c\xcd\x22\x87\x30\x78\x93\x37\x7c\x96\x35\x20\x55\x32\x7c\x01\x37\x7c\x51\x34\xfc\x06\x35\x21\x53\xb4\x7c\xe5\x35\x7c\x07\x71\xbe\x96\x35\x07\xe7\x6f\x78\xee\x95\xa0\xe1\x91\x46\x38\xf4\x37\xbc\xe1\x7f\xc5\x33\xff\x47\x3c\xbb\x63\xa8\x3f\xf6\xc7\x0f\x20\xc2\x95\xc2\x37\x8b\xd3\x31\x15\xd2\x37\x47\xa0\xe6\xbf\xd6\x90\xc8\x22\xfc\x2b\x25\xf1\x4c\x90\x50\x75\x79\xa8\xfb\x63\xbc\x3e\x8d\x6b\xca\x2f\xb7\x01\x19\x8f\x21\x08\x9f\x15\x24\x8f\xe1\x0f\x8f\x11\x04\x8f\xc5\x17\xa8\x03\x05\xb8\xd1\x2b\x8f\xc9\xa7\xbc\x25\x08\x88\xcb\x29\xff\x8d\x97\x4a\x74\x5f\x46\xf0\x98\xcf\xee\xdf\xf0\xdc\xff\x05\xcf\xf9\x9f\xf1\xae\x3f\xe6\xae\xa3\xff\x17\xb2\xf8\x87\x8c\x72\xf4\x9f\xf2\x18\x0c\xae\xf4\x9f\x71\xff\xd1\xb7\x3f\xf5\xcf\xc7\x1a\x9b\xa7\xb1\x42\x12\xfb\x0c\x09\x21\x45\x0a\xcf\x3f\xf4\xbc\xe8\x14\xd0\x5e\x48\x24\x0e\x0a\x86\x61\xd4\xc2\x0b\x5c\x36\x94\xfb\xac\x15\xd5\xd2\x7f\x4c\x56\xe4\xe1\xfc\x1d\x0a\xf0\x38\xae\xf2\x38\x8e\x48\x6a\x14\x28\x4f\x7e\x41\xc3\xa7\x8b\x99\x6c\xae\x0a\xc1\xd8\x60\xb8\xb1\x7c\xdd\x2c\xd8\x3a\xbe\x0c\xde\x62\x6b\xb8\x82\x5a\x8b\xac\xf3\xb0\x7d\x6b\xb8\x8a\x28\x38\x1e\xc7\x8c\xce\xa3\x25\x52\xd3\x74\x01\x5a\xa1\x72\x3e\xd7\x31\x92\x8b\x07\x2c\x04\xf4\x40\x4f\xf4\x94\x8f\x1f\xbe\x62\xdf\xf8\x89\xa6\xf0\x24\xd3\x7a\x56\x60\x3f\xf9\x5e\x7a\xe3\x76\xca\x8c\xb0\xc1\xdc\xbc\x0f\x15\xa4\x45\x22\xf7\x65\x97\x67\x59\x99\xd9\x60\x9b\x87\x95\x42\xc7\x6e\x90\xc5\xf5\x95\x56\x81\xbf\x26\xae\xf3\xcc\xee\x8b\x2e\xa3\x0e\x3b\x38\x70\x88\xfd\x88\x6e\x58\xa1\xb4\xd7\x11\x35\x96\xbf\xd5\x47\x20\xc2\xca\x08\x32\xd8\x98\x26\x4c\x89\x38\xea\x76\xa0\x55\x3c\x35\x69\x1d\xa5\x6e\xac\x9a\x8f\x21\x3b\x98\xda\x0d\x5c\x28\x9e\xba\x82\x36\x74\x34\x90\xcf\x7e\x3a\xb7\x68\x14\x4f\x56\x72\x8b\xb9\x83\xae\xab\x58\xc1\x7d\x30\xc2\xf4\x46\x7c\x37\xd5\x47\xbd\xed\x76\x84\x0b\x6a\xe6\x9b\xab\x8d\xc5\x53\x78\x3a\x4c\x34\xe9\xad\x22\xee\x4b\x69\x61\x41\x0d\xa9\x05\xc9\xa5\xaf\x8d\x81\x3b\x03\x94\x44\xd8\x3c\xe2\xa5\xad\x6e\x38\x3d\x4d\x44\x4c\x67\x30\x2d\xe2\xc6\x62\xa2\x29\x24\x35\x16\x6a\xf1\xd0\x51\xc2\x72\x6f\xa1\x70\xf3\x6a\xe6\x4b\x1f\x44\x2b\x8f\x27\x10\x87\xa5\x2d\xc2\x43\x37\xd1\x46\x05\x09\x9d\x4e\xca\x01\x4a\x54\x3b\xe9\x2f\x16\x21\x65\x97\xaf\x04\x98\x2a\xb6\x84\xa8\x36\x63\xda\x25\x34\x0c\x47\x54\xb5\x48\x24\x6d\x33\x35\x80\x61\x6c\xdd\x77\x69\xa4\x36\xdf\x1e\x4b\x89\x19\xc3\x3a\x84\x5b\x62\x36\x7e\x0b\x8b\x26\x0f\x87\x41\x00\xf0\x60\x17\x98\x28\xbb\x6a\x28\xfb\x90\x03\x4a\xb7\x4b\x43\xb6\x2c\x6f\x09\x25\x40\xfb\xa5\xfb\xf8\xdb\x6f\xee\xaa\x87\xf5\x32\xac\xd5\x78\x28\x73\x8d\x9a\x0e\xc4\x19\xb2\xd7\xa2\x69\x06\x02\xa1\xe3\xe7\x60\x84\x02\x8f\x61\x11\x03\x81\x2b\xb4\xf3\x6e\xa3\xd8\xab\xaf\x30\xc3\xc3\x4f\x97\xb3\xc6\x39\x1f\xeb\x17\x50\x93\xfa\x76\xa8\x5f\xc0\x16\x06\x8c\x74\x00\x11\x33\xf9\x50\x0e\x48\xd9\xf2\x07\xf3\xbf\x1f\xa3\x1f\xd4\x31\xfe\x20\xee\x37\xe4\xaa\x21\xfb\xcb\x4a\x7b\x03\xbe\xeb\x19\xdc\x50\x3a\xc0\xb8\x6a\x39\x7b\xad\xc6\x8d\x09\x7a\x9c\xb3\x49\xd0\x07\xde\x49\x7a\xe2\x8f\xdc\x91\x0d\xbd\x98\x90\xcd\x63\x32\x6c\x69\xa2\x2c\x4a\xb2\xd9\xb6\x2d\x89\x4f\xad\x6f\x0c\x75\x33\x66\xb9\xb9\x3b\x28\x0c\x46\x24\x23\xef\xe6\x81\x9f\xb3\x29\xa2\xe6\xa0\x7d\x63\x5b\xa7\x89\x73\xb6\x16\xab\xbd\xd0\x6b\x99\xff\x1a\x8a\xef\x19\x8b\xdd\xc5\x46\xd0\xd5\x69\x97\x76\xb2\x8a\x86\xa1\xc0\xf3\x13\x7c\xd8\x86\x91\x87\x88\x23\x02\x9b\xe1\x7d\xeb\x1f\x25\x13\xc5\xff\x21\x13\xff\x87\x4c\xfc\x1f\x32\xf1\xff\x98\x4c\xb8\x83\x81\x39\x7d\xf2\x9a\x7c\xf8\x87\xf3\xc7\xfe\xe3\xfc\x47\xd6\x15\x52\xce\xe4\x4d\xc1\x80\x84\x3f\x1c\x2b\x64\x04\xca\xff\x16\x99\xf8\x0b\x2f\xfd\x1f\xf1\xfe\xdf\x91\x89\x55\x72\xbe\x96\x33\x7b\x05\x32\xa0\x3f\x9c\x7f\xf3\x1f\xe7\x1f\x88\x82\x3b\xfc\xf1\x3f\xe7\x73\x7c\xe1\xb1\x7c\xe7\x71\xba\xff\x1d\x32\xf1\x17\x9e\x29\xfc\x8f\x78\xff\xdf\x90\x89\xa1\x86\xdf\xca\xf8\x83\x4c\xe4\x7f\x91\x09\xf3\xbf\xc8\x04\x74\xe8\x81\xbe\xb2\x34\x7c\x2e\x65\x18\xd9\xd3\xf2\x0b\x94\x67\x81\x42\xaf\x33\x3d\xe1\x31\x92\x44\x16\x50\x74\x84\x82\x12\xec\x66\x80\x03\x2c\xaf\x4f\x9a\xde\x95\x78\xd6\xe5\x34\x55\x09\x06\x45\x88\x3a\x28\xd2\xc6\x3e\x83\xce\x11\x41\x00\x1c\x81\xe9\x51\x45\x88\x46\xaf\xba\xea\x3b\xe3\x6b\x26\x7f\xf3\x3c\xff\xc6\x5f\x20\x06\xe1\xb4\xa3\xc6\x55\x22\x79\xaf\xbc\xd5\xe7\x86\x3a\xcb\x40\x9f\xc4\x7c\x0b\xd1\xb7\xfd\x04\x1f\x15\x40\x0a\x01\x4a\xfe\x44\x0b\xb8\x49\x75\x34\xf2\x43\x02\x2a\x5b\xc5\x27\x2b\x4b\xa7\xa2\x03\xe7\xdd\x1e\x09\xcb\x64\x8f\x1b\xa6\x22\xde\x29\xe8\x23\xdd\xa0\x7d\x25\x93\xde\xef\xf6\x38\x04\x4d\x51\x73\x57\xf7\xfa\xe4\x55\x5e\x4a\x7e\xdb\x45\x08\x2d\xfb\xef\xbc\xf8\x86\xb8\x64\x35\x12\x99\xf5\x27\x82\xcc\xef\xa9\xc0\xa5\x9b\x77\x02\x48\x7e\xef\xb2\x71\x5d\xc0\x5e\xa6\x65\x01\xa4\xf8\x8b\x8d\x7e\x8e\x0a\x28\x7a\x15\xc6\x72\x6c\xc8\xc4\xcc\x99\x52\xb6\xcd\xfb\xec\x07\xd9\xef\x71\xdc\x93\x2d\x1d\x11\xaa\xd1\x28\x9e\x7f\xdd\xab\x78\xb4\xd8\xb9\x58\xa2\x51\xbc\x64\xed\xee\x46\x06\x7a\x21\xec\xc8\x84\xa9\x23\x6c\x16\xb6\x01\xb2\xd5\x9b\x5f\x6a\xb3\xea\x99\x98\xb4\xb3\x0a\xd9\xed\xb6\x95\x9d\x45\x24\xd0\x00\x97\xb2\x0e\x61\x67\xb8\x5a\x17\x3b\x9a\xa6\x4c\x5b\xce\x06\x0e\xd8\xc5\xf8\x35\xb7\x9c\xe5\x4a\x18\x72\x0f\xd2\x97\x3f\x4d\xbc\x27\x82\xf4\x53\x64\x1d\xc7\xd2\x76\xa4\x06\x29\x34\x5c\x6e\x2b\x25\x30\xf2\x2c\xdd\xb4\x90\x56\x66\xa2\xe9\x78\xee\x45\x0d\x33\x89\x05\xae\xd1\x14\xa4\x51\xb8\x67\x71\x18\x61\x77\x94\x63\x35\x39\x39\xd2\xe6\xc6\x58\x20\x38\xfb\xf9\x09\xd8\x8b\xca\x97\x9f\x87\xd7\xaa\x67\xdc\xc2\xe2\x44\x8b\xca\x94\x74\x06\x79\xf8\x87\x66\x1d\xb9\x05\x1c\x8b\x49\x9b\x05\x50\x3b\xb8\x27\x05\x96\x12\x26\x23\x29\x7f\xb6\x22\x23\x89\x9b\x42\x2f\xa2\xa5\xc0\x1e\x7e\xac\x3c\x23\x17\x3c\xad\x86\xf4\x40\xbc\x9f\xb9\xe8\xfc\xd5\x77\x2d\x09\x6a\xf9\xe6\xd2\x50\x2e\xe0\x2d\x74\x0d\xff\x5e\x8f\xfe\x35\xd8\xdb\x09\xde\xb5\xf4\x69\x5b\x97\x18\x6d\x31\x95\xae\x22\x65\xd5\x64\x9e\xae\xd8\x96\x45\x5c\x77\xd3\x25\x59\xe6\x0a\x3f\xdf\x75\x05\xa1\x9c\x29\xa3\x52\x73\x2f\x4c\x71\x83\x9c\xf5\xd2\x14\x9e\x4d\xd4\x33\xe7\x16\x6a\xb1\x66\x38\x67\x86\x01\x99\x8d\x34\x4f\xcb\x51\xc3\xc7\xbc\x66\x3f\xce\x96\xbe\x42\x3e\x03\x72\x07\xe3\x2d\x57\x20\x16\xc2\x1d\xf7\xf5\x33\x06\xda\xb7\xec\xfa\x07\xd4\x9d\xae\x72\xba\x98\xfc\x50\x3f\xf5\x34\xb3\x50\x48\x20\x53\xef\xc8\x99\x6c\x03\xf0\x87\xcd\x6d\x30\xfa\x38\x09\xbc\x06\xd5\x82\x61\x8c\xdb\xc8\x76\x22\x0a\xb4\xf2\x9f\x6d\x4b\xda\xb7\xf1\xdf\xc5\x25\xda\xff\x3e\x9e\x8d\x1a\x8a\xe3\xcf\xb6\xfc\xe7\x07\xa4\x6f\x6c\x0c\x4b\x06\x9b\xac\x6b\x65\xde\xb0\xfa\xac\x80\xa0\x76\x9b\x22\x78\xb1\x8d\xc8\x8b\x97\xe7\xc5\xd8\x41\x29\x89\x1e\x2c\x3e\x8a\xeb\xb2\x71\x3a\x8a\x0e\x2d\x85\x25\x2f\x98\x4a\x2b\xa9\xcf\xc0\xef\x37\x32\xcd\x55\x3a\x1b\x14\xfa\x3b\xcd\x74\xb4\x26\x73\xe1\xdb\x6f\xfc\x3e\xb4\x04\xe9\xef\x42\xbd\xe5\x7e\x28\xae\x05\xb7\x31\xd1\x90\xd8\x40\x0b\x41\xdd\x73\x19\x02\xb6\x3e\x04\x7f\x25\x01\x9e\x44\x66\xc2\x54\x4e\xba\x86\xe8\x03\x74\xb6\xec\x36\x28\x3c\x00\x94\x55\xe0\x7a\xde\x64\x8f\x12\xf6\xa8\x09\x06\xf3\x15\x87\xa6\xa2\x99\x24\x66\x93\x21\xf7\x21\x54\x02\x77\x21\x75\xc7\x60\xfc\xd6\x28\x5a\x89\x36\x54\x8a\x4e\x18\x10\x83\xb1\xee\x3c\x88\xfa\x65\x7f\xa0\xa0\x13\x97\x68\x53\x57\xc9\x78\x70\xde\xfc\x2c\x7e\xc3\x33\xc5\x5e\x32\x0a\x61\x22\xb6\x01\xc7\x57\xd3\x0d\x19\xb6\x8d\x15\xcc\xe8\xf8\xd2\x63\xfd\x93\xe0\xe2\x14\x47\x36\x8b\xd6\x4e\x7b\x32\xc5\xf6\xf4\x84\xe0\x32\x8e\x46\x9b\xc6\xe9\xdf\xce\x49\xdd\xa1\x72\xbc\x4f\x77\x97\x4b\xca\xec\xa2\x8b\xf4\x03\xaf\x33\x2f\x12\xd8\xa5\x25\x34\xf6\xb2\xda\x2e\x33\x9b\x0c\x02\x12\x7a\xbd\x33\xf1\xb9\x4e\xf2\x57\xaf\x94\x88\xaf\x11\x7f\x00\x9b\x69\xac\x88\xd2\xf5\xb2\x74\x97\x65\xc4\x5d\x26\x80\xa2\x20\xb7\x30\x96\x8d\xcf\x61\xe9\xd3\x5e\xb9\x38\xb0\x3a\x34\x4d\xe7\x10\xc9\xf5\x23\x43\x02\x02\xe8\x8f\xcc\x06\x06\x69\x6a\x99\x2e\x5c\x91\x6a\x2d\x5c\xc4\xc3\x0a\x1b\x1d\x46\xa4\xcf\x53\x03\x36\x71\x7f\xc7\xe1\xdb\x9d\xe7\x57\x64\xce\x04\x61\x6d\x19\x0d\x2e\x85\x1a\x5f\xbd\xd2\x3f\x07\xad\x19\xf1\x3b\x69\xbb\x25\x80\xc8\xa8\xfb\x91\x00\x57\x89\x2d\x73\xa4\xcf\xb5\xe9\xa1\x9c\xd1\xed\xa3\x17\xbf\x86\xb7\x0d\x52\xd6\x6e\xac\x4a\x32\x65\x93\x66\x72\x5e\x97\x82\x8f\x90\x2b\xa4\x0d\x7b\x54\x1f\x69\x8e\x02\xab\x6b\x2f\x9b\xcc\xd0\x20\x39\xa4\xf2\x62\xe2\xfd\x00\x0a\x02\x36\x89\x8b\xaa\x74\x01\x53\x97\x66\x19\x52\xd0\xfe\xe2\x07\xd8\xdd\x5f\x8c\x10\x6d\x8c\x03\x61\xf6\xf8\x95\xf3\xc1\x49\xb2\xd9\x59\xcc\x17\xa5\x8d\xa0\x39\xb8\x73\xe0\xa3\xb2\xe9\x4b\x9f\x67\xb1\xe7\xf8\x85\xfb\x22\xd6\xed\x63\x5e\xba\x0d\x90\x92\x30\x56\x33\x84\x51\x20\x00\xe3\x13\x83\x5f\x0e\xf1\xab\x68\xae\x83\xff\x4d\xe9\x54\x8b\xc7\x57\xdd\xad\x9c\x14\xf5\x1d\x24\x8c\x91\x4e\x61\x96\x3a\xa3\x2e\xca\xff\x64\x20\x70\x34\xd9\xbf\x4b\x77\xff\x6f\x8e\x7f\x47\x70\x0d\x41\x14\xdd\x95\xba\x35\x47\x90\xd5\x90\x08\xb5\xf0\x04\xc7\xcf\x03\xe5\x9e\x97\xef\x59\xd9\xe2\xaa\xd6\x4a\xb0\x21\xcd\x5e\x9a\xc2\x07\xef\xd1\xf4\x61\x72\x50\xb4\x5c\x98\xb8\x56\x0c\x12\x4d\x0a\x0f\x1d\x72\x91\x46\x3f\x4c\x6e\x44\x53\x38\x45\x81\xcf\x63\xc6\x65\x9e\xaa\xcf\xaa\x40\x0b\xa0\x49\xf4\xba\x52\x61\x7f\x31\x35\x99\xb7\xd2\x36\x4e\xc2\x1d\x3c\x27\x71\x10\x5a\x15\x06\x16\xb0\xd3\xe2\xb7\x8f\xbf\xc3\x6e\x9d\x11\x41\xc3\xb4\xa0\xc0\xe3\x47\x2b\xf0\x6b\xc8\x0d\x24\x30\x94\xfc\x63\x0d\x08\x1b\x43\x91\x69\x97\x04\xa5\x6a\xcf\xe3\x9d\xd0\x44\xd7\x5a\x0b\x29\x89\xd4\x8a\x27\x95\x47\xe2\x82\x9f\x7c\xdc\x02\xb4\xd2\x0b\x74\x45\x42\x31\xed\x7f\x04\xd0\x38\xcd\xbd\xcf\xed\x27\xf9\xe7\x46\x98\xed\x4e\x0c\x49\xba\xc5\xfd\xad\x43\x92\xd8\x0a\x23\x1a\x10\x90\x55\xcf\x77\xb4\xc3\x92\x74\xfc\x02\xcd\x74\x77\x6d\x58\x2b\x45\x61\x57\x4d\x71\x0f\x05\x56\xc9\x22\x26\xdb\xd8\x6d\x0b\xd0\xb0\xda\xf8\xc6\xf9\x81\x4b\x25\x09\xf9\x62\x26\xeb\x3f\x51\x59\x58\xe3\x9a\x1b\xf8\x5d\x15\xcd\xda\x26\x1b\x85\xa4\x08\xb5\x14\xa1\xe8\xa6\xe5\xfa\xc6\xc7\x7d\x71\xb7\x61\xc4\x9b\x17\x18\xc5\xe2\x07\xae\x98\x14\xa3\xec\x1c\x7d\x37\xcb\xe8\x36\xd2\x52\x1d\x1b\x6a\xfd\x84\xe0\x80\x33\xb6\xd5\x36\x34\xee\xe6\x47\x4b\x36\x91\x7e\x9d\x7c\x73\x95\x6d\x37\x5e\x00\x92\xde\x17\x23\x73\xad\x09\xa2\xd8\xd3\x0f\x5e\x30\x05\xfc\x2e\x8f\x73\x73\x18\x7f\xc2\x21\x11\x0e\x67\x3b\x77\xa5\x4a\xb8\x29\x39\x4e\xf3\x2e\xa4\xea\x9d\xbf\x14\x7a\x2c\xfb\x93\xbe\x18\x9e\x79\xbb\x56\x17\xf2\x5f\xc4\xa4\xad\xb5\x84\x2b\xfa\x11\xdd\xc6\x06\x1d\x0b\x33\xd8\x2c\xd4\x37\x27\xec\xf9\xa0\x83\x06\xe6\x37\x02\x3e\xe3\x3d\xff\x00\x8b\x2f\x7c\x2b\x5c\x52\x13\x7d\x70\x94\x4c\x18\x19\xc3\x42\xdd\xf4\x3d\x90\x19\x80\x91\x16\x24\x02\x30\x2e\xc2\x9b\xdd\x3c\xbb\x20\x67\x47\xf8\x52\xed\x13\x8c\xc9\x3c\xbf\xeb\xa1\xc8\x26\xe1\x24\xee\x89\x05\x2d\x54\x2f\x2e\x12\x77\x09\xad\x5a\xf8\x32\x41\x15\xb3\x78\xc2\x2a\xb1\x80\xa3\x16\x48\x42\xfd\x98\xf4\x25\x5d\xbe\x15\xba\x13\x9c\xe9\x12\xe9\x98\x10\x5b\x52\xc4\xc0\x2e\x79\x01\xa9\xd0\x2d\xc3\x1b\x6b\xa1\x91\x76\x1b\xda\x4a\xd3\x9a\x62\x88\xed\x24\x6d\x0d\x87\x10\xce\x6f\x10\x9e\x23\x24\x07\x1b\x6e\xad\x61\xdb\x2f\x14\x20\x21\xab\x86\x58\x77\x40\xc2\x72\x09\xb3\x5d\x9a\xf6\x7a\x26\x5c\x68\x59\xc0\x36\xa0\xd6\x4c\x01\xba\x46\x3c\xbb\x4f\x6f\x69\xfb\xaa\xeb\x73\xb7\xaa\xc3\x9e\x39\x82\x46\x70\x5c\x8d\x4c\xda\x8e\xb6\xb4\x99\x9c\xb5\x28\x7d\x9e\xd1\xb3\xa3\x11\x75\xee\x66\xce\x94\x5f\x44\x39\x46\xcb\xe3\x18\x72\x05\xf9\x03\x46\x18\x3d\x91\xfb\x86\x5d\x98\x62\x30\xac\xb5\x75\xa8\xd0\x93\x39\xf3\x9f\x6f\x81\xff\x5c\x0d\xe1\xd1\x7c\xff\x32\xdb\xf1\xf7\xd6\xa5\x3f\xdb\x91\x13\x3b\x37\x3e\xcf\xaf\xcb\x43\x99\xc5\x63\x18\xd6\x2e\x8b\xc3\x68\x39\x11\xd1\x0d\x84\x19\xdc\x17\x42\x3d\x1b\x1d\x5c\x64\x90\xa9\x01\x16\xa6\x29\xaa\xab\x31\xa8\x2f\x44\xc1\x75\x02\xd7\x64\x3d\xa7\xe4\xa3\x51\x77\x4c\x64\xdc\xcf\x8a\x9a\xab\x74\x4f\xaf\x82\x14\x17\xeb\xc7\xef\x9f\x41\xe2\xdf\x5c\x5b\x53\x38\x4d\x47\x90\xbc\xd7\xef\x05\x00\x94\x78\x6b\xab\xf2\xe0\x6d\xfb\xf8\xe3\x92\x11\x9b\x24\x98\xd5\x1e\x23\x94\xff\xe5\xc8\x2e\x57\x0f\x78\x16\x85\x1c\x31\x65\x9e\xc6\x28\x34\x58\x08\xc0\xa2\x7b\x67\xa2\x5f\xeb\xcf\xf2\xe9\x10\x04\x40\xe3\x1d\x86\xa0\xfd\x27\x7e\x56\x38\xf6\x6c\xa9\x59\xa9\x29\x67\xdf\x15\xfa\x64\x85\xdf\x22\xe0\xa5\x6c\x4f\x77\xa9\x0a\xa0\x2a\x0c\x4f\x79\x84\x0c\x2e\xe5\x63\xfa\x2d\x8e\x1d\xde\x61\xf5\xe6\x07\xd7\x5c\x7c\x7e\xb0\xd2\xae\x7e\xf0\xad\xd6\xa8\x0f\xb4\x61\xa5\x70\x47\xcc\xf3\x73\x05\x4d\xe1\x64\x61\x5f\x92\x24\x36\xe2\x6b\x2c\xa2\x69\x3b\xf5\x66\x4a\x48\xf8\xe5\x06\x09\x2c\x20\x66\x60\xdc\x46\x37\xd2\x75\x36\x78\x63\x95\xcc\x4f\x48\x2a\xa8\x94\x56\x42\xbe\xaf\x49\x5e\x73\x99\x83\xa3\x9a\x36\x66\x91\x1b\x64\xc7\x7a\x13\xc1\xfe\x3c\xf5\x76\x10\x96\xc0\xfd\x09\x37\x53\x09\x15\xf7\xb6\x9b\x88\x3b\x37\x4c\x75\xc6\xf2\x55\x5e\x6e\x43\x3b\x94\x6d\x41\x38\xab\x71\x11\xa5\x60\xd6\xe3\xee\xaf\xa2\x59\x88\x8e\x24\xbb\xa6\x17\xa6\x90\xdf\xf2\x84\x7a\x1c\x15\x0e\x6f\x37\xd0\xdb\x8e\x55\x08\x40\xa2\xd3\x1a\x2d\x72\xff\xeb\xce\x4f\xe1\x87\x49\xf6\xcc\x4d\xe0\x7c\xb1\x71\xbc\x42\x28\x92\xb3\x40\x4c\x86\xf2\x8b\x32\xb9\x63\x1e\x90\x06\x0d\xf4\x93\xd0\x04\x4e\x12\x89\x7e\xca\x59\x76\x0c\x4f\x2d\xc4\xc2\xb8\x88\xeb\x72\x93\x63\xf4\xdd\x8e\x72\xca\x0b\x77\xde\x6a\xbf\x1e\x17\xb7\xa2\x1f\x57\x2f\xd3\xb4\x18\xeb\x02\x6a\x78\x53\x6b\x76\xea\x1d\xc4\xad\xd8\xcb\xc5\x34\x43\x43\xa2\xd3\xce\x1e\x9b\x1c\xb3\x08\x0e\x80\x03\xc8\x49\x36\xd1\xdd\x51\x2b\x29\x8b\x3a\x97\x4f\x7d\x3d\x15\x7b\x11\x2e\xb4\xa6\xbf\xd3\xdd\x95\x7b\xfa\x6d\x07\x9f\xad\x9b\xb6\xca\x2a\x86\xa0\xcd\x99\x93\x34\x44\xc6\xd2\x80\x2b\xb9\x7f\xd0\x98\xdd\x6c\x66\x53\x8b\x0d\x05\x36\x4b\x55\x92\xf0\xa8\x96\x3f\x31\xd4\x55\x72\xa0\x0a\xea\x09\xe6\x66\x0d\x97\x72\xe4\x3d\x29\x17\x93\x9e\x4a\xb0\xd7\x58\x2d\x09\xa2\x47\xb9\x46\x5f\x45\xb4\x3f\x06\xad\x6f\x39\xf5\x19\x27\x3c\x02\x4c\x0d\xfc\x4a\xe4\x7f\x65\xc3\x97\xa3\x42\xdd\xcc\x87\x3b\x2f\xa2\x3d\xfb\xed\x56\x0a\xe9\x58\x7c\x5a\x58\x3f\x28\x95\xd1\x0d\x69\x15\x9e\x55\xc8\x6f\x83\x89\xe3\x1c\x50\xd1\xb4\x1f\x46\xc1\x6e\x13\x58\x87\xa5\x28\x92\x45\xc0\x12\x35\xc0\x85\x32\x38\x0c\xcc\xd9\x0f\x84\xb8\x10\xc2\xbe\x15\x83\xd1\x7a\xd4\x06\x91\x24\xd0\x9a\xe4\x1f\xe5\x1b\x5d\xfd\x2f\x2b\x21\x98\xdc\xbf\x9f\xe5\xfc\x9f\x4a\xc2\x2d\xf9\xe4\x68\x3f\xc6\x5f\xa2\x9a\x45\x14\x08\xe3\x1b\xa8\x7b\x66\x4a\x2d\xcd\x42\x0d\xac\x2f\xd0\x45\x0b\x2f\x49\x09\xf9\x2f\x7c\xd8\x36\x3e\x65\xaf\x9d\x10\x3c\x91\x58\xd5\x75\x56\x26\x61\x79\x21\x5a\x33\xc1\x16\xda\x61\x2f\xc3\x35\x7f\xfb\xef\xaa\x2c\xcc\xa8\x53\x9e\xf3\xa3\x3c\x3b\xab\xba\x20\x51\xc2\x56\xbe\xce\x62\x48\xd2\xb2\x65\xe4\x55\xb9\xc2\x93\xca\x06\x39\x87\xdd\x61\xb4\xa5\x16\x97\x13\x24\xc3\xdf\xc1\x78\xee\x7a\x85\xe6\x3b\xf7\x30\x5a\x13\xb1\xd5\xf6\x0d\x25\x33\xa3\xe1\x2b\x4e\xf9\x82\xba\x05\x5c\xe8\x99\x04\xb6\x3f\x30\x32\xe7\xe7\x40\xa1\x01\xd0\x5a\xbe\x92\x46\x00\x6d\x7e\x9d\x18\xf8\x74\xaf\x9c\xcf\x45\xc2\xdc\xb5\x0b\xd3\x69\x93\x4b\x20\xbf\x58\xb4\xbe\x7b\x4d\xe5\x97\xb4\x1a\x2f\x4f\xfd\x1a\x12\xf2\xbb\x1c\xbe\x64\xc7\x5b\x49\xb3\xd3\xc1\xcf\xba\x85\x91\xe3\xee\x96\x00\x13\x80\x39\x09\x60\x53\x71\x39\x53\xe1\x77\x80\x3d\x10\x6a\x8a\xbf\x87\x0a\xcd\x33\x25\x69\xa2\xa7\x37\x90\x6f\x98\x7b\x99\xee\x8d\x1b\xbb\x91\x99\x44\x48\x14\xb0\x9b\x53\x66\x66\x1c\x7a\x0b\x7b\x81\x1f\xa4\x36\x66\x8c\x2c\x3b\x11\xdb\x89\x87\x6c\x60\xe1\xbc\x4c\xe1\x64\x87\xd8\x33\x10\x6b\xcb\x84\x99\x74\x6b\x51\x30\xb7\x22\x05\x2f\xc2\x85\xaa\x98\x2a\xf3\xa0\x8d\xaf\xca\x6c\x0f\xea\x63\xa0\x62\x48\x93\x3a\x54\x91\x12\x79\x1f\xae\x35\x0a\xbe\x96\x6d\x8e\xbe\x7c\xec\xe1\xbc\xc7\x25\x2d\xf5\xf3\x15\x9e\xda\xa1\xbb\x7a\xaa\x90\x87\xa4\xc3\x28\x29\x5c\x1b\x86\xaa\x16\x9f\xa0\x16\x30\xd2\x80\xcd\x65\xc8\xd5\x81\x7d\x05\x67\x24\x0e\x1d\x58\x4e\x46\x01\x8c\xe0\xce\xc5\x76\x4e\xf2\x4c\xd5\x0a\xd0\xdb\x1a\xe8\xc1\x64\xac\xe2\x5d\x89\x67\x70\xa2\x0e\x2c\x86\x65\x68\x50\xda\xb9\x35\x53\xe4\xfb\x47\x89\x56\xeb\x50\x08\x6a\xe1\x6e\x1d\x11\xc4\x11\x48\x0c\xdf\x9a\x2f\xea\x9a\x2e\xdf\x17\x26\x06\xcb\xfa\x53\x3a\x94\x4a\xf4\x89\xbf\x5b\x8e\x5e\x5b\x2a\xab\x61\x35\xb0\x23\xe0\xb9\x64\x47\xbb\x98\x92\xe6\xc3\xc6\x21\x56\xa1\x9c\x3e\x65\xe4\x0b\x69\x2d\x6c\xe0\x6d\x68\x23\xfa\xe3\x54\x4b\xf9\xfc\x90\x60\xf8\x1d\x71\xf1\x73\x4c\x78\xde\x1c\x92\x7e\x85\xf8\xf6\x27\x02\x1f\x17\x36\xc3\x8d\xc2\xc0\x05\x07\x4f\xef\xa4\x83\x19\x42\x1e\xc3\x97\xc8\x02\x1b\xca\x59\xd0\xcd\x94\x00\xe0\xa0\x3f\x39\x04\x06\xe2\x22\x57\x76\x49\x33\xf0\xf6\x55\xc1\xa2\xad\xdd\xf8\xd0\x4f\xa1\x47\x5f\xd3\x00\x27\xf8\x55\x61\x7d\x3a\xdb\x60\xd0\x39\x67\xc2\xef\xfe\x8b\xb4\xf8\x29\x0f\xbb\xb9\xbc\xe2\x0e\x98\x09\xa7\xe2\x14\x47\x22\x98\x70\x5e\xfb\xe8\x6a\x37\xf8\x3a\x9c\xa2\xa4\x5c\xe8\xe0\xef\x90\xed\xfd\xba\x19\x0e\x3b\x39\x7a\x6b\xe7\x3d\xbd\xfe\xe1\xa6\x84\xe3\xf9\x97\x75\x25\x54\xea\x7f\x27\x12\x82\xdf\x61\x49\xb0\xe0\xd8\xf5\xfe\xc6\xdd\xfb\xb1\xcd\xa9\xa8\xde\xcb\xb5\x29\xcb\x0a\x22\xa7\xad\x9a\xac\x2f\x44\xd5\xac\xc2\xcf\x9c\x29\x4e\x6e\x64\xaa\x19\x52\xa5\xf3\x3d\x25\xd6\x5b\x95\x89\xb8\x66\x58\x8c\xc6\x35\xbc\xce\x65\x3d\x0d\xa1\x3f\xec\xa5\x01\x05\x2e\x41\x99\xfb\x89\x39\x6a\xf8\xf6\x3c\xf7\xc3\x37\xae\x8e\xf7\xce\x09\x50\xdb\x24\x54\x4b\x22\xd2\x38\x27\xfb\x72\x1f\x31\xd6\x65\x49\x07\xe7\xaf\xbe\x7e\xbf\xbe\xda\x09\x92\x40\xaa\x1c\x3d\x3e\x87\xa0\x4f\x51\xbd\xed\x7d\xb3\x6c\x0e\x30\x58\x61\x7a\x9e\xb5\xed\xb0\x63\x0c\x70\x4b\x9a\x76\xeb\xcb\xd8\x48\x2f\x00\x8b\x5e\x14\x25\x6c\xbd\xa2\x2b\x87\x57\x4a\xa9\x4b\x26\x90\x59\x3e\x3c\x6d\xcc\x14\xac\xd8\x2b\xc2\xef\x99\xda\xcb\x44\x96\x2d\x8a\x05\x12\xa2\xed\xbd\xbe\x33\x9f\xd6\xd7\xf9\xf5\xa0\x18\x0f\x24\x5e\x38\x99\x27\x18\x95\x11\x07\xd4\xf3\x0e\x36\x03\xca\x7d\x09\x12\xa0\xee\x16\x6f\x2f\xac\x07\xd2\x91\x32\x53\x61\x0c\xe2\x57\x7a\x1a\x69\x81\xa5\x66\xa1\xfe\xf4\x08\xd9\x53\x30\x2a\xc8\x92\xc6\xc5\x19\xa3\x0a\xcf\x09\x62\xac\x55\x76\x8c\xc0\x43\xd4\xaf\x73\x78\xe4\xd7\x59\xbf\xea\x79\xdd\x25\x29\x50\xee\xda\x99\x5c\x97\x18\xa6\x4f\x9b\x8c\xbc\x9a\x54\x42\xd0\xc8\xe0\x4a\xf6\x5a\x1e\x4d\x2d\x50\xc2\x77\xd9\xd1\xe8\xb2\x0c\x51\xd9\xb7\x37\xb7\x8d\xa7\xb6\x21\x29\xe0\xb5\xe7\x35\x32\xcb\xab\x17\x00\x93\xf6\x17\x8d\xb5\xb6\xdf\xed\xda\x71\x2e\x4d\x64\x42\x40\x2f\x38\xe0\x08\x68\x83\x2c\x57\x18\xf1\x13\xe2\x15\x08\x92\xb3\xce\x44\x5d\xbf\x70\xcd\x07\x8f\xfe\x01\xe5\x62\xff\x60\xc1\x8a\xd2\xcc\x81\x5e\x71\x79\x1a\xc4\x2e\x5c\x61\xd9\x05\x46\xc1\xce\x2b\x6d\xd5\xf5\x13\x0d\x1b\x28\xbc\xd8\xcd\x37\x00\xc2\x50\xd7\xc8\xe6\xea\x03\x0e\x33\xd2\x0c\x85\x90\x4c\xa8\x81\x52\x08\x93\x45\x17\x30\x17\x93\x03\xa1\xf7\x21\x61\xb2\xaa\x53\xcb\xcb\xbf\x04\x65\x0a\x17\xb3\x56\x84\x91\x18\x7c\x05\x23\x14\xfe\xd1\x15\x74\x99\x8d\xf7\x6b\x69\xeb\xe6\x7e\x6b\xc5\x0d\xdb\x95\x9e\x9b\xff\xe6\xf3\xea\x6e\x0f\xf8\x43\xb8\xfe\xba\x6e\x86\x67\x54\x0e\x24\xc7\x8f\xf9\x9c\xe9\xfe\x27\x1d\xf1\x9d\x5d\xff\x2e\x5d\x5b\xc5\xbf\x93\xf7\x3f\x4b\xf9\xec\xf8\x58\xb5\x3c\x86\xee\x2d\x70\xb4\xd0\x31\xc4\x52\x89\x1d\xd6\xe4\x1c\x76\x87\x08\xcd\x06\x58\xca\xe2\xa5\x16\x30\x6a\x2c\x07\x31\x65\x97\x04\x1c\x1b\xfe\x7f\xcc\x7d\x79\x93\xab\x46\xb6\xe7\xff\xfd\x29\x88\xf2\xf4\xb8\x7b\x64\x01\xc9\x4e\xdd\x7b\x3d\x0f\x09\xb4\x82\xf6\x0d\x4d\x4c\xbc\x60\x07\x89\x4d\x80\x58\x54\x53\xdf\x7d\x22\x41\x52\xed\xb6\xfb\xb5\x5f\x84\xc3\xbe\x25\x29\x97\x93\x67\xf9\x9d\x5f\x26\x14\xaa\x53\xba\x86\xd2\x49\x8e\x31\xab\x4e\xe7\x4e\x67\x91\x2f\xc7\x7d\x96\xb4\xf3\x34\xc9\xb8\x69\x16\x69\xe9\x11\x2f\x03\xb3\xa5\xb3\x97\xb8\xbc\xe4\x01\x27\x91\x98\xb1\x38\xcc\x8e\xa1\x57\x9d\xfd\x2d\x3e\xe9\x55\xc4\x28\x12\x8f\x92\xe0\x9c\xa7\x7e\xbc\x1b\xf1\x31\x29\x73\x4a\xe7\xb4\xf1\xa9\x29\xaf\x0e\x4a\xcd\xe2\xe2\xdd\x79\xe1\x1b\xfd\x29\x3b\x9e\xc9\xae\xbd\x12\x37\xeb\x53\xb1\x76\x3c\x67\xa4\x54\xd4\xd6\x0d\x18\x5f\xda\x0d\x0e\xa5\x6a\x93\xbb\xb0\x53\x2d\x26\xf8\xbc\x83\x11\x63\x6d\xc0\xea\x99\xe2\xaf\xcb\x68\x31\x12\x8c\xea\x34\x76\xcd\xa9\xe6\x66\x6c\x4b\x1c\x51\x7c\xd8\x22\x8c\x7c\x15\x16\x55\xb8\x33\x52\xbd\x75\x94\x8b\x11\x95\x38\x76\xa0\x88\x62\x7f\x7b\xca\x43\x6b\xd7\xdd\x2f\xf9\x89\xc8\x06\x51\x4e\xbb\xfc\x44\xe4\x68\x85\xaf\x38\x46\x8c\xb3\x88\x4e\xd6\xc7\xf3\x88\x9a\x55\xa4\x2a\x8e\xe2\x8a\x99\xf7\x47\x33\xad\x3a\x75\x5a\x93\x83\xdd\xa2\xc8\x9d\x4c\x10\x78\x86\x1b\xc5\x74\x7f\xb4\x93\xc9\x2e\xed\xac\x4f\xfb\xb3\x23\x0a\x4c\x57\x97\x4d\xc1\x13\x0a\xcd\x3a\x82\xfd\x9a\x97\x83\x19\xb7\x70\x99\x25\xcb\xf5\xd3\x7e\x79\x98\xc6\x7c\xcf\xbc\x8c\x47\xda\x66\x3f\x74\x3b\x4e\x5f\x58\x5e\xc6\x04\x28\xb0\x42\x4f\xc2\xee\x91\xb3\xce\xbb\x96\xa4\x08\x07\x4d\xdb\x9f\x67\x03\xb3\x58\x9b\x83\x4d\x4f\xf5\xcf\xe7\xfe\xac\xdf\x9d\x2e\x8a\x42\x3d\x38\x74\x72\x9a\x16\x86\xb1\x38\xb6\xc8\x75\x89\x0f\xa5\x3c\xcc\x82\x74\xd2\xa7\xf6\xc1\x5a\xab\x64\xac\x10\x8a\xf1\x60\x3d\xb1\xf7\xf6\x6a\x3c\xc1\xf7\x0b\xad\xe0\xbb\x91\xcd\x9d\x46\x58\xac\x08\xd5\xa0\xa2\xc7\x47\x41\x59\x1d\xd3\xa5\x34\xca\x42\xc5\x0a\x15\x56\x52\x36\x8a\x56\xe8\xd6\x41\xb9\x8c\x16\x2e\xc3\xea\x3b\x49\xf5\x86\x3b\x49\xd8\xac\xb6\x34\xbe\x94\x04\xf7\x72\x2a\xec\x53\xd2\x31\x76\x25\xb5\x99\xba\x6a\x40\x2d\xd2\x89\x33\xd0\xd3\x51\x6f\x5a\xed\x57\xe9\x1c\x28\x93\x96\x6b\x44\x6e\xb4\xf6\x8f\x3d\x4f\x59\xb5\x56\xf3\x5e\xac\x14\xbb\xe9\xa1\x1f\xef\x1c\xa9\xb5\x2b\xfa\x47\x30\xa1\xe3\xde\x28\x1b\x4f\xba\xd6\xe9\xec\xa8\xfd\x73\xdc\x5d\x74\xf4\xae\x38\x8d\xf1\x71\x67\x64\x50\x9b\x68\x46\x9a\x55\x67\x3a\xd9\x72\xe7\xca\xec\x38\x9d\xc1\x7a\xe5\x9e\xe6\xe3\xee\x91\x0c\xa4\x3d\x26\x47\xeb\x7e\x6b\xd1\xf1\xa2\xd1\x94\xdd\x68\x89\x50\x48\x42\x98\x1d\xd4\x99\xb7\x5e\x6f\xf9\x81\x4b\xe9\xc4\x82\x3d\xf2\x07\x9e\x73\x27\x24\x5b\x6e\x4b\xce\xee\x0b\x19\x69\x0d\x05\x73\xa3\xc8\x61\xeb\xbc\xce\x5b\x3a\x31\x5e\x58\xcb\xee\xfe\xb0\x1f\x79\x1d\x5e\xdf\xf0\x87\xe1\x85\x88\xec\x04\x74\xc6\x79\x6e\xb2\x7d\xde\x5c\x74\x39\xdc\xd7\x2c\x7c\x70\x99\x66\x2d\x63\xbb\x09\x93\xe5\x58\x4c\x94\x51\x75\xf4\xec\x62\xd2\x89\xbb\x8e\x84\xad\x05\xdf\x97\x76\x67\x3b\x10\xcf\xdc\xde\xb7\xed\x3c\x0f\xb8\xdd\x72\xce\xe3\xf5\xdf\x3c\xc2\xe3\x1e\x6b\xe0\x5c\x44\xcd\xfe\xe4\x9b\x02\x45\xf0\x15\xaf\x3c\xbc\x22\x96\x34\x77\x5a\x65\xe0\x7f\x33\x5c\x2d\x49\xad\xec\xc7\x39\xb3\xb9\x5f\xfe\x4e\x76\xd3\xdc\xa9\x2b\xc6\xca\x5a\x65\x25\xff\x49\xfc\x8c\x94\x81\x1f\xa6\x3f\x7e\x76\xb3\x2c\x7e\xc4\xb0\xa2\x28\xd0\x82\x44\xa3\xc4\xc1\x08\x1c\xc7\xa1\x98\x9f\x91\xdc\xb3\x8a\x4e\x54\xfe\xf8\x19\x47\x70\x84\x25\x10\x80\xe3\xf7\x72\xaf\x95\x6f\xfd\x5e\x59\x5a\xf0\xc7\xca\xd2\x92\x0c\x4a\x34\x45\x69\x01\x0e\x9a\x8a\xb4\xd7\x26\xf8\x0e\xc5\x71\xfa\x4f\x2f\x47\x6b\x11\x86\x69\x51\x9f\xd7\x43\xfd\xa4\x3c\xab\x85\x1b\xda\x57\xe5\x5f\x49\x40\x7e\x2c\xff\xaa\x1b\xb8\x69\x7e\x3e\x9e\xa2\x3e\x29\x17\x4b\xe8\xc0\xfc\x42\x1d\x9a\xfd\x58\x9e\xd5\x60\x79\xd3\xf8\xa2\xbc\x2c\xc3\x7f\xac\xa6\xab\x6b\x1c\xa5\x7f\x55\x5e\x16\x7c\x2c\x77\xab\xe9\x0c\xa7\x7d\x31\x9e\x27\xa9\x8f\x15\x60\x0d\x8a\xe6\xb9\xff\xf6\x72\xb1\x1b\x9e\x1f\xa0\xc4\x06\xb8\x14\xfd\x79\xcd\x58\xf0\xbb\x35\x63\x3f\x8a\xf8\x57\x0b\xc7\xbe\x97\xcf\xa3\x00\xe1\x01\x0a\x64\x0a\x65\x11\x96\x40\x69\x97\x44\x79\x9f\x40\x39\x04\x10\x75\x3d\x75\xaa\x0d\xdf\xb8\x14\x4a\xfb\x24\x4a\x22\x80\x44\x08\x94\x6f\x03\xd2\x25\x51\xce\x6f\x53\x28\x83\x00\x0e\x65\xdc\x36\x25\x03\x16\x61\x59\x94\xf0\xdb\x24\xca\x22\x80\x44\xf9\x01\x8f\x82\x4b\x40\x10\x28\x40\xf0\x4d\x2d\x9b\x46\x59\xbf\xae\x38\x4e\xa0\xec\x4d\x36\x0b\x5b\xf3\x46\x08\x89\xd2\x1b\x96\x41\xa9\xab\x0c\x0a\x65\x61\x1b\x5b\x7f\x6c\xc3\x8f\xf9\xad\x8d\xa9\xcb\x89\xb3\x08\xee\xb7\x19\xd8\x07\xa7\x53\x28\xf0\x29\xa8\x39\x89\x72\x08\xd5\x14\x8c\xe7\x5c\x4a\x66\x88\xda\x44\xb7\x4d\xa1\x2f\xd5\x7a\xff\x4e\x90\xb6\x6d\xff\x6e\x6d\x6a\xe2\x8f\x91\x00\xe0\x6e\x24\x40\xe3\x28\x4e\x90\x0d\x0f\x5c\x5b\x89\x97\xd6\x7f\x8b\x08\x1a\x2e\x79\x8f\x47\x86\xa4\xf8\xcf\x4b\x47\x7f\x04\x2f\x8b\x03\x92\xd1\x7f\x13\xbc\x5f\x7a\x82\xfc\x83\x9e\x00\x28\x0d\xc0\xd5\x17\x00\x65\xc1\xb5\x4a\x37\x43\xa3\x44\xdd\x4e\xbc\xb4\xff\xf5\xbd\x71\xcf\x13\x86\x42\x49\x84\xa6\x51\xda\xb8\x55\xe6\xaf\xeb\xcd\x93\x6d\x1a\x05\xf0\x85\x45\xc9\xba\x92\x7b\x9d\x23\x10\x7a\x5c\x9d\x3d\xec\x92\xe0\x51\x06\x61\x48\x94\x41\x08\xd8\xc7\x50\x06\x9c\x89\x12\xcd\x0c\xa6\xcd\xa1\x74\x9b\xa8\x6b\xe5\x37\x25\xd9\x39\x98\x04\x6d\xd0\xa6\xe1\x2a\x4c\xfd\x52\xcb\x83\xab\xc2\x71\x80\x45\x9b\x1a\xf3\x08\xd1\xd4\xc6\x6f\xf2\xe8\x5a\x25\x1e\x34\x05\xe9\x51\x06\x81\x39\xc0\xa2\xa0\x49\xc5\xba\xac\x3f\x81\xb7\x01\x4a\x23\x4c\x53\xcc\x1d\xe6\x20\xd5\xae\x6b\xb7\xf3\xf5\x1b\xa6\x16\x84\x12\x08\x83\xf2\x75\x9d\x7a\x1c\x25\x11\x3c\x68\xf3\x28\x8f\x00\x1a\x25\x0d\x94\x6e\xca\xd7\x43\x7b\x91\xba\xda\x3c\x51\xbb\x81\x6d\xcc\x87\x62\x01\x4a\xb4\x99\xba\x19\x00\x94\x87\x3c\xc1\x22\x44\x5d\x20\x9e\x42\x50\x0a\x61\x51\x0e\x4e\x25\x10\xaa\xd6\x80\xad\x4d\xa2\xa1\x26\x4c\x9b\x40\xd9\x80\x80\x7c\x00\x5c\x80\x02\x03\xaa\x42\xd5\xf5\xe6\x89\xa6\xea\x7c\xbb\xae\xd9\xcf\xb4\x01\x4c\xf0\xf6\xbd\x52\x3d\x59\xeb\xe1\x02\x94\xde\x90\x5c\x53\x99\x1e\x47\xea\x0a\xfb\x57\x2b\x50\xf6\x12\x50\x08\x5e\x6b\x0f\xe7\xe2\x8d\x97\xea\xe0\xbd\x96\x5f\xcf\xcd\xeb\xe1\x50\x79\x1a\x25\x5d\x94\x37\x3e\x0c\x6b\x83\x5a\x33\x18\x93\xba\xa0\x7f\xed\x49\xa8\x48\x1b\x5a\x68\xa0\x2c\x4a\xc0\xe8\x40\xed\xa0\xbb\xae\x75\xf7\xeb\x0f\x4d\x94\x98\x3a\x08\xcd\x14\xb2\xfe\x04\xa0\xc6\x4c\x53\x89\x9f\x6a\x54\x46\x69\xb4\x99\x72\x2d\xf5\x5f\xff\xcf\x40\xa4\x34\x62\x78\x68\x0b\xc4\x0c\xec\xe5\x51\x0a\xca\x82\x3a\x73\xb5\xc2\x75\x49\xff\x5a\x3f\x12\xc1\xaf\x35\xff\x01\x44\x56\xa3\x6f\x1b\x2a\x09\xad\xbd\x01\xa1\x66\x69\x0e\x82\x8f\x32\xa0\xb9\x64\x13\xe6\xda\x55\x3c\x0a\xe3\xc9\x34\x16\x7d\xa9\x0a\xd9\x04\x0b\x0a\xae\xcd\xa2\x11\x02\xea\x52\xbb\xfc\x1a\x86\xdb\x10\x0e\x4e\xab\x1b\xa1\x3b\xdc\x36\xca\x37\x6b\x36\x6a\x93\xed\x1a\xc0\xa0\x66\x77\xe8\x6c\xce\x68\x43\x9c\xa3\xa0\x5d\x8f\x21\xda\x74\xed\x57\x68\x15\xdc\x48\x70\x88\x29\xf8\x01\x34\xc8\x87\x2d\x24\xca\xa0\x00\xa1\x21\xd6\x14\x12\x0e\xa2\x00\xca\x18\x28\x8d\x12\xf5\x12\xc4\xcd\xc5\x57\x47\x35\xea\x41\x67\xd7\xd1\xe0\xa1\x72\x44\x13\x2c\xe8\x24\x18\x59\x18\xb6\x1c\x40\x38\xf0\xf5\x60\xa2\x99\x53\x1b\xf1\xe2\xcf\x9a\x15\x6a\x65\xe9\xab\x7f\x41\x93\x97\x97\xa0\x4d\xa3\x24\xd4\x01\x7a\x06\x7a\x95\x81\xe9\x08\x93\x13\x42\xb2\x09\x33\x7d\x17\xd6\xae\xe3\x42\xdc\xa5\xd5\x71\x43\xf9\xba\xb5\x71\x30\x0b\x1d\x3c\x00\xac\x51\x77\x34\x71\x78\x19\x4f\xd5\xeb\x12\x8d\x18\x12\x46\xaf\x96\x8c\xdc\x38\xa2\xce\x1a\x0a\x01\x06\x0a\x10\x0a\x06\x08\xe1\xeb\xe8\x52\x90\x29\x58\x84\x43\xe0\x58\xa8\x3c\xdc\xa4\x01\x8f\x12\x6d\x0a\x6a\x47\xb7\x49\x94\x47\x41\x9b\x83\x1a\xb2\x30\x53\xeb\x5c\x6f\xd8\x0e\xba\xb6\xce\x13\xc8\x16\xe4\x25\x80\x13\xb8\x7b\x22\xd3\x4d\xb4\x09\x04\x87\x1a\xc2\x4c\xa3\x8d\xc6\xfa\x17\x5f\xd4\x4e\xaa\x29\xc2\x80\x03\x91\x5a\x73\xaa\x49\xb6\x7a\xc5\x5a\x0a\x0c\x6d\xbb\x16\xd4\xa0\x89\x82\x2e\x85\x79\x00\x9d\xdf\xbc\xd0\x35\x8c\xae\x70\x68\x32\x0f\x2e\x43\xd7\xcb\x50\x28\x85\xd4\xf4\x09\xc5\x41\x0d\x60\x8c\x79\xa4\xa6\x49\x14\xda\x5b\xf3\x11\xe4\xab\x1b\x68\xd9\x36\x55\x03\x11\x1a\xce\x35\x54\x4c\xd6\xbc\x45\xa0\x64\xbb\xa6\x6d\xba\x49\x42\x1e\xe5\x20\xc9\xc3\x2c\x84\x10\x84\x2a\xbe\xd2\xb3\x7d\xb7\x97\xbd\x42\x1c\xf2\x66\x63\x13\x85\xf2\x01\x45\xd5\x04\x4c\x34\x3e\x23\x6f\xac\x03\x6e\x69\xf2\x42\x4e\xd0\x26\x2a\x87\x44\x07\xad\x69\xc4\x41\x4a\xc1\xf3\xda\xaf\xed\x7a\xe9\xc6\xd9\xd0\x6a\xe2\x12\xb0\x35\x17\x50\x2e\x94\x01\xdb\x1a\x9a\x44\x41\x03\xc6\x1a\x90\x74\xcd\x7a\x6d\x00\xe5\xbe\x52\x81\xba\xc1\xba\x7e\xf9\x40\x39\x30\x76\x50\xce\x95\x1e\x1a\x78\xb1\xd0\xe8\xab\x65\xfc\x8d\x30\xe8\x5a\x14\xd7\xbe\x49\xac\x5d\xcb\x34\xb8\x6e\x28\x83\x42\xe0\xe2\x74\xc3\xa0\x4c\x93\x13\xe4\x6f\x4e\xe7\x9a\xe9\xd4\x45\x01\x34\x42\xb3\xc6\xeb\xe0\xb3\x75\x32\xc0\xf0\xd5\x3a\xd7\x20\xad\xdd\x4e\xd6\xcc\x52\x6f\x20\x46\x13\x13\x0a\x0a\xaa\x01\xc2\xd7\xae\x80\xf4\x56\xf3\x42\xbd\x52\x83\x5e\xae\x99\xd1\xa8\x0a\x37\x58\x03\xdc\xc6\x72\xd7\xb1\xfc\x9d\xca\xa8\x57\x54\xf6\xc2\xf3\x75\xcc\x58\xe3\x46\xf4\xe4\x9d\x76\xb8\x3a\x62\x48\xad\x36\xd3\xec\x70\x24\xfc\x0c\x61\x7f\xf3\xb5\x02\x18\x84\xc1\x21\x19\x5e\xb3\x81\x68\xd7\x0c\x03\xd7\x85\xb0\x6d\x76\x7d\xe4\xbe\x2b\x82\xe6\x88\x60\xd4\x11\x46\xc1\x95\xb6\x48\x68\xc7\x0b\x7d\x41\xeb\xae\xfb\x53\xcd\xe2\x70\xfd\xc6\x14\x94\xbb\xb1\x1e\xdc\x9a\xb8\x37\xe4\x51\xef\x28\xb7\x36\x98\x8b\x35\x52\xae\x5b\x4b\x8d\x39\xfe\xaa\x21\x40\x6a\x69\x10\x82\x0a\xe0\x11\x86\x68\xe0\x07\x97\xab\xb7\x24\xa6\x09\x67\x13\x64\x70\xdd\x71\x1a\x8e\xbe\x9a\x01\x93\x09\x66\x04\x79\x23\x3a\xb2\x7d\xdd\x84\x6e\x1b\x76\x1d\xc3\x2b\x29\x5f\xdd\xfd\xe9\xa5\x15\xf9\x72\x69\xf5\xe5\x01\x97\xfa\x63\x07\x5c\x78\x45\xc6\xf0\xcd\x01\x97\xa5\x50\x02\xbf\x1e\x70\x69\x0e\x65\xeb\x76\xe2\xc7\xcf\x1c\x8b\xb2\xf8\xbf\x7b\xc0\xfd\x78\xdd\x6f\xf3\x96\x6d\x33\x5f\x5c\xc8\xb3\x1f\x2f\x9c\x6d\xce\x32\x6d\xfa\x8b\x0b\x73\xf0\xf1\xf4\x6c\x93\x16\x63\x7f\x7e\x7a\x46\x19\x40\x7c\xbc\xb1\x60\x98\xba\xa5\x7f\x75\x21\xff\x71\x38\x69\x18\x5f\xdd\x87\x60\xe9\x4f\xee\x2b\xb0\x3a\x67\x7e\x71\x9f\x80\xfb\xe4\x3e\x87\xa1\x69\xc0\xf8\xea\x3e\x01\xfb\xf1\xfc\xaf\x1b\x1c\xa7\x7f\xa1\x3e\x4f\x7c\x1c\xaf\x59\x8c\xa1\x7d\x35\x9e\xf9\xe4\x62\xc4\xa6\x4c\xfe\xf3\xf1\x7f\xe6\x7d\x05\xb7\x4d\xb0\x1b\xf0\x39\xee\xa9\xdf\xbd\xa5\xf0\x66\xf6\xbf\x7a\x37\xe1\xd6\x00\xb5\x3d\x44\x5e\xf8\xe3\x67\xdd\xca\x2d\xff\x6e\x45\x9a\x3b\x7f\x27\xa5\x87\x7f\xe7\xb6\x61\xe9\xff\xc5\xbe\x8f\x14\xbc\x29\x0f\x9f\xf4\x24\x69\x8e\x05\x5a\xb0\x27\x55\xa2\x85\x5f\x86\x5d\x42\x09\x86\x2b\xe9\xb8\x56\x1d\x69\xd1\x9b\x4b\x49\x49\x4b\xdc\x78\xe5\x01\x1d\x73\x59\x5e\xc0\xa8\xe5\x96\x0c\xbb\x13\x4b\x75\x9c\x8e\xba\xdf\x48\xca\x1a\xab\xc8\x09\xb9\x67\x15\x76\xba\x12\xb1\x3e\xe3\x1f\x89\xe4\x5c\x10\xf8\x65\x61\xae\xb1\xdd\x86\x07\x9b\x4d\x1f\x0f\x96\xf3\x31\x46\x86\x40\xc3\x0e\xc7\x8a\x31\x99\x5d\x4a\xf6\xb9\xed\x6e\xd9\x9a\x15\xf4\x84\x91\x77\x07\x59\xee\x9f\x43\x0d\x63\xb9\x68\x3f\xb6\x92\x7e\xaa\x8e\xb3\x44\x94\x00\x73\x1e\xf5\x65\x20\xf3\x8e\x34\x9d\x1a\xaa\x49\x98\x32\xb0\x27\x45\xa2\xcb\x18\xa6\xed\x26\xec\x08\x58\xf6\x4c\x09\x8e\xeb\x93\xd4\x13\x8e\xb8\x80\x6f\xf6\x13\xbd\x27\x69\xf3\x6e\x27\x35\x86\xc7\xdd\x81\x67\xe9\x8a\x9c\xc8\x27\xbe\xac\x2c\x6e\xd6\x39\x0a\xa1\x37\x98\xf6\x62\xb7\x75\x20\xac\x2e\x95\xa4\x66\xd4\xa1\xe4\xb4\x77\xd6\xfb\x3e\x36\x38\x71\x8b\x2c\x57\xb7\x71\xb9\x9a\x7b\x34\x11\x81\x43\xbe\xf5\xfa\xaa\xb6\xd8\xcb\x38\xa6\x9d\x45\x67\x7a\xec\x62\x7b\xae\xa3\xca\xc4\xec\x54\x7a\x66\x0c\x7a\xfb\xa3\x1b\x89\x65\x6c\x69\x3b\x01\x5b\x1f\xce\x07\x8c\x1a\x44\xd3\x72\x3c\x3e\x78\x53\xcf\x3a\xb2\x8b\xf5\xd2\x5d\x4c\xe6\x5b\x6d\xa2\xf6\xe6\x67\x45\xb3\x13\xb5\x5b\x7a\x05\x15\x5d\xf6\x63\xfb\xa4\xab\x23\x5c\xca\x17\xa6\x0f\xc4\x79\x55\xad\x52\x6e\xd7\x9d\xac\x04\x66\x2d\xc9\x4a\x91\x8b\x95\x1c\xef\xb7\xc3\xfd\x64\xe2\x4f\x64\x7f\x3e\x1d\x13\xb2\x32\x5a\x8c\x5a\xb4\x70\x3c\xef\xc1\x92\xed\xf6\x7a\x97\xd1\xe5\x48\x33\xfd\x70\x7d\x98\x6f\x7d\xf5\x78\xea\x46\x9d\x6d\x4f\x8f\x42\x69\xa3\x1a\xb2\x2c\x50\xe6\x24\xec\x30\x04\xd5\x9f\xa7\x62\x67\x3b\x74\xec\xfd\x48\x72\xca\x63\xd4\x75\x2f\xcb\xde\x36\x0f\xa9\x4d\x3c\xb7\x02\x31\x20\x36\xc5\x6e\x9e\xee\x46\x45\x0f\xb8\x8c\xd1\x72\x4a\x7f\x4e\x1f\x9c\xa5\x27\xad\xa5\x0c\x2f\xcc\xa1\xc5\x66\x8a\xb4\x6c\x85\x52\x9f\xd0\xba\xb2\x37\x52\xa6\xc3\xe1\x76\x98\xf0\x16\x2e\x4a\x92\x2c\x28\xeb\xa4\x58\x9c\x0d\x77\x23\x54\xab\xb1\x17\xac\x8b\x29\x4b\x8f\x02\x66\xd3\x23\x3b\x39\xeb\x05\x53\xed\xd0\x2a\x4d\x76\xdd\x1b\x6f\x96\x58\x67\x36\xea\x01\x1d\x93\xa8\xcc\x59\x25\x12\xc5\x8f\x18\x7c\x4a\x1f\x0d\x2b\x9a\x9c\xa2\xc2\x3b\x9f\xd5\xb1\xc6\x39\xee\x60\x27\x50\xdc\x9a\x57\x56\x84\x30\x77\xaa\x45\xbe\x5a\xb9\x12\x89\xeb\x73\x4f\x5b\xf6\x35\xaa\x92\x95\xd1\xa4\x17\xb5\xc4\x13\x46\x18\x83\x8c\xea\xaa\x7e\x51\xf5\x6c\x62\xc9\x74\x06\x45\x91\x28\x05\xa6\xe5\xa2\xbe\xa0\xbb\xe0\xc8\xba\x40\x9d\x53\xe3\x01\x29\x04\x76\x4b\x30\xf6\x95\xa4\xef\x67\x39\xdf\x1d\x66\x97\xb9\x08\x7c\x5e\xd2\x33\x75\x7a\xc8\x59\x2a\xc7\x4c\x72\xca\x2f\x94\xd9\x4a\x4c\x52\xa9\xe8\x0f\xb7\x13\xee\x44\x54\x47\x76\x37\x51\x17\x29\x3f\x4a\x16\x39\xb9\xa1\x84\x8e\x20\x2e\xfb\x0b\xc6\x9a\xe3\xd8\x64\xfe\x67\xfe\xca\xb2\xf4\xd3\xf2\x2f\x46\x12\xfe\xeb\xbf\x5a\x78\xea\x49\xd2\x7a\xb6\xd9\x99\x33\x15\x3b\x5b\xdb\xfd\x30\xf2\xd4\xbd\xb7\x54\xc7\xaa\x3b\x32\x18\x49\x37\xcf\x83\xa9\xeb\x78\x87\x88\xcc\xb0\x62\x00\x2e\x4c\x07\x1f\x09\xee\xb4\x52\x86\xb2\x5b\x46\xd4\x71\xd4\x3f\x02\x61\xb9\x12\xca\x62\xdb\xc3\x95\x38\xa6\xcd\x81\xc1\xe7\xbd\xf5\x45\x2d\x3c\x53\x8b\x4e\xc1\xa9\xc5\xf1\x34\x5f\x5e\xf4\x4b\x3f\x9b\x18\x25\xc3\xcf\x56\x4b\x82\x91\x56\xc1\x3c\x5b\xf2\x09\x35\xa8\xb0\x32\x67\x95\x2d\x7b\xd8\xb4\x32\x97\xae\x2e\x1b\x43\x53\x67\x3b\xac\xd5\x1a\x66\xfc\x99\x9a\x08\x79\xab\xbb\x59\x30\x59\x67\xbd\x5e\x9d\x94\x51\x2a\x1a\x8b\xcb\x61\x3f\xdd\x2b\xdc\x96\xdf\xcb\xe3\xb2\x85\xed\x44\x9d\xb2\x68\xec\x38\xa0\x87\x21\xee\xc7\x43\x75\xdb\x5f\x6b\x5d\x5c\x5d\xed\xc3\x4e\x57\x90\xc6\xd1\x66\x41\xca\x24\x13\x89\x11\x3b\xd1\x53\xc7\xdf\x17\xfa\x49\x64\xbc\xf9\x78\xba\xeb\x29\xc6\x78\xbd\xb1\x3b\xc7\x8e\x10\xcd\x5d\x5f\xa4\xcb\x52\x11\x63\x6c\x90\x2c\x73\xf2\x04\x46\x8e\xba\x25\x2f\x78\x89\x8f\x77\x97\x63\x57\x1d\x69\x8b\xbd\x7f\x48\xce\x04\xa9\x0d\xb6\xab\x8b\xec\x69\x81\x50\x55\x59\x8e\x4f\xf9\xb5\x6a\xda\xf4\x4c\x48\x4e\x7e\x1c\x77\x6c\x65\x6d\x9f\xa9\x48\x90\xa5\xe4\xb4\xef\x8c\x8d\x75\xa9\xf4\x16\xdd\x81\x14\xe3\xa2\xb3\xa5\xe5\x88\x9a\xf0\x93\xe1\x04\x98\x3d\x7c\xb7\x4b\x37\xbd\xe9\xba\x9a\x8d\x56\x97\xa8\xb5\xed\x08\x13\xd1\x33\x0f\x31\x97\x39\x83\x7e\x9f\x34\x70\x31\x1c\x51\xe7\xe1\xc2\xa6\x8c\x69\xb7\xa3\x6d\xe9\xf1\x41\xe5\xca\xe3\x5e\x66\x89\x32\x1e\xf1\x73\xa3\x77\xa1\xf5\xcd\x69\xb0\x1e\xf5\x07\x7b\x99\x50\xb3\x49\x30\xf6\x70\x46\xed\x56\xde\xa6\xa7\x53\x29\x96\x4b\x63\x65\x25\xd8\x20\xa6\x2c\x73\xda\x67\x02\xc5\x03\x97\x05\x53\x48\xb1\xb9\x2e\x76\xad\x5c\x16\xb3\x63\xf7\x32\x88\xc6\x6c\x9c\x19\x0a\xa3\x55\x72\xd0\xd7\x0e\x79\x66\x95\xd4\xcc\xf7\xaa\x68\x78\xec\x2d\x0e\xc1\x5a\x12\x96\x96\xdf\x21\x92\xdd\x7c\xb1\xb4\x0f\xeb\xee\x8a\x9f\xf9\xdb\x38\xd8\x12\xc0\x5b\xf5\x2f\x5d\xa1\x92\x8e\x6b\xaf\x9c\x2d\x4e\x3b\xd7\x22\x36\xd4\x65\x6c\x5c\x74\x33\xa8\x74\xe7\x18\x8f\x70\xa3\x3f\x3d\x0b\x8c\x4a\x28\xab\x6e\x3a\x8e\x3c\x7a\x90\x4e\xc6\xec\x84\x54\x26\xad\x73\xa1\x6a\x5b\xbd\x54\xed\x48\x96\x8f\x17\xb3\x34\xac\x82\xf1\x13\x75\xab\xed\xdd\x80\x9b\x0d\x06\x7d\xf2\x62\xdb\x31\x58\x17\xa3\xe5\xe0\xc2\xe7\xf9\x71\xcd\xcd\x22\x53\x37\xe6\xaa\xaa\x2e\x69\xbf\x54\x8f\xe5\xea\xd8\x37\x37\xe2\xdc\xdc\x80\x51\x0a\x4e\x33\x47\x15\x99\xd1\xf0\x3c\x94\x58\x27\xdd\x6d\x2c\x7b\xe8\x0e\xcf\x0a\x4e\x1f\x59\xb3\x50\x74\x4b\x09\x5c\x8e\xd5\x00\x77\xb6\x87\x8a\xb6\x51\xab\x38\x49\x46\xb2\x73\xb0\x88\x49\xd2\x02\xd9\x45\xdd\x09\x93\x50\x0c\x13\xf2\xb2\x70\x07\x07\x92\xdd\xe4\x15\x51\xc4\xbb\x41\x36\x11\x4c\x1a\x2b\xe6\xaa\x20\x32\x5b\xe5\xbc\x22\xba\x45\xb4\xf9\x53\x09\x22\xf8\x8b\x7d\x11\xc9\xf3\x5f\xd5\xd8\x6d\xfe\x3c\x51\xe9\xb6\x1c\x72\x4b\x64\xa0\x8f\xa7\xd2\xa9\x1a\x2e\xab\x70\xdd\x1b\xa5\xcb\xe9\xd2\x9d\x14\x5d\x2d\xf0\xd4\xbd\x24\x92\xb2\x33\x3c\x1a\xe7\x32\x9a\x60\x5e\x77\x6f\xcd\xf6\x9e\xda\x17\x09\xad\x2f\xb6\x3c\xbc\x47\x8f\x95\xae\x5b\xfa\x1b\x4d\x3b\x0a\x63\xa2\x3a\x1a\x42\xd6\xda\x5e\x4c\xf9\xcc\x5e\x8e\x65\x44\x6e\xf7\x32\x15\x9f\xb9\x60\x67\x07\x96\xa5\x92\x1c\x47\x9f\x1d\x86\x4d\xa2\x59\xcf\xa5\xc3\xdc\x60\x88\x80\x77\x0f\xd1\xa2\x45\xcb\x4a\xcc\x2a\xc9\x51\xb5\x49\x16\x3f\x6d\x32\x23\x6a\x6d\xb2\xee\xba\x17\xeb\x87\xd6\xa1\xbf\x68\x8d\xf4\x6d\xc8\x32\xd3\x6a\xce\x59\xb3\x22\xdd\x0b\xab\xb9\xce\x2d\x30\x57\x0b\xf7\xce\x70\xe2\x1c\xf8\xe1\xc9\x3a\x77\x7a\xdd\x02\x8c\x33\x7e\xaa\x74\xc2\xc9\xb6\x9b\x12\xd4\xae\x38\xf6\xb1\xf9\x58\x5d\x4b\x5e\xff\xb0\x11\x66\xf3\xc8\xc6\x92\x13\xce\x72\x64\xbc\x74\xa5\x15\xb9\x96\xe7\x11\x57\x5e\x70\x6f\x49\xf7\x34\x61\x12\x24\x83\xf9\x80\x10\xa3\x93\xda\x12\x97\xf2\xf2\xc2\x2c\x2e\x96\xb1\xf5\x43\x91\xaf\x82\x35\xc5\xca\xea\xc1\xa4\xa6\x74\x67\x77\x12\x57\x7d\xaa\xa7\x90\x93\x78\x25\x1d\x63\x73\x44\x27\x05\x2e\x44\x85\xbc\x50\x74\x77\x6d\xc7\x34\xe7\xac\xa6\x9a\x88\xad\x07\xc1\x64\x3e\x1b\x32\x6a\x90\x8f\xb7\x8b\x1d\xb8\x48\xcb\xc1\x7a\x84\x45\x9d\x94\x08\x83\x99\xd6\x52\x9c\x02\xdf\x0f\x15\x32\xdb\x57\xfd\x68\x54\x54\xce\x65\x3e\xe9\x10\x87\x49\x35\x1a\xee\x77\xac\xd7\xc1\xfd\x78\x16\x29\x2c\xbe\xee\x07\xb3\x1d\x77\xe9\xae\x5b\x49\x9f\x9b\x88\x9b\x72\x50\x98\x5e\x97\x0e\xc6\xe9\x6c\xdd\x5b\x4f\x30\x27\xcf\x64\xd9\x26\xf9\xb4\x77\xd9\x9c\xb4\x09\xa9\x26\x5d\x66\x75\xe8\x68\xe7\x93\xbb\x73\x27\x02\x58\xcd\xa3\x93\x1f\x6d\x58\x51\x6b\xc5\x87\xfd\x09\xf4\xd2\xdd\xba\xab\x05\x3d\x82\x3f\x30\x72\xae\xba\x36\xe9\x0d\x97\xf0\x30\xd9\xcb\x79\x71\x6f\xe5\xd1\xd9\x5d\x5c\x2e\x33\x7b\xda\x6f\x91\x6e\x2c\xf0\x6b\x7e\x5d\x79\xd1\xd4\x5f\x8d\xd8\xb8\x67\xad\xba\xf3\x25\xb3\xe8\x5f\x86\x96\x5e\xd9\xad\xe8\x42\xc7\xcb\xcb\x36\x0b\x96\x5b\x20\x4d\xf9\xd8\xcd\xe7\x38\x9e\xfa\x9d\x45\x86\x71\xa7\x05\x29\x46\x5b\x73\xa7\x7b\xc6\x65\xed\xad\x2e\x26\x4d\x88\xad\xcc\x94\x83\x6a\xd5\x01\x54\x50\x82\x44\x11\xc6\x1b\x63\x11\x4b\xc2\xea\x90\xa4\x67\xc9\xb7\x2c\x6c\xb0\xeb\x07\x61\x6f\x51\x75\xa6\x7d\x91\xc4\xbb\x58\x28\x89\x87\x89\x93\xb2\x5d\x31\x4e\xd5\x20\x1c\xf4\x49\x75\x66\x39\x9d\x6e\x3e\x48\xf9\x48\xb5\x03\x2e\xec\xf3\xe6\x48\xa3\x77\xd4\x98\x13\x84\xf9\x65\xbe\xa3\xc6\xcb\x09\x59\x18\x7f\xea\x97\x0a\xab\xbf\x5a\x2e\x9b\xe5\x4b\x8d\x51\xff\x5a\x17\x45\x57\xd8\x80\x56\xf1\x7d\x9c\x9d\x09\x20\x14\xdb\xc2\x55\x63\x7b\x29\xf6\xdc\xd6\x31\xcf\x17\x26\x37\xc1\x07\x36\x35\xc4\xca\xad\x69\x63\x73\x40\x73\x3d\x7c\x1e\xcd\x5b\xdd\x4d\xda\x1b\x6b\xf2\x72\x1e\x67\x98\x19\x07\xf9\x25\x5b\x4d\x2f\x97\x63\xc5\x18\x56\x36\x8d\xb7\xc6\x7e\x9f\xeb\x53\x52\x99\xd2\x34\xa0\x96\xe5\x45\x5a\x93\x09\xcd\x62\x64\x3f\xde\xfa\xbe\x82\x65\x33\x2a\x95\xc9\x95\x96\x2c\xa6\xbb\xf3\x32\xc2\x96\xdb\x51\xbe\x63\xc1\xfa\xcc\xe1\x5d\xdb\xf5\x13\x6c\x45\xad\xcd\x6d\x4f\xd8\xd8\x66\x18\xa4\xab\x75\x96\x9b\x33\x92\x9e\xae\xab\xf9\x78\x13\x8e\x9c\x9d\xd8\x59\x19\x07\xde\x33\x84\x74\x65\xc9\x5a\xc9\x1e\x30\x9c\x26\x4e\x0a\x07\xd6\x87\x62\x0b\xe6\xa3\x9d\xe4\x2a\x3d\xfc\xa4\x86\x13\x1e\xb7\xcd\x30\x37\x23\x47\x0d\xf2\xd1\x6c\x8d\x63\x9b\x8e\x10\x8b\x94\x6b\x88\xc9\x76\x61\x54\xde\xd1\xee\x00\x36\x4d\x2e\xce\x96\xd5\xf9\x85\x0b\x72\x29\x2f\x45\x7f\x48\x65\x9b\x2a\xd3\x3a\x4b\x49\xca\x82\xad\x8b\x97\xe9\x5a\x29\xe2\x22\xdc\x1e\x4e\x82\x6f\x94\x91\xe3\x0d\x4c\x50\x78\xf3\xaa\x7b\xe6\x58\x6f\x88\xb5\xd2\x51\x66\x33\xad\xc9\x2e\x75\x62\x93\xed\x6d\xbb\x4a\x87\xc6\xc7\xf9\x51\x55\xfa\x8a\x2e\x9b\x7b\x47\xf6\xed\x43\x6b\xcc\x8f\xa9\x56\x2f\xec\xcd\x89\x92\xdd\x86\xd9\x30\xa5\x71\x41\x0f\xbc\x7e\x21\x0f\xe5\xac\x75\x6c\x49\xf9\x25\x5f\x4e\x86\x83\x8b\xe9\x39\xe6\x08\x13\x82\xdd\x7c\xe1\x7a\x83\x9c\x9e\x4d\x97\x85\x1a\xf4\x5b\xc6\x69\xb6\x89\xf0\xc1\x49\x2c\x0f\xdc\x79\x35\x26\xf2\x10\x0c\x6c\xad\x35\x0a\xcc\xe1\x31\xcf\xf6\x18\x65\x4f\x67\xbb\x35\xb9\x9d\x89\x71\xcf\x9a\x6c\x37\xd5\x7a\x9c\x54\x5d\x6f\xd8\x57\x26\xd4\x25\x1d\xf0\x9c\x53\x05\x64\x77\x68\x4c\x57\xc5\xaa\xb5\x1b\x98\xbb\xc4\x9c\xcf\x07\xc2\x3e\xca\x24\xee\xd8\x99\xc5\xcb\xd3\x6c\x32\xc8\x3a\xd3\x84\xe2\x06\xeb\x40\x9e\x1a\xbb\xc5\x68\xc5\x9b\xdb\x89\xd2\x57\x47\x3d\xbd\xe2\x41\x3c\x98\x0a\xb9\x56\x1d\x97\xda\x70\xe5\xb4\xf4\xc2\xb2\x4d\x37\xc9\x2c\x71\xb1\x52\x96\x45\x95\xf4\xba\xce\x90\xe3\x24\x9c\x66\x06\x55\x8b\x12\x5c\xc2\xd8\xcd\xf7\x32\xb9\x80\x07\x6a\x79\x6d\xb1\xf6\x69\xb7\xed\x4d\x98\x3f\x73\xbf\xbc\x78\x7f\xb1\x7a\x82\x01\x7f\x3f\x4f\x1f\xf1\x2c\xc7\x71\x61\xed\x1a\x2d\x45\x65\xcc\x69\xe0\x58\xbd\x91\x03\x7a\xd1\x66\x13\xaf\xb7\x7e\xaf\x8b\xa7\xc4\xb0\xd7\x03\x87\xb2\xa3\xbb\xe3\x03\xd5\x59\x96\xaa\x99\x1a\x33\xd5\x90\x82\x79\x30\x14\x4f\xb8\x93\x4a\x8b\xe1\xc6\xab\xa8\x55\x2c\xb2\x9b\xde\xa5\x07\x06\x11\x7d\xb0\x08\x8d\xca\xdc\xe9\x69\xe2\xfa\x31\xad\x5c\xa8\xcb\xd9\xbc\x5c\x62\xbc\x88\x17\xab\x2e\x67\xcf\x92\x23\x8e\xad\xba\x4c\xcb\x16\x33\xd5\x33\xe4\x01\xcf\xae\xc0\xd8\x20\xf2\xb9\x68\xa4\xad\x64\x40\x5a\x6b\xa1\xdc\x5c\xc2\x10\xb7\x43\x20\x2e\x14\x4e\x6a\x79\x53\x33\xa7\x8d\x8c\xdc\x05\xfb\x3e\x53\x6d\xfc\xc9\x81\x49\x23\x7f\xad\x3b\x9b\x55\x86\x9f\xe8\x5e\x3f\xdb\x31\xf9\xee\xd4\x65\x36\x47\x7f\x25\xb5\xc6\xc2\x14\x9b\x4e\xc5\xc1\x72\x38\x9f\x2d\xe6\x71\xba\xeb\xb6\x8e\x47\xe9\x42\x48\xb2\x80\x57\x69\x96\x73\x54\x26\x5f\xaa\xb3\x91\xea\xdb\x4e\xe5\xa5\x42\xdf\x6e\xcd\x85\x25\xd1\xed\x8a\x8b\x85\xac\x8c\x94\xa0\xec\xb6\x3c\xae\x4b\x1d\x4c\xb9\x1b\x60\x17\x85\x9d\x4e\xc7\xbd\x7e\x9c\x19\x53\x06\xeb\xac\xe2\x11\x5e\x59\xf3\x0e\xae\xb6\x02\x7b\x3c\x3f\xef\xf7\x7d\xfc\x30\x77\xac\x85\xbe\xe5\x76\x66\x14\x44\x7a\xca\xcb\x13\x2e\x35\x8c\xd6\x7a\x36\x98\x54\x94\x58\x9c\xb8\xa1\x7f\x88\xb2\xe1\x70\x2e\x05\x34\x8f\x2d\xa2\x65\xa5\x80\xee\xf8\xb8\x1b\xef\x27\x9d\x80\x3d\x0e\x37\x4e\xa5\x30\x85\x23\x84\x4b\x67\x31\xe6\xf3\xd3\xdc\x1e\xcc\x3c\xa5\x27\x0e\x4e\x55\x6f\x93\xca\x0b\xbe\x1b\xe0\x11\xa5\x5e\x22\x41\x58\x26\xcb\x43\xd7\xf2\xe7\xf6\x62\xa6\x83\x8d\x41\x9d\x42\x5c\x52\x69\x99\xd8\xf2\x7d\x49\xeb\xc8\x46\x39\x77\x7a\x83\xb8\xaf\x1f\x95\xa1\x38\x62\x78\xab\x55\x1c\x46\xdc\x66\x77\x5a\x38\x63\xcf\xc4\x13\xd6\xce\xe6\x66\x79\x5c\xa4\xfc\xf2\x24\x10\x47\x47\x08\x00\xb5\x5c\x0e\xe7\x2e\x7f\x76\xcf\x72\x7f\xa6\x84\xe3\x51\x8a\xd1\xe3\xd3\x59\x06\x25\x3e\xc1\x17\xdd\xd4\xbb\x78\x4e\x24\x6a\xf2\xa9\x63\x0e\x22\xc5\xab\xf2\xc4\xef\xa4\x83\x4d\x09\x8a\xd8\x15\xa9\x4e\xd7\x2a\xa2\x53\xd9\x1f\x8f\xc5\x42\x70\xb2\x69\xc5\x8d\xce\xb6\x7a\x3e\xb6\x68\x27\xf2\xfb\x7d\xad\xbf\x2f\x0c\x90\x0e\xfb\x91\x78\x21\x85\xe9\x6c\xbf\xdc\xc8\xda\xc0\xd9\x14\x95\x19\x8d\x44\x05\x0c\x28\x51\x9f\x4f\xc5\xb3\xe3\x76\x48\x35\x9e\x8a\x14\x35\xb0\xa3\x81\x13\x9e\x29\x8b\x5d\x46\xf8\x59\xf0\xf0\x34\x1b\xc8\x23\x52\x38\x9b\x5c\x87\xd7\xe3\xc1\x99\xc9\x67\xd1\xf2\xcc\xaf\x32\xd1\x67\xb2\xf5\x39\xea\x79\x43\x75\xea\x9c\xf1\x16\xa0\x39\x65\x1c\x4c\xcb\x28\xc8\x2a\x91\x9c\x7b\x18\xa9\xac\x16\xac\xc7\x8d\x71\x49\xec\x83\xfe\x60\x4a\x8b\x12\xb9\xa3\xc4\x7c\xa2\xb9\x7b\x7f\x34\x2d\xa4\xe3\x54\x58\xe5\xe6\xcc\x20\x30\xcc\x2d\xc9\x60\x37\xa2\xfd\xde\x48\xeb\x71\x63\x4e\x5f\x66\x26\xae\xf6\xed\x70\x3a\xd2\x95\xbe\x55\x12\xa0\x64\x8c\xba\x5e\xd1\xd4\x1f\xce\xc4\xd1\x25\x61\x0d\xf9\xcf\xe1\x09\x3d\x32\x2b\xe4\xa9\xbe\x7d\xf9\xf8\x13\x49\x91\x2c\x69\x7f\xb3\xa3\x30\x6b\xdb\x5a\xe0\xf9\xd5\xe3\xc3\xc0\xf2\x73\x2b\xf3\x0c\x0d\x99\x58\x67\xeb\xe1\x17\xe4\xde\xf0\x0b\x22\x24\x9e\xe6\xff\x82\xa4\x5a\x98\xb6\x53\x2b\xf1\xae\x53\xeb\x05\x00\x15\x97\xdf\x7c\x2f\xb4\xda\xae\xe5\x39\x6e\xf6\x08\x50\x8a\xfc\x16\x68\x89\xe3\x85\x8f\xf8\xb7\x22\x4a\xcc\xb6\x9e\x58\xda\xf1\xb1\xfe\xd9\xd6\x7c\xff\x5b\xbb\xb0\xf4\xa3\x97\xb5\x33\xab\x6c\xa4\xb4\x35\xf3\x70\x4e\xb3\x47\x80\xe3\x7f\xff\xd6\x0e\xd2\xaf\x7a\x6e\xf3\xb4\xb8\xed\x7a\x8e\xeb\xc3\x05\x9b\x7b\xb2\x8f\x59\xa2\x85\x69\xac\x25\x56\x98\x3d\x6b\x77\x4b\x01\x60\x2d\x9d\xfc\x56\x8b\x33\x2d\x23\x4a\xb4\xcc\x8b\xc2\xc7\x30\x0a\xad\x67\xed\xd1\x8d\x72\x2b\xb9\x8f\xc5\x71\x1d\xb7\xf8\x0f\x63\xcf\xa1\x69\x25\xd0\xc0\x67\xed\x51\x33\x32\x2f\xb7\x7e\xd1\x1e\x73\x2f\xf5\x32\xcb\x7c\x37\xf7\x39\xcd\x92\x28\x74\x90\xa7\xda\x3d\x45\xe3\x0f\x16\xc7\x9f\x33\x4d\xf7\x2d\xe4\x49\x8f\x12\xd3\x4a\xa0\xc2\xbe\x16\xa7\x30\x38\xcd\x9b\x6f\xd7\x8e\x34\xd6\x0c\x2f\x74\x1e\xf1\x6f\x81\x56\x36\x77\x6d\x1b\xc3\x5f\xde\x36\xa2\x1e\x7d\x2d\xcd\xda\x86\xeb\xf9\xe6\x5d\xaa\x1e\x65\x59\x14\xb4\x7d\xcb\xce\xda\x89\x66\x7a\xe7\xf4\x91\x8c\xcb\x6f\x6f\x7b\x93\xda\x63\x2f\xdd\xcf\x59\xf2\x68\x7b\xc9\x5d\x58\xf6\x22\x2f\x8b\xe2\x47\x1c\xf6\x87\x99\xdb\x8e\xec\x76\x56\xc5\xd6\x3f\xac\xdc\x0a\xff\xf9\x66\xab\xb9\x3a\xc0\x66\x6d\xce\xd6\x9e\xdf\xcd\x07\x71\x89\xa4\x91\xef\x99\xc8\x4f\x26\x6f\xea\x16\xf1\x2d\xd6\x4c\x13\x9a\x88\x32\xb4\x15\x7c\xcb\xad\x04\x22\xcc\x6f\x6b\xbe\xe7\x84\x8f\x59\x14\x3f\xff\x14\x6b\x0e\xc4\x92\x66\xc2\xd0\xd4\xed\x6d\x2f\xb3\x82\xf4\xd1\xb0\xc2\xcc\x4a\x5e\x21\xfc\xf1\x27\x5c\x27\x35\x9a\x7c\x6b\xe3\x23\xf5\xb2\x28\xc3\x1b\x94\x61\x7e\xbb\xe9\x68\xdb\xdf\x4c\x2f\x8d\x7d\xad\x7a\xb4\x7d\xab\x7c\x8d\x62\x14\x10\x56\xf0\xed\x75\xdc\x68\x1c\xff\x06\xa1\xe7\xd9\x55\x1b\x66\x91\x15\x66\x8f\x30\x40\x56\x5b\xb7\xb2\xc2\xb2\xc2\xbb\x2d\x38\x02\xac\xe0\xad\xe2\x2f\x08\x6c\x54\x78\xd7\x7b\x05\xd2\x7d\x10\xaf\x99\x94\xa9\xbf\x1f\xf4\x16\x9e\xb6\x6d\xbf\x19\xd0\xf6\x23\x27\x42\x9e\xae\x59\x47\xa0\x04\x74\xe8\x35\xef\x50\xd6\x0a\x90\x97\x1f\xf8\x15\x40\x2c\x0a\xe8\x77\x9a\xb6\x03\x2b\x3c\x7f\xea\xe7\x37\x9e\xba\xc9\x85\x51\x43\xf0\x4f\x24\x98\x5e\x8e\x3c\xdd\xb2\x1e\x41\x99\x4f\x97\x31\xbd\xfc\x0d\x72\xef\xe3\xe1\x7f\x5f\xcc\x49\x73\x98\x4f\x9e\xef\xdf\x5c\xf9\xed\xce\x33\xdc\xdd\xe0\x1a\x6c\x28\x20\x3e\xb7\x2e\xcd\x9d\x9b\x2f\x1b\x41\xd0\x95\x28\xec\xaa\x2d\x6e\x87\x5a\x92\x44\x05\xf2\x74\xb3\xb8\x66\x87\x9f\xae\x31\xbf\xe1\xf9\x13\x2c\x5f\x61\x77\xcd\x26\xc8\x83\x57\x83\x6a\x38\x5c\xe7\xdf\xa1\xfc\x31\x67\x2c\xd3\xc6\x6d\xea\x1d\x7a\xbf\x5c\x26\x8b\xe2\xaf\x92\x1b\x76\xbd\xcf\xec\x97\x4c\x83\x08\x80\x1a\xa1\x30\x83\xdb\x9e\x11\x85\xbf\xbc\xbc\xfd\xf5\x7f\x21\x4f\x57\x76\x69\xc0\x81\x86\x51\xfd\xeb\xa1\x9a\xad\x91\xa7\xc2\xf5\x32\xab\x26\x26\xeb\x31\x8c\x8a\x44\x8b\xaf\x47\x4e\x57\x4b\xdd\x3b\x36\x59\x9b\xa3\x78\xf0\x66\x43\x09\xa2\x30\xaa\xa7\x3d\xff\x47\x60\x99\x9e\x86\x44\xa1\x5f\x21\xa9\x91\x58\x56\x88\x68\xa1\x89\xfc\xe3\x85\xe3\x68\x1c\x8f\xcb\x7f\x22\x4f\xbf\x11\x13\x2f\xac\x29\xf8\xd5\x88\xc2\x33\xad\x77\x31\xbb\x2d\x15\x27\x1e\x0c\xdc\x5b\x2a\xf9\x34\xba\xd7\xde\x5f\x5e\x6c\xfa\xe5\xcd\x4e\x89\xe3\xf8\x27\x91\xfc\x2a\x60\xaf\x47\x7f\x86\x1b\xd8\xaf\x7d\xba\x7b\xe0\xbf\xb5\xed\xfc\x1f\x37\xb1\xec\xff\xfb\xa8\xd9\x59\x43\x07\x0d\x17\x3d\x20\xff\x78\x40\xb4\x2c\x4b\xfe\x01\xbb\xff\x89\x3c\xfc\xf3\xe1\x39\x4b\x90\xa7\xda\xe8\x66\xaf\xf5\xc2\xd4\x33\xad\x47\x2d\x8f\x3c\xf3\x8f\x32\xf9\xeb\x7d\xf4\x6b\x36\x87\x96\x3c\xff\x07\xdc\xa9\x73\xcf\x2a\xe2\x28\xc9\x6e\x30\x32\xad\xdc\x33\xae\xbf\x72\x7c\x46\xcd\x36\xa4\x8f\x17\xe7\xc3\x4f\xcf\x28\xfc\xd9\x86\x58\x42\x9e\xea\xb7\xb6\x1f\x15\x8f\x0d\xb6\xea\xcf\xa9\x9b\x78\xe1\xb1\x0d\xae\xdd\xcd\xc7\x47\xf0\x8c\x06\x7e\x5b\x3b\x67\xd1\x8d\x39\xea\x7c\x78\x84\x2d\xcf\x68\xbd\x2f\xb6\x13\x2b\x8d\xa3\x30\xad\xb9\xf5\xb6\xa6\xee\x47\xc6\xf1\xd5\x16\xfa\x0d\x52\x01\x5c\xb2\x5d\xd6\x73\xef\xc7\x8a\x7b\x7b\x6a\x24\x91\xef\xc3\xe4\xc9\xa2\xb3\xe1\x3e\xff\xed\x3b\x56\x7f\x03\xe1\xd7\xbf\x7d\xc7\x20\x08\x7e\xfd\xdb\x77\x88\x92\x5f\xff\x86\x20\xdf\x21\xf1\x79\xe6\x8f\x87\x57\x58\x7b\x80\x1d\x9f\x77\xd5\xa4\xfd\x80\x18\xbe\x96\xa6\x3f\x1e\x6a\xd0\xd5\x2d\xbf\xfe\xcf\x50\x4f\xe3\x6f\xdf\x31\xd3\xcb\x7f\x63\x36\x44\xff\x55\xfa\x75\xc4\x55\xd2\xdb\xb4\x78\xf8\xf5\xbb\x86\x40\x54\xfc\x78\x70\xb3\x2c\x4e\x1f\x31\x0c\x2e\x85\x7a\xd1\x03\x92\x69\x89\x63\x65\x3f\x1e\xfe\x53\xf7\xb5\xf0\xf8\x80\x24\x96\xff\xe3\x21\x8c\xa2\xd8\x0a\xad\x04\x09\xa3\xc4\xb2\xad\x24\x81\x46\x08\x7a\x74\xce\x90\xe1\xac\xb7\xfc\x8e\x69\xbf\xbe\x52\xed\xbf\xb6\xf4\x4f\x5e\x98\x66\x9a\xef\xff\x2b\x2a\x0c\x9b\x29\xff\x8a\x12\x0d\x71\xfc\x89\x1e\xf8\x93\xd6\xfd\x37\xcc\xff\x54\x83\xdb\x7b\x04\xf9\xb0\xa2\xe3\x65\xee\x59\x47\x8d\x28\xa8\x17\xc7\x4c\x2f\x69\x7b\xa1\x69\x95\x6d\x37\x0b\x7c\xcc\x4b\xd3\xb3\x95\x62\xff\x8a\x22\xf7\xb5\x10\xe4\x3b\xdc\x90\x9b\x2f\xf3\x3c\x7c\xfd\x65\x9e\x87\xfb\x97\x79\x1e\xe0\xde\x0e\x38\x94\x42\x08\xf0\xf0\xeb\x77\xc3\x4b\x0c\xdf\x42\x8c\xf2\xc7\x03\x8b\xd2\x0f\x88\x51\xfd\x78\xa0\x50\xee\x01\x49\x7e\x3c\x80\x07\xec\xcd\x00\x00\x50\xf0\xc9\x88\xeb\x83\x11\x0f\x4a\xfd\xad\x04\x0e\xa5\x8c\x36\x5e\x3f\x1d\x48\xd7\x0f\x33\x11\xf5\x93\x8f\x74\xfd\xa4\x72\xfd\xd8\x2f\xde\x26\x11\x70\x7d\xc8\x95\x1e\xc0\x49\x97\x37\x62\x38\x94\x46\x78\x94\x1d\xd0\xb5\x1c\x04\x47\xb9\x36\x5e\x3f\x9c\xc5\xd6\xaf\x70\x11\x1c\x21\xea\x87\xcc\x38\x84\xaa\xff\x11\x08\x8d\x12\x1b\xfe\xbd\x24\x40\xa2\x54\x2d\x8a\x47\xf9\x9c\x45\x79\x83\x40\xa9\x36\x8e\x52\x70\x46\xad\x0f\x55\x3f\x10\x4b\x74\x01\x85\x02\x04\x5c\x1f\xe1\xe4\x11\x00\xd7\xbd\x4d\xbe\xbc\xf7\x02\x8d\xb2\x8d\x17\x00\x81\xf2\x9f\x3b\x8a\xbe\x39\x0a\xd0\x28\xf5\xd5\x10\xf2\x3a\x04\xff\x62\x08\xf1\xbb\xeb\x90\x77\x19\x5f\x2d\x43\xde\x15\x79\xb3\x0a\x84\xc4\x2b\xc0\x62\xda\x1d\xc9\xaf\x08\xef\xf6\xf6\xe5\xcd\x8d\x02\xaf\x5b\xde\x7b\x5e\x7d\xbb\x2f\xdf\x59\xf5\xba\xe7\xdc\x37\x99\x87\x2f\xd2\xa6\xb9\x58\x7b\x8d\xed\x21\x4c\x12\x24\xb2\x5f\x35\x3d\x3d\x21\x89\x16\x3a\x16\x82\x76\x12\x4b\x33\x8d\xe4\x1c\xe8\x29\xd2\x7e\x7e\x7e\x35\x06\x7b\x7a\x42\x3c\x1b\x41\x67\x10\x07\xcf\xcf\xf7\x7c\x7c\x7a\x42\xfe\x47\x12\x45\x19\xda\xd7\x32\xab\xd0\xaa\xf5\x42\x46\x9e\x9f\x9f\x9e\xae\x23\xff\x1f\x72\x4e\x7c\x29\x35\xb4\xd8\x42\x9e\x9f\x1f\x7e\x85\x1d\x13\x2d\x80\x1f\xa0\x87\x9e\x9e\x10\xcb\x4f\xad\xeb\x8c\x6b\x07\x6c\x0c\x4d\xe4\xcd\xf2\x4f\x4f\xed\xdb\xc8\xb7\x8a\xdf\x14\x7a\xdb\xfa\x6e\x3e\xdc\xda\xde\xfa\xe1\x6a\xcd\x00\x1e\xf0\x5e\x0f\x7c\x45\x7b\xf7\xd3\xd2\x03\x52\x9f\x17\x7c\x2d\xb3\x20\x75\xbc\x61\x0a\xa8\xc1\x07\x21\xd8\x9b\x18\xbc\x57\xe7\x4d\xf7\x55\x8f\xa5\x77\x79\x65\xda\x6b\x2d\xde\x9c\x54\xdf\x1e\x1c\xae\x07\x85\x87\x8f\xe1\x6e\x36\x5a\xa8\xdb\x55\xf0\x7b\x07\xbc\xd7\xe1\x95\x82\xef\xb7\xe7\xab\x1e\xef\x8f\x1e\x37\x9c\xd6\xed\x77\xb1\x59\xf2\x4a\x99\xcc\xbc\x4f\xbe\x9d\xc4\xdf\xb2\xec\x7b\x67\x5f\x39\xfa\xe3\x39\xa1\xd1\x2b\x33\xdf\x08\x7f\x23\xea\x05\x8e\x68\x47\x33\x8e\xb2\x17\x1e\x5f\x63\x0f\x42\x0f\x45\x5f\xe5\xe4\x67\xf2\x7e\xbb\xe5\x3b\xf6\x62\xdc\x4b\xc2\xc8\x5e\x9a\x79\xa1\xf3\x2a\x76\xff\x65\x17\x3c\x3d\xc1\xee\x5e\x12\x05\x52\x99\x35\xc9\x00\xd5\xfe\xb7\x9c\xf1\xc7\xb2\xf0\x6b\xb1\x9f\xa1\xf0\x3d\xfe\x3f\xcb\xa3\x5a\x89\xdf\xcb\xa3\x46\xcb\x46\x42\xc3\x21\xe2\x64\x59\x47\xee\xf9\xf9\xbe\xcf\x1b\x9e\x89\x5e\x4f\x17\xd8\x4f\xf7\x6c\x7b\x1b\xda\xaf\x36\xf9\xdb\xde\x8e\xdc\xf6\xfb\x87\x17\xbe\xf9\x82\xb8\x9a\xc3\xc4\xe7\xeb\xfc\x6f\xdb\xf3\xad\x50\x0b\xac\x1f\x77\xff\xbd\x73\xec\x3d\x93\x5e\xbb\xa8\x21\x89\xa5\x1b\x25\xd9\x27\x6e\x7a\xed\xfe\xcf\xa9\xeb\x0f\x85\xe4\x4d\xae\x7f\x09\xda\x37\x69\xfe\x2a\x73\xdf\x6f\x4b\xdf\xb1\xe6\xe8\xff\x1d\x83\x87\xa9\x5f\xff\xf6\xff\x03\x00\x00\xff\xff\x15\x51\x66\x61\x81\x6f\x01\x00") - -func dirIndexHtmlDirIndexHtmlBytes() ([]byte, error) { - return bindataRead( - _dirIndexHtmlDirIndexHtml, - "dir-index-html/dir-index.html", - ) -} - -func dirIndexHtmlDirIndexHtml() (*asset, error) { - bytes, err := dirIndexHtmlDirIndexHtmlBytes() - if err != nil { - return nil, err - } - - info := bindataFileInfo{name: "dir-index-html/dir-index.html", size: 94081, mode: os.FileMode(420), modTime: time.Unix(1403768328, 0)} - a := &asset{bytes: bytes, info: info} - return a, nil -} - -var _dirIndexHtmlKnowniconsTxt = []byte("\x1f\x8b\x08\x00\x00\x00\x00\x00\x00\xff\x1c\xd0\x5d\x8e\xc3\x20\x0c\x04\xe0\xf7\x39\xcc\xbc\xec\x5e\xc8\x0d\x3f\xa1\x0d\x8b\x1b\x5b\x94\xf4\xf4\x2b\xe7\xe5\x43\x06\xa1\xd1\x98\x22\x1b\x28\xad\x94\x10\x94\xd9\xc0\x47\x57\x70\x03\x37\x8d\xd3\x0c\x4c\xe2\x60\xea\x15\x4c\x63\x0b\x7c\x81\xe9\x13\xf3\x2a\x60\x56\x03\xf3\xca\x60\x39\x26\x58\x5b\x01\x77\x70\x8f\xff\xbb\xf7\x03\x6c\x9b\x81\xcd\x06\xf8\x94\x29\xe0\x53\x6b\x90\x43\x03\x5f\xf9\x02\x8f\x1c\x51\xbd\x25\xb0\xbf\x26\xd8\x47\xa0\x3f\xc1\x6f\x50\xc1\x91\x4a\x60\x81\x83\xc3\x35\x88\xd1\x1d\xd4\x78\xd5\x5d\x41\xfd\xab\xa0\x6a\xdc\x59\x02\xf5\x02\xdf\x0e\x9e\x72\x82\xe7\x03\x3c\xbd\x80\x26\x11\x68\x77\x43\x7b\x1f\xa0\x57\x09\xbe\xa0\xdf\x1b\xf1\xe5\xe0\x47\x26\xf8\xe9\x13\x5c\x87\xdd\x2c\x70\x45\xa9\x2b\xf8\x36\xc5\x7f\x00\x00\x00\xff\xff\x1a\xae\x71\x74\x46\x01\x00\x00") - -func dirIndexHtmlKnowniconsTxtBytes() ([]byte, error) { - return bindataRead( - _dirIndexHtmlKnowniconsTxt, - "dir-index-html/knownIcons.txt", - ) -} - -func dirIndexHtmlKnowniconsTxt() (*asset, error) { - bytes, err := dirIndexHtmlKnowniconsTxtBytes() - if err != nil { - return nil, err - } - - info := bindataFileInfo{name: "dir-index-html/knownIcons.txt", size: 326, mode: os.FileMode(420), modTime: time.Unix(1403768328, 0)} - a := &asset{bytes: bytes, info: info} - return a, nil -} - -// Asset loads and returns the asset for the given name. -// It returns an error if the asset could not be found or -// could not be loaded. -func Asset(name string) ([]byte, error) { - cannonicalName := strings.Replace(name, "\\", "/", -1) - if f, ok := _bindata[cannonicalName]; ok { - a, err := f() - if err != nil { - return nil, fmt.Errorf("Asset %s can't read by error: %v", name, err) - } - return a.bytes, nil - } - return nil, fmt.Errorf("Asset %s not found", name) -} - -// MustAsset is like Asset but panics when Asset would return an error. -// It simplifies safe initialization of global variables. -func MustAsset(name string) []byte { - a, err := Asset(name) - if err != nil { - panic("asset: Asset(" + name + "): " + err.Error()) - } - - return a -} - -// AssetInfo loads and returns the asset info for the given name. -// It returns an error if the asset could not be found or -// could not be loaded. -func AssetInfo(name string) (os.FileInfo, error) { - cannonicalName := strings.Replace(name, "\\", "/", -1) - if f, ok := _bindata[cannonicalName]; ok { - a, err := f() - if err != nil { - return nil, fmt.Errorf("AssetInfo %s can't read by error: %v", name, err) - } - return a.info, nil - } - return nil, fmt.Errorf("AssetInfo %s not found", name) -} - -// AssetNames returns the names of the assets. -func AssetNames() []string { - names := make([]string, 0, len(_bindata)) - for name := range _bindata { - names = append(names, name) - } - return names -} - -// _bindata is a table, holding each asset generator, mapped to its name. -var _bindata = map[string]func() (*asset, error){ - "init-doc/about": initDocAbout, - "init-doc/contact": initDocContact, - "init-doc/help": initDocHelp, - "init-doc/ping": initDocPing, - "init-doc/quick-start": initDocQuickStart, - "init-doc/readme": initDocReadme, - "init-doc/security-notes": initDocSecurityNotes, - "dir-index-html/dir-index.html": dirIndexHtmlDirIndexHtml, - "dir-index-html/knownIcons.txt": dirIndexHtmlKnowniconsTxt, -} - -// AssetDir returns the file names below a certain -// directory embedded in the file by go-bindata. -// For example if you run go-bindata on data/... and data contains the -// following hierarchy: -// data/ -// foo.txt -// img/ -// a.png -// b.png -// then AssetDir("data") would return []string{"foo.txt", "img"} -// AssetDir("data/img") would return []string{"a.png", "b.png"} -// AssetDir("foo.txt") and AssetDir("notexist") would return an error -// AssetDir("") will return []string{"data"}. -func AssetDir(name string) ([]string, error) { - node := _bintree - if len(name) != 0 { - cannonicalName := strings.Replace(name, "\\", "/", -1) - pathList := strings.Split(cannonicalName, "/") - for _, p := range pathList { - node = node.Children[p] - if node == nil { - return nil, fmt.Errorf("Asset %s not found", name) - } - } - } - if node.Func != nil { - return nil, fmt.Errorf("Asset %s not found", name) - } - rv := make([]string, 0, len(node.Children)) - for childName := range node.Children { - rv = append(rv, childName) - } - return rv, nil -} - -type bintree struct { - Func func() (*asset, error) - Children map[string]*bintree -} - -var _bintree = &bintree{nil, map[string]*bintree{ - "dir-index-html": {nil, map[string]*bintree{ - "dir-index.html": {dirIndexHtmlDirIndexHtml, map[string]*bintree{}}, - "knownIcons.txt": {dirIndexHtmlKnowniconsTxt, map[string]*bintree{}}, - }}, - "init-doc": {nil, map[string]*bintree{ - "about": {initDocAbout, map[string]*bintree{}}, - "contact": {initDocContact, map[string]*bintree{}}, - "help": {initDocHelp, map[string]*bintree{}}, - "ping": {initDocPing, map[string]*bintree{}}, - "quick-start": {initDocQuickStart, map[string]*bintree{}}, - "readme": {initDocReadme, map[string]*bintree{}}, - "security-notes": {initDocSecurityNotes, map[string]*bintree{}}, - }}, -}} - -// RestoreAsset restores an asset under the given directory -func RestoreAsset(dir, name string) error { - data, err := Asset(name) - if err != nil { - return err - } - info, err := AssetInfo(name) - if err != nil { - return err - } - err = os.MkdirAll(_filePath(dir, filepath.Dir(name)), os.FileMode(0755)) - if err != nil { - return err - } - err = ioutil.WriteFile(_filePath(dir, name), data, info.Mode()) - if err != nil { - return err - } - err = os.Chtimes(_filePath(dir, name), info.ModTime(), info.ModTime()) - if err != nil { - return err - } - return nil -} - -// RestoreAssets restores an asset under the given directory recursively -func RestoreAssets(dir, name string) error { - children, err := AssetDir(name) - // File - if err != nil { - return RestoreAsset(dir, name) - } - // Dir - for _, child := range children { - err = RestoreAssets(dir, filepath.Join(name, child)) - if err != nil { - return err - } - } - return nil -} - -func _filePath(dir, name string) string { - cannonicalName := strings.Replace(name, "\\", "/", -1) - return filepath.Join(append([]string{dir}, strings.Split(cannonicalName, "/")...)...) -} diff --git a/assets/bindata_dep.go b/assets/bindata_dep.go deleted file mode 100644 index 50459a4452d..00000000000 --- a/assets/bindata_dep.go +++ /dev/null @@ -1,9 +0,0 @@ -//+build never,!never - -package assets - -import ( - // Make sure go mod tracks these deps but avoid including them in the - // actual build. - _ "github.com/go-bindata/go-bindata/v3" -) diff --git a/assets/bindata_version_hash.go b/assets/bindata_version_hash.go deleted file mode 100644 index ac8bd502fe8..00000000000 --- a/assets/bindata_version_hash.go +++ /dev/null @@ -1,6 +0,0 @@ -// File generated together with 'bindata.go' when running `go generate .` DO NOT EDIT. (@generated) -package assets - -const ( - BindataVersionHash = "512eb789cd905714e03f29d4e04de7549e8c9c3e" -) diff --git a/core/corehttp/gateway_handler_unixfs_dir.go b/core/corehttp/gateway_handler_unixfs_dir.go index 7d491ea49fd..f462e52f8f6 100644 --- a/core/corehttp/gateway_handler_unixfs_dir.go +++ b/core/corehttp/gateway_handler_unixfs_dir.go @@ -94,7 +94,7 @@ func (i *gatewayHandler) serveDirectory(ctx context.Context, w http.ResponseWrit w.Header().Set("Content-Type", "text/html") // Generated dir index requires custom Etag (it may change between go-ipfs versions) - if assets.BindataVersionHash != "" { + if assets.AssetHash != "" { dirEtag := getDirListingEtag(resolvedPath.Cid()) w.Header().Set("Etag", dirEtag) if r.Header.Get("If-None-Match") == dirEtag { @@ -208,5 +208,5 @@ func (i *gatewayHandler) serveDirectory(ctx context.Context, w http.ResponseWrit } func getDirListingEtag(dirCid cid.Cid) string { - return `"DirIndex-` + assets.BindataVersionHash + `_CID-` + dirCid.String() + `"` + return `"DirIndex-` + assets.AssetHash + `_CID-` + dirCid.String() + `"` } diff --git a/go.mod b/go.mod index 3cbfbe3eb28..1756df7f291 100644 --- a/go.mod +++ b/go.mod @@ -5,6 +5,7 @@ require ( contrib.go.opencensus.io/exporter/prometheus v0.4.0 github.com/blang/semver/v4 v4.0.0 github.com/ceramicnetwork/go-dag-jose v0.1.0 + github.com/cespare/xxhash v1.1.0 github.com/cheggaaa/pb v1.0.29 github.com/coreos/go-systemd/v22 v22.3.2 github.com/dustin/go-humanize v1.0.0 @@ -12,7 +13,6 @@ require ( github.com/facebookgo/atomicfile v0.0.0-20151019160806-2de1f203e7d5 github.com/fsnotify/fsnotify v1.5.1 github.com/gabriel-vasile/mimetype v1.4.0 - github.com/go-bindata/go-bindata/v3 v3.1.3 github.com/hashicorp/go-multierror v1.1.1 github.com/ipfs/go-bitswap v0.6.0 github.com/ipfs/go-block-format v0.0.3 diff --git a/go.sum b/go.sum index e12f621d602..c66a3626052 100644 --- a/go.sum +++ b/go.sum @@ -241,8 +241,6 @@ github.com/gabriel-vasile/mimetype v1.4.0 h1:Cn9dkdYsMIu56tGho+fqzh7XmvY2YyGU0Fn github.com/gabriel-vasile/mimetype v1.4.0/go.mod h1:fA8fi6KUiG7MgQQ+mEWotXoEOvmxRtOJlERCzSmRvr8= github.com/ghodss/yaml v1.0.0/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04= github.com/gliderlabs/ssh v0.1.1/go.mod h1:U7qILu1NlMHj9FlMhZLlkCdDnU1DBEAqr0aevW3Awn0= -github.com/go-bindata/go-bindata/v3 v3.1.3 h1:F0nVttLC3ws0ojc7p60veTurcOm//D4QBODNM7EGrCI= -github.com/go-bindata/go-bindata/v3 v3.1.3/go.mod h1:1/zrpXsLD8YDIbhZRqXzm1Ghc7NhEvIN9+Z6R5/xH4I= github.com/go-check/check v0.0.0-20180628173108-788fd7840127/go.mod h1:9ES+weclKsC9YodN5RgxqK/VD9HM9JsCSh7rNhMZE98= github.com/go-errors/errors v1.0.1/go.mod h1:f4zRHt4oKfwPJE5k8C9vpYG+aDHdBFUsgrm6/TyX73Q= github.com/go-gl/glfw v0.0.0-20190409004039-e6da0acd62b1/go.mod h1:vR7hzQXu2zJy9AVAgeJqvqgH9Q5CA+iKCZ2gyEVpxRU= @@ -667,7 +665,6 @@ github.com/julienschmidt/httprouter v1.3.0/go.mod h1:JR6WtHb+2LUe8TCKY3cZOxFyyO8 github.com/kami-zh/go-capturer v0.0.0-20171211120116-e492ea43421d/go.mod h1:P2viExyCEfeWGU259JnaQ34Inuec4R38JCyBx2edgD0= github.com/kisielk/errcheck v1.1.0/go.mod h1:EZBBE59ingxPouuu3KfxchcWSUPOHkagtvWXihfKN4Q= github.com/kisielk/errcheck v1.2.0/go.mod h1:/BMXB+zMLi60iA8Vv6Ksmxu/1UDYcXs4uQLJ+jE2L00= -github.com/kisielk/errcheck v1.5.0 h1:e8esj/e4R+SAOwFwN+n3zr0nYeCyeweozKfO23MvHzY= github.com/kisielk/errcheck v1.5.0/go.mod h1:pFxgyoBC7bSaBwPgfKdkLd5X25qrDl4LWUI2bnpBCr8= github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck= github.com/kkdai/bstream v0.0.0-20161212061736-f391b8402d23/go.mod h1:J+Gs4SYgM6CZQHDETBtE9HaSEkGmuNXF86RwHhHUvq4= @@ -1625,7 +1622,6 @@ golang.org/x/lint v0.0.0-20190909230951-414d861bb4ac/go.mod h1:6SW0HCj/g11FgYtHl golang.org/x/lint v0.0.0-20190930215403-16217165b5de/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= golang.org/x/lint v0.0.0-20191125180803-fdd1cda4f05f/go.mod h1:5qLYkcX4OjUUV8bRuDixDT3tpyyb+LUpUlRWLxfhWrs= golang.org/x/lint v0.0.0-20200130185559-910be7a94367/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY= -golang.org/x/lint v0.0.0-20200302205851-738671d3881b h1:Wh+f8QHJXR411sJR8/vRBTZ7YapZaRvUcLFFJhusH0k= golang.org/x/lint v0.0.0-20200302205851-738671d3881b/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY= golang.org/x/mobile v0.0.0-20190312151609-d3739f865fa6/go.mod h1:z+o9i4GpDbdi3rU15maQ/Ox0txvL9dWGYEHz965HBQE= golang.org/x/mobile v0.0.0-20190719004257-d2bd2a29d028/go.mod h1:E/iHnbuqvinMTCcRqshq8CkpyQDoeVncDDYHnLhea+o= From 70398d275cad281bb55362632dd5a1ce7cb6e80e Mon Sep 17 00:00:00 2001 From: Franky W Date: Mon, 11 Apr 2022 15:31:46 +0200 Subject: [PATCH 350/414] Change `assets.Asset` from a `func` to the embed.FS This removes the delegation to the function and requires all callers that used the `asset.Asset` func to access to asset via the `embed.FS` --- assets/assets.go | 13 +++---------- core/corehttp/gateway_indexPage.go | 4 ++-- 2 files changed, 5 insertions(+), 12 deletions(-) diff --git a/assets/assets.go b/assets/assets.go index 579a8b2ca73..e16c8ff172d 100644 --- a/assets/assets.go +++ b/assets/assets.go @@ -20,7 +20,7 @@ import ( ) //go:embed init-doc dir-index-html/dir-index.html dir-index-html/knownIcons.txt -var dir embed.FS +var Asset embed.FS // AssetHash a non-cryptographic hash of all embedded assets var AssetHash string @@ -43,7 +43,7 @@ func init() { return nil } - file, err := dir.Open(path) + file, err := Asset.Open(path) if err != nil { return err } @@ -58,13 +58,6 @@ func init() { AssetHash = strconv.FormatUint(sum.Sum64(), 32) } -// Asset loads and returns the asset for the given name. -// It returns an error if the asset could not be found or -// could not be loaded. -func Asset(f string) ([]byte, error) { - return dir.ReadFile(f) -} - // SeedInitDocs adds the list of embedded init documentation to the passed node, pins it and returns the root key func SeedInitDocs(nd *core.IpfsNode) (cid.Cid, error) { return addAssetList(nd, initDocPaths) @@ -84,7 +77,7 @@ func addAssetList(nd *core.IpfsNode, l []string) (cid.Cid, error) { basePath := path.IpfsPath(dirb.Cid()) for _, p := range l { - d, err := Asset(p) + d, err := Asset.ReadFile(p) if err != nil { return cid.Cid{}, fmt.Errorf("assets: could load Asset '%s': %s", p, err) } diff --git a/core/corehttp/gateway_indexPage.go b/core/corehttp/gateway_indexPage.go index 3bee4822bb4..fbea91649d3 100644 --- a/core/corehttp/gateway_indexPage.go +++ b/core/corehttp/gateway_indexPage.go @@ -94,7 +94,7 @@ func hasDNSLinkOrigin(gwURL string, path string) bool { var listingTemplate *template.Template func init() { - knownIconsBytes, err := assets.Asset("dir-index-html/knownIcons.txt") + knownIconsBytes, err := assets.Asset.ReadFile("dir-index-html/knownIcons.txt") if err != nil { panic(err) } @@ -121,7 +121,7 @@ func init() { } // Directory listing template - dirIndexBytes, err := assets.Asset("dir-index-html/dir-index.html") + dirIndexBytes, err := assets.Asset.ReadFile("dir-index-html/dir-index.html") if err != nil { panic(err) } From ca4a3ed96167d2ea2f46a4e5c1235ae4e7b65d31 Mon Sep 17 00:00:00 2001 From: Jorropo Date: Tue, 12 Apr 2022 02:25:31 +0200 Subject: [PATCH 351/414] fix: assets: correctly use the argument err in the WalkDirFunc Hashing Files --- assets/assets.go | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/assets/assets.go b/assets/assets.go index e16c8ff172d..dea00e28915 100644 --- a/assets/assets.go +++ b/assets/assets.go @@ -39,6 +39,10 @@ var initDocPaths = []string{ func init() { sum := xxhash.New() err := fs.WalkDir(Asset, ".", func(path string, d fs.DirEntry, err error) error { + if err != nil { + return err + } + if d.IsDir() { return nil } From bb68a685253f77fdf49475cb963ee1995c93657f Mon Sep 17 00:00:00 2001 From: Gus Eggert Date: Tue, 12 Apr 2022 11:58:03 -0400 Subject: [PATCH 352/414] feat: port collect-profiles.sh to 'ipfs diag profile' (#8786) * feat: add block profiling to collect-profiles.sh * feat: add more profiles to 'ipfs diag profile' This adds mutex and block profiles, and brings the command up-to-par with 'collect-profiles.sh', so that we can remove it. Profiles are also now collected concurrently, which improves the runtime from (profile_time * num_profiles) to just (profile_time). Note that this has a backwards-incompatible change, removing --cpu-profile-time in favor of the more general --profile-time, which covers all sampling profiles. * docs(cli): ipfs diag profile * add CLI flag to select specific diag collectors Co-authored-by: Marcin Rataj --- bin/collect-profiles.sh | 53 ------- cmd/ipfs/debug.go | 4 +- core/commands/profile.go | 217 +++++++------------------- core/commands/root.go | 2 +- core/commands/version.go | 26 +--- profile/goroutines.go | 27 ++++ profile/profile.go | 268 +++++++++++++++++++++++++++++++++ profile/profile_test.go | 172 +++++++++++++++++++++ test/sharness/t0152-profile.sh | 28 +++- version.go | 25 +++ 10 files changed, 574 insertions(+), 248 deletions(-) delete mode 100755 bin/collect-profiles.sh create mode 100644 profile/goroutines.go create mode 100644 profile/profile.go create mode 100644 profile/profile_test.go diff --git a/bin/collect-profiles.sh b/bin/collect-profiles.sh deleted file mode 100755 index 25032a4655b..00000000000 --- a/bin/collect-profiles.sh +++ /dev/null @@ -1,53 +0,0 @@ -#!/usr/bin/env bash - -# collect-profiles.sh -# -# Collects go profile information from a running `ipfs` daemon. -# Creates an archive including the profiles, profile graph svgs, -# ...and where available, a copy of the `ipfs` binary on the PATH. -# -# Please run this script and attach the profile archive it creates -# when reporting bugs at https://github.com/ipfs/go-ipfs/issues - -set -euo pipefail -IFS=$'\n\t' - -SOURCE_URL="${1:-http://127.0.0.1:5001}" -tmpdir=$(mktemp -d) -export PPROF_TMPDIR="$tmpdir" -pushd "$tmpdir" > /dev/null - -if command -v ipfs > /dev/null 2>&1; then - cp "$(command -v ipfs)" ipfs -fi - -echo Collecting goroutine stacks -curl -s -o goroutines.stacks "$SOURCE_URL"'/debug/pprof/goroutine?debug=2' - -curl -s -o goroutines.stacks.full "$SOURCE_URL"'/debug/stack' - -echo Collecting goroutine profile -go tool pprof -symbolize=remote -svg -output goroutine.svg "$SOURCE_URL/debug/pprof/goroutine" - -echo Collecting heap profile -go tool pprof -symbolize=remote -svg -output heap.svg "$SOURCE_URL/debug/pprof/heap" - -echo "Collecting cpu profile (~30s)" -go tool pprof -symbolize=remote -svg -output cpu.svg "$SOURCE_URL/debug/pprof/profile" - -echo "Enabling mutex profiling" -curl -X POST "$SOURCE_URL"'/debug/pprof-mutex/?fraction=4' - -echo "Waiting for mutex data to be updated (30s)" -sleep 30 -curl -s -o mutex.txt "$SOURCE_URL"'/debug/pprof/mutex?debug=2' -go tool pprof -symbolize=remote -svg -output mutex.svg "$SOURCE_URL/debug/pprof/mutex" - -echo "Disabling mutex profiling" -curl -X POST "$SOURCE_URL"'/debug/pprof-mutex/?fraction=0' - -OUTPUT_NAME=ipfs-profile-$(uname -n)-$(date +'%Y-%m-%dT%H:%M:%S%z').tar.gz -echo "Creating $OUTPUT_NAME" -popd > /dev/null -tar czf "./$OUTPUT_NAME" -C "$tmpdir" . -rm -rf "$tmpdir" diff --git a/cmd/ipfs/debug.go b/cmd/ipfs/debug.go index d3fa90940b9..5eeb590e2c5 100644 --- a/cmd/ipfs/debug.go +++ b/cmd/ipfs/debug.go @@ -3,13 +3,13 @@ package main import ( "net/http" - "github.com/ipfs/go-ipfs/core/commands" + "github.com/ipfs/go-ipfs/profile" ) func init() { http.HandleFunc("/debug/stack", func(w http.ResponseWriter, _ *http.Request) { - _ = commands.WriteAllGoroutineStacks(w) + _ = profile.WriteAllGoroutineStacks(w) }, ) } diff --git a/core/commands/profile.go b/core/commands/profile.go index f92c3169a7c..a5567fc814b 100644 --- a/core/commands/profile.go +++ b/core/commands/profile.go @@ -2,18 +2,15 @@ package commands import ( "archive/zip" - "context" - "encoding/json" "fmt" "io" "os" - "runtime" - "runtime/pprof" "strings" "time" cmds "github.com/ipfs/go-ipfs-cmds" "github.com/ipfs/go-ipfs/core/commands/e" + "github.com/ipfs/go-ipfs/profile" ) // time format that works in filenames on windows. @@ -23,22 +20,27 @@ type profileResult struct { File string } -const cpuProfileTimeOption = "cpu-profile-time" +const ( + collectorsOptionName = "collectors" + profileTimeOption = "profile-time" + mutexProfileFractionOption = "mutex-profile-fraction" + blockProfileRateOption = "block-profile-rate" +) var sysProfileCmd = &cmds.Command{ Helptext: cmds.HelpText{ Tagline: "Collect a performance profile for debugging.", ShortDescription: ` -Collects cpu, heap, and goroutine profiles from a running go-ipfs daemon -into a single zip file. To aid in debugging, this command also attempts to -include a copy of the running go-ipfs binary. +Collects profiles from a running go-ipfs daemon into a single zip file. +To aid in debugging, this command also attempts to include a copy of +the running go-ipfs binary. `, LongDescription: ` -Collects cpu, heap, and goroutine profiles from a running go-ipfs daemon -into a single zipfile. To aid in debugging, this command also attempts to -include a copy of the running go-ipfs binary. +Collects profiles from a running go-ipfs daemon into a single zipfile. +To aid in debugging, this command also attempts to include a copy of +the running go-ipfs binary. -Profile's can be examined using 'go tool pprof', some tips can be found at +Profiles can be examined using 'go tool pprof', some tips can be found at https://github.com/ipfs/go-ipfs/blob/master/docs/debug-guide.md. Privacy Notice: @@ -48,6 +50,8 @@ The output file includes: - A list of running goroutines. - A CPU profile. - A heap profile. +- A mutex profile. +- A block profile. - Your copy of go-ipfs. - The output of 'ipfs version --all'. @@ -68,19 +72,51 @@ However, it could reveal: }, NoLocal: true, Options: []cmds.Option{ - cmds.StringOption(outputOptionName, "o", "The path where the output should be stored."), - cmds.StringOption(cpuProfileTimeOption, "The amount of time spent profiling CPU usage.").WithDefault("30s"), + cmds.StringOption(outputOptionName, "o", "The path where the output .zip should be stored. Default: ./ipfs-profile-[timestamp].zip"), + cmds.DelimitedStringsOption(",", collectorsOptionName, "The list of collectors to use for collecting diagnostic data."). + WithDefault([]string{ + profile.CollectorGoroutinesStack, + profile.CollectorGoroutinesPprof, + profile.CollectorVersion, + profile.CollectorHeap, + profile.CollectorBin, + profile.CollectorCPU, + profile.CollectorMutex, + profile.CollectorBlock, + }), + cmds.StringOption(profileTimeOption, "The amount of time spent profiling. If this is set to 0, then sampling profiles are skipped.").WithDefault("30s"), + cmds.IntOption(mutexProfileFractionOption, "The fraction 1/n of mutex contention events that are reported in the mutex profile.").WithDefault(4), + cmds.StringOption(blockProfileRateOption, "The duration to wait between sampling goroutine-blocking events for the blocking profile.").WithDefault("1ms"), }, Run: func(req *cmds.Request, res cmds.ResponseEmitter, env cmds.Environment) error { - cpuProfileTimeStr, _ := req.Options[cpuProfileTimeOption].(string) - cpuProfileTime, err := time.ParseDuration(cpuProfileTimeStr) + collectors := req.Options[collectorsOptionName].([]string) + + profileTimeStr, _ := req.Options[profileTimeOption].(string) + profileTime, err := time.ParseDuration(profileTimeStr) if err != nil { - return fmt.Errorf("failed to parse CPU profile duration %q: %w", cpuProfileTimeStr, err) + return fmt.Errorf("failed to parse profile duration %q: %w", profileTimeStr, err) } + blockProfileRateStr, _ := req.Options[blockProfileRateOption].(string) + blockProfileRate, err := time.ParseDuration(blockProfileRateStr) + if err != nil { + return fmt.Errorf("failed to parse block profile rate %q: %w", blockProfileRateStr, err) + } + + mutexProfileFraction, _ := req.Options[mutexProfileFractionOption].(int) + r, w := io.Pipe() + go func() { - _ = w.CloseWithError(writeProfiles(req.Context, cpuProfileTime, w)) + archive := zip.NewWriter(w) + err = profile.WriteProfiles(req.Context, archive, profile.Options{ + Collectors: collectors, + ProfileDuration: profileTime, + MutexProfileFraction: mutexProfileFraction, + BlockProfileRate: blockProfileRate, + }) + archive.Close() + _ = w.CloseWithError(err) }() return res.Emit(r) }, @@ -120,148 +156,3 @@ However, it could reveal: }), }, } - -func WriteAllGoroutineStacks(w io.Writer) error { - // this is based on pprof.writeGoroutineStacks, and removes the 64 MB limit - buf := make([]byte, 1<<20) - for i := 0; ; i++ { - n := runtime.Stack(buf, true) - if n < len(buf) { - buf = buf[:n] - break - } - // if len(buf) >= 64<<20 { - // // Filled 64 MB - stop there. - // break - // } - buf = make([]byte, 2*len(buf)) - } - _, err := w.Write(buf) - return err -} - -func writeProfiles(ctx context.Context, cpuProfileTime time.Duration, w io.Writer) error { - archive := zip.NewWriter(w) - - // Take some profiles. - type profile struct { - name string - file string - debug int - } - - profiles := []profile{{ - name: "goroutine", - file: "goroutines.stacks", - debug: 2, - }, { - name: "goroutine", - file: "goroutines.pprof", - }, { - name: "heap", - file: "heap.pprof", - }} - - { - out, err := archive.Create("goroutines-all.stacks") - if err != nil { - return err - } - err = WriteAllGoroutineStacks(out) - if err != nil { - return err - } - } - - for _, profile := range profiles { - prof := pprof.Lookup(profile.name) - out, err := archive.Create(profile.file) - if err != nil { - return err - } - err = prof.WriteTo(out, profile.debug) - if err != nil { - return err - } - } - - // Take a CPU profile. - if cpuProfileTime != 0 { - out, err := archive.Create("cpu.pprof") - if err != nil { - return err - } - - err = writeCPUProfile(ctx, cpuProfileTime, out) - if err != nil { - return err - } - } - - // Collect version info - // I'd use diag sysinfo, but that includes some more sensitive information - // (GOPATH, etc.). - { - out, err := archive.Create("version.json") - if err != nil { - return err - } - - err = json.NewEncoder(out).Encode(getVersionInfo()) - if err != nil { - return err - } - } - - // Collect binary - if fi, err := openIPFSBinary(); err == nil { - fname := "ipfs" - if runtime.GOOS == "windows" { - fname += ".exe" - } - - out, err := archive.Create(fname) - if err != nil { - return err - } - - _, err = io.Copy(out, fi) - _ = fi.Close() - if err != nil { - return err - } - } - return archive.Close() -} - -func writeCPUProfile(ctx context.Context, d time.Duration, w io.Writer) error { - if err := pprof.StartCPUProfile(w); err != nil { - return err - } - defer pprof.StopCPUProfile() - - timer := time.NewTimer(d) - defer timer.Stop() - - select { - case <-timer.C: - case <-ctx.Done(): - return ctx.Err() - } - return nil -} - -func openIPFSBinary() (*os.File, error) { - if runtime.GOOS == "linux" { - pid := os.Getpid() - fi, err := os.Open(fmt.Sprintf("/proc/%d/exe", pid)) - if err == nil { - return fi, nil - } - } - path, err := os.Executable() - if err != nil { - return nil, err - } - return os.Open(path) -} diff --git a/core/commands/root.go b/core/commands/root.go index 64b9b42fbf0..3fe31a8587a 100644 --- a/core/commands/root.go +++ b/core/commands/root.go @@ -67,13 +67,13 @@ NETWORK COMMANDS swarm Manage connections to the p2p network dht Query the DHT for values or peers ping Measure the latency of a connection - diag Print diagnostics bitswap Inspect bitswap state pubsub Send and receive messages via pubsub TOOL COMMANDS config Manage configuration version Show IPFS version information + diag Generate diagnostic reports update Download and apply go-ipfs updates commands List all available commands log Manage and show logs of running daemon diff --git a/core/commands/version.go b/core/commands/version.go index ecdda594b2d..70686da24dc 100644 --- a/core/commands/version.go +++ b/core/commands/version.go @@ -4,23 +4,13 @@ import ( "errors" "fmt" "io" - "runtime" "runtime/debug" version "github.com/ipfs/go-ipfs" - fsrepo "github.com/ipfs/go-ipfs/repo/fsrepo" cmds "github.com/ipfs/go-ipfs-cmds" ) -type VersionOutput struct { - Version string - Commit string - Repo string - System string - Golang string -} - const ( versionNumberOptionName = "number" versionCommitOptionName = "commit" @@ -28,16 +18,6 @@ const ( versionAllOptionName = "all" ) -func getVersionInfo() *VersionOutput { - return &VersionOutput{ - Version: version.CurrentVersionNumber, - Commit: version.CurrentCommit, - Repo: fmt.Sprint(fsrepo.RepoVersion), - System: runtime.GOARCH + "/" + runtime.GOOS, //TODO: Precise version here - Golang: runtime.Version(), - } -} - var VersionCmd = &cmds.Command{ Helptext: cmds.HelpText{ Tagline: "Show IPFS version information.", @@ -56,10 +36,10 @@ var VersionCmd = &cmds.Command{ // must be permitted to run before init Extra: CreateCmdExtras(SetDoesNotUseRepo(true), SetDoesNotUseConfigAsInput(true)), Run: func(req *cmds.Request, res cmds.ResponseEmitter, env cmds.Environment) error { - return cmds.EmitOnce(res, getVersionInfo()) + return cmds.EmitOnce(res, version.GetVersionInfo()) }, Encoders: cmds.EncoderMap{ - cmds.Text: cmds.MakeTypedEncoder(func(req *cmds.Request, w io.Writer, version *VersionOutput) error { + cmds.Text: cmds.MakeTypedEncoder(func(req *cmds.Request, w io.Writer, version *version.VersionInfo) error { all, _ := req.Options[versionAllOptionName].(bool) if all { ver := version.Version @@ -95,7 +75,7 @@ var VersionCmd = &cmds.Command{ return nil }), }, - Type: VersionOutput{}, + Type: version.VersionInfo{}, } type Dependency struct { diff --git a/profile/goroutines.go b/profile/goroutines.go new file mode 100644 index 00000000000..be227af488d --- /dev/null +++ b/profile/goroutines.go @@ -0,0 +1,27 @@ +package profile + +import ( + "io" + "runtime" +) + +// WriteAllGoroutineStacks writes a stack trace to the given writer. +// This is distinct from the Go-provided method because it does not truncate after 64 MB. +func WriteAllGoroutineStacks(w io.Writer) error { + // this is based on pprof.writeGoroutineStacks, and removes the 64 MB limit + buf := make([]byte, 1<<20) + for i := 0; ; i++ { + n := runtime.Stack(buf, true) + if n < len(buf) { + buf = buf[:n] + break + } + // if len(buf) >= 64<<20 { + // // Filled 64 MB - stop there. + // break + // } + buf = make([]byte, 2*len(buf)) + } + _, err := w.Write(buf) + return err +} diff --git a/profile/profile.go b/profile/profile.go new file mode 100644 index 00000000000..06cd4a7ba33 --- /dev/null +++ b/profile/profile.go @@ -0,0 +1,268 @@ +package profile + +import ( + "archive/zip" + "bytes" + "context" + "encoding/json" + "fmt" + "io" + "os" + "runtime" + "runtime/pprof" + "sync" + "time" + + version "github.com/ipfs/go-ipfs" + "github.com/ipfs/go-log" +) + +const ( + CollectorGoroutinesStack = "goroutines-stack" + CollectorGoroutinesPprof = "goroutines-pprof" + CollectorVersion = "version" + CollectorHeap = "heap" + CollectorBin = "bin" + CollectorCPU = "cpu" + CollectorMutex = "mutex" + CollectorBlock = "block" +) + +var ( + logger = log.Logger("profile") + goos = runtime.GOOS +) + +type collector struct { + outputFile string + isExecutable bool + collectFunc func(ctx context.Context, opts Options, writer io.Writer) error + enabledFunc func(opts Options) bool +} + +func (p *collector) outputFileName() string { + fName := p.outputFile + if p.isExecutable { + if goos == "windows" { + fName += ".exe" + } + } + return fName +} + +var collectors = map[string]collector{ + CollectorGoroutinesStack: { + outputFile: "goroutines.stacks", + collectFunc: goroutineStacksText, + enabledFunc: func(opts Options) bool { return true }, + }, + CollectorGoroutinesPprof: { + outputFile: "goroutines.pprof", + collectFunc: goroutineStacksProto, + enabledFunc: func(opts Options) bool { return true }, + }, + CollectorVersion: { + outputFile: "version.json", + collectFunc: versionInfo, + enabledFunc: func(opts Options) bool { return true }, + }, + CollectorHeap: { + outputFile: "heap.pprof", + collectFunc: heapProfile, + enabledFunc: func(opts Options) bool { return true }, + }, + CollectorBin: { + outputFile: "ipfs", + isExecutable: true, + collectFunc: binary, + enabledFunc: func(opts Options) bool { return true }, + }, + CollectorCPU: { + outputFile: "cpu.pprof", + collectFunc: profileCPU, + enabledFunc: func(opts Options) bool { return opts.ProfileDuration > 0 }, + }, + CollectorMutex: { + outputFile: "mutex.pprof", + collectFunc: mutexProfile, + enabledFunc: func(opts Options) bool { return opts.ProfileDuration > 0 && opts.MutexProfileFraction > 0 }, + }, + CollectorBlock: { + outputFile: "block.pprof", + collectFunc: blockProfile, + enabledFunc: func(opts Options) bool { return opts.ProfileDuration > 0 && opts.BlockProfileRate > 0 }, + }, +} + +type Options struct { + Collectors []string + ProfileDuration time.Duration + MutexProfileFraction int + BlockProfileRate time.Duration +} + +func WriteProfiles(ctx context.Context, archive *zip.Writer, opts Options) error { + p := profiler{ + archive: archive, + opts: opts, + } + return p.runProfile(ctx) +} + +// profiler runs the collectors concurrently and writes the results to the zip archive. +type profiler struct { + archive *zip.Writer + opts Options +} + +func (p *profiler) runProfile(ctx context.Context) error { + type profileResult struct { + fName string + buf *bytes.Buffer + err error + } + + ctx, cancelFn := context.WithCancel(ctx) + defer cancelFn() + + var collectorsToRun []collector + for _, name := range p.opts.Collectors { + c, ok := collectors[name] + if !ok { + return fmt.Errorf("unknown collector '%s'", name) + } + collectorsToRun = append(collectorsToRun, c) + } + + results := make(chan profileResult, len(p.opts.Collectors)) + wg := sync.WaitGroup{} + for _, c := range collectorsToRun { + if !c.enabledFunc(p.opts) { + continue + } + + fName := c.outputFileName() + + wg.Add(1) + go func(c collector) { + defer wg.Done() + logger.Infow("collecting profile", "File", fName) + defer logger.Infow("profile done", "File", fName) + b := bytes.Buffer{} + err := c.collectFunc(ctx, p.opts, &b) + if err != nil { + select { + case results <- profileResult{err: fmt.Errorf("generating profile data for %q: %w", fName, err)}: + case <-ctx.Done(): + return + } + } + select { + case results <- profileResult{buf: &b, fName: fName}: + case <-ctx.Done(): + } + }(c) + } + go func() { + wg.Wait() + close(results) + }() + + for res := range results { + if res.err != nil { + return res.err + } + out, err := p.archive.Create(res.fName) + if err != nil { + return fmt.Errorf("creating output file %q: %w", res.fName, err) + } + _, err = io.Copy(out, res.buf) + if err != nil { + return fmt.Errorf("compressing result %q: %w", res.fName, err) + } + } + + return nil +} + +func goroutineStacksText(ctx context.Context, _ Options, w io.Writer) error { + return WriteAllGoroutineStacks(w) +} + +func goroutineStacksProto(ctx context.Context, _ Options, w io.Writer) error { + return pprof.Lookup("goroutine").WriteTo(w, 0) +} + +func heapProfile(ctx context.Context, _ Options, w io.Writer) error { + return pprof.Lookup("heap").WriteTo(w, 0) +} + +func versionInfo(ctx context.Context, _ Options, w io.Writer) error { + return json.NewEncoder(w).Encode(version.GetVersionInfo()) +} + +func binary(ctx context.Context, _ Options, w io.Writer) error { + var ( + path string + err error + ) + if goos == "linux" { + pid := os.Getpid() + path = fmt.Sprintf("/proc/%d/exe", pid) + } else { + path, err = os.Executable() + if err != nil { + return fmt.Errorf("finding binary path: %w", err) + } + } + fi, err := os.Open(path) + if err != nil { + return fmt.Errorf("opening binary %q: %w", path, err) + } + _, err = io.Copy(w, fi) + _ = fi.Close() + if err != nil { + return fmt.Errorf("copying binary %q: %w", path, err) + } + return nil +} + +func mutexProfile(ctx context.Context, opts Options, w io.Writer) error { + prev := runtime.SetMutexProfileFraction(opts.MutexProfileFraction) + defer runtime.SetMutexProfileFraction(prev) + err := waitOrCancel(ctx, opts.ProfileDuration) + if err != nil { + return err + } + return pprof.Lookup("mutex").WriteTo(w, 2) +} + +func blockProfile(ctx context.Context, opts Options, w io.Writer) error { + runtime.SetBlockProfileRate(int(opts.BlockProfileRate.Nanoseconds())) + defer runtime.SetBlockProfileRate(0) + err := waitOrCancel(ctx, opts.ProfileDuration) + if err != nil { + return err + } + return pprof.Lookup("block").WriteTo(w, 2) +} + +func profileCPU(ctx context.Context, opts Options, w io.Writer) error { + err := pprof.StartCPUProfile(w) + if err != nil { + return err + } + defer pprof.StopCPUProfile() + return waitOrCancel(ctx, opts.ProfileDuration) +} + +func waitOrCancel(ctx context.Context, d time.Duration) error { + timer := time.NewTimer(d) + defer timer.Stop() + select { + case <-timer.C: + return nil + case <-ctx.Done(): + return ctx.Err() + } +} diff --git a/profile/profile_test.go b/profile/profile_test.go new file mode 100644 index 00000000000..8da00d0181a --- /dev/null +++ b/profile/profile_test.go @@ -0,0 +1,172 @@ +package profile + +import ( + "archive/zip" + "bytes" + "context" + "testing" + "time" + + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" +) + +func TestProfiler(t *testing.T) { + allCollectors := []string{ + CollectorGoroutinesStack, + CollectorGoroutinesPprof, + CollectorVersion, + CollectorHeap, + CollectorBin, + CollectorCPU, + CollectorMutex, + CollectorBlock, + } + + cases := []struct { + name string + opts Options + goos string + + expectFiles []string + }{ + { + name: "happy case", + opts: Options{ + Collectors: allCollectors, + ProfileDuration: 1 * time.Millisecond, + MutexProfileFraction: 4, + BlockProfileRate: 50 * time.Nanosecond, + }, + expectFiles: []string{ + "goroutines.stacks", + "goroutines.pprof", + "version.json", + "heap.pprof", + "ipfs", + "cpu.pprof", + "mutex.pprof", + "block.pprof", + }, + }, + { + name: "windows", + opts: Options{ + Collectors: allCollectors, + ProfileDuration: 1 * time.Millisecond, + MutexProfileFraction: 4, + BlockProfileRate: 50 * time.Nanosecond, + }, + goos: "windows", + expectFiles: []string{ + "goroutines.stacks", + "goroutines.pprof", + "version.json", + "heap.pprof", + "ipfs.exe", + "cpu.pprof", + "mutex.pprof", + "block.pprof", + }, + }, + { + name: "sampling profiling disabled", + opts: Options{ + Collectors: allCollectors, + MutexProfileFraction: 4, + BlockProfileRate: 50 * time.Nanosecond, + }, + expectFiles: []string{ + "goroutines.stacks", + "goroutines.pprof", + "version.json", + "heap.pprof", + "ipfs", + }, + }, + { + name: "Mutex profiling disabled", + opts: Options{ + Collectors: allCollectors, + ProfileDuration: 1 * time.Millisecond, + BlockProfileRate: 50 * time.Nanosecond, + }, + expectFiles: []string{ + "goroutines.stacks", + "goroutines.pprof", + "version.json", + "heap.pprof", + "ipfs", + "cpu.pprof", + "block.pprof", + }, + }, + { + name: "block profiling disabled", + opts: Options{ + Collectors: allCollectors, + ProfileDuration: 1 * time.Millisecond, + MutexProfileFraction: 4, + BlockProfileRate: 0, + }, + expectFiles: []string{ + "goroutines.stacks", + "goroutines.pprof", + "version.json", + "heap.pprof", + "ipfs", + "cpu.pprof", + "mutex.pprof", + }, + }, + { + name: "single collector", + opts: Options{ + Collectors: []string{CollectorVersion}, + ProfileDuration: 1 * time.Millisecond, + MutexProfileFraction: 4, + BlockProfileRate: 0, + }, + expectFiles: []string{ + "version.json", + }, + }, + } + for _, c := range cases { + t.Run(c.name, func(t *testing.T) { + if c.goos != "" { + oldGOOS := goos + goos = c.goos + defer func() { goos = oldGOOS }() + } + + buf := &bytes.Buffer{} + archive := zip.NewWriter(buf) + err := WriteProfiles(context.Background(), archive, c.opts) + require.NoError(t, err) + + err = archive.Close() + require.NoError(t, err) + + zr, err := zip.NewReader(bytes.NewReader(buf.Bytes()), int64(buf.Len())) + require.NoError(t, err) + + for _, f := range zr.File { + logger.Info("zip file: ", f.Name) + } + + require.Equal(t, len(c.expectFiles), len(zr.File)) + + for _, expectedFile := range c.expectFiles { + func() { + f, err := zr.Open(expectedFile) + require.NoError(t, err) + defer f.Close() + fi, err := f.Stat() + require.NoError(t, err) + assert.NotZero(t, fi.Size()) + }() + } + }) + } +} diff --git a/test/sharness/t0152-profile.sh b/test/sharness/t0152-profile.sh index 13b40517b8d..0bc328d2ed2 100755 --- a/test/sharness/t0152-profile.sh +++ b/test/sharness/t0152-profile.sh @@ -16,8 +16,8 @@ test_expect_success "profiling requires a running daemon" ' test_launch_ipfs_daemon -test_expect_success "test profiling (without CPU)" ' - ipfs diag profile --cpu-profile-time=0 > cmd_out +test_expect_success "test profiling (without sampling)" ' + ipfs diag profile --profile-time=0 > cmd_out ' test_expect_success "filename shows up in output" ' @@ -29,12 +29,17 @@ test_expect_success "profile file created" ' ' test_expect_success "test profiling with -o" ' - ipfs diag profile --cpu-profile-time=1s -o test-profile.zip + ipfs diag profile --profile-time=1s -o test-profile.zip ' test_expect_success "test that test-profile.zip exists" ' test -e test-profile.zip ' + +test_expect_success "test profiling with specific collectors" ' + ipfs diag profile --collectors version,goroutines-stack -o test-profile-small.zip +' + test_kill_ipfs_daemon if ! test_have_prereq UNZIP; then @@ -42,7 +47,8 @@ if ! test_have_prereq UNZIP; then fi test_expect_success "unpack profiles" ' - unzip -d profiles test-profile.zip + unzip -d profiles test-profile.zip && + unzip -d profiles-small test-profile-small.zip ' test_expect_success "cpu profile is valid" ' @@ -57,12 +63,22 @@ test_expect_success "goroutines profile is valid" ' go tool pprof -top profiles/ipfs "profiles/goroutines.pprof" | grep -q "Type: goroutine" ' +test_expect_success "mutex profile is valid" ' + go tool pprof -top profiles/ipfs "profiles/mutex.pprof" | grep -q "Type: delay" +' + +test_expect_success "block profile is valid" ' + go tool pprof -top profiles/ipfs "profiles/block.pprof" | grep -q "Type: delay" +' + test_expect_success "goroutines stacktrace is valid" ' grep -q "goroutine" "profiles/goroutines.stacks" ' -test_expect_success "full goroutines stacktrace is valid" ' - grep -q "goroutine" "profiles/goroutines-all.stacks" +test_expect_success "the small profile only contains the requested data" ' + find profiles-small -type f | sort > actual && + echo -e "profiles-small/goroutines.stacks\nprofiles-small/version.json" > expected && + test_cmp expected actual ' test_done diff --git a/version.go b/version.go index c29491a2745..0018a056ecc 100644 --- a/version.go +++ b/version.go @@ -1,5 +1,12 @@ package ipfs +import ( + "fmt" + "runtime" + + "github.com/ipfs/go-ipfs/repo/fsrepo" +) + // CurrentCommit is the current git commit, this is set as a ldflag in the Makefile var CurrentCommit string @@ -27,3 +34,21 @@ var userAgentSuffix string func SetUserAgentSuffix(suffix string) { userAgentSuffix = suffix } + +type VersionInfo struct { + Version string + Commit string + Repo string + System string + Golang string +} + +func GetVersionInfo() *VersionInfo { + return &VersionInfo{ + Version: CurrentVersionNumber, + Commit: CurrentCommit, + Repo: fmt.Sprint(fsrepo.RepoVersion), + System: runtime.GOARCH + "/" + runtime.GOOS, //TODO: Precise version here + Golang: runtime.Version(), + } +} From 63b00256642c6ddcb35eecd95ea4e23a6bba21f3 Mon Sep 17 00:00:00 2001 From: Caian Benedicto Date: Tue, 12 Apr 2022 14:44:03 -0300 Subject: [PATCH 353/414] feat(docker): /container-init.d for advanced initialization (#6577) * Add initialization directory support to Docker image * Add sharness test, fix bugs in init script Fixed in init script: - Added some missing quotes around expansions - Fixed INIT_ARGS to not pass any args if IPFS_PROFILE isn't specified - Use printf instead of "echo -e" - Only run scripts in top-level of init dir - Handle filenames correctly when finding init scripts (by using find + xargs) * chore: docker cleanup cleans up containers and images (useful when run on developer machine) * remove container init documentation from README There is already IPFS Docker documentation where this should live: https://docs.ipfs.io/how-to/run-ipfs-inside-docker/ Co-authored-by: Caian Co-authored-by: Marcin Rataj Co-authored-by: Gus Eggert --- Dockerfile | 5 +++++ bin/container_daemon | 19 ++++++++-------- bin/container_init_run | 14 ++++++++++++ test/ipfs-test-lib.sh | 10 +++++++++ test/sharness/t0300-docker-image.sh | 31 +++++++++++++++++++++++++-- test/sharness/t0301-docker-migrate.sh | 2 ++ 6 files changed, 69 insertions(+), 12 deletions(-) create mode 100755 bin/container_init_run diff --git a/Dockerfile b/Dockerfile index 751ba6a9f23..dce35b54c71 100644 --- a/Dockerfile +++ b/Dockerfile @@ -54,6 +54,7 @@ LABEL maintainer="Steven Allen " ENV SRC_DIR /go-ipfs COPY --from=0 $SRC_DIR/cmd/ipfs/ipfs /usr/local/bin/ipfs COPY --from=0 $SRC_DIR/bin/container_daemon /usr/local/bin/start_ipfs +COPY --from=0 $SRC_DIR/bin/container_init_run /usr/local/bin/container_init_run COPY --from=0 /tmp/su-exec/su-exec-static /sbin/su-exec COPY --from=0 /tmp/tini /sbin/tini COPY --from=0 /bin/fusermount /usr/local/bin/fusermount @@ -93,6 +94,10 @@ RUN mkdir -p $IPFS_PATH \ RUN mkdir /ipfs /ipns \ && chown ipfs:users /ipfs /ipns +# Create the init scripts directory +RUN mkdir /container-init.d \ + && chown ipfs:users /container-init.d + # Expose the fs-repo as a volume. # start_ipfs initializes an fs-repo if none is mounted. # Important this happens after the USER directive so permissions are correct. diff --git a/bin/container_daemon b/bin/container_daemon index 8fe429036a7..ae8725be5db 100755 --- a/bin/container_daemon +++ b/bin/container_daemon @@ -1,9 +1,10 @@ #!/bin/sh set -e + user=ipfs repo="$IPFS_PATH" -if [ `id -u` -eq 0 ]; then +if [ "$(id -u)" -eq 0 ]; then echo "Changing user to $user" # ensure folder is writable su-exec "$user" test -w "$repo" || chown -R -- "$user" "$repo" @@ -14,14 +15,11 @@ fi # 2nd invocation with regular user ipfs version + if [ -e "$repo/config" ]; then echo "Found IPFS fs-repo at $repo" else - case "$IPFS_PROFILE" in - "") INIT_ARGS="" ;; - *) INIT_ARGS="--profile=$IPFS_PROFILE" ;; - esac - ipfs init $INIT_ARGS + ipfs init ${IPFS_PROFILE:+"--profile=$IPFS_PROFILE"} ipfs config Addresses.API /ip4/0.0.0.0/tcp/5001 ipfs config Addresses.Gateway /ip4/0.0.0.0/tcp/8080 @@ -31,9 +29,9 @@ else SWARM_KEY_PERM=0400 # Create a swarm key from a given environment variable - if [ ! -z "$IPFS_SWARM_KEY" ] ; then + if [ -n "$IPFS_SWARM_KEY" ] ; then echo "Copying swarm key from variable..." - echo -e "$IPFS_SWARM_KEY" >"$SWARM_KEY_FILE" || exit 1 + printf "%s\n" "$IPFS_SWARM_KEY" >"$SWARM_KEY_FILE" || exit 1 chmod $SWARM_KEY_PERM "$SWARM_KEY_FILE" fi @@ -43,14 +41,15 @@ else # Check during initialization if a swarm key was provided and # copy it to the ipfs directory with the right permissions # WARNING: This will replace the swarm key if it exists - if [ ! -z "$IPFS_SWARM_KEY_FILE" ] ; then + if [ -n "$IPFS_SWARM_KEY_FILE" ] ; then echo "Copying swarm key from file..." install -m $SWARM_KEY_PERM "$IPFS_SWARM_KEY_FILE" "$SWARM_KEY_FILE" || exit 1 fi # Unset the swarm key file variable unset IPFS_SWARM_KEY_FILE - fi +find /container-init.d -maxdepth 1 -type f -iname '*.sh' -print0 | sort -z | xargs -n 1 -0 -r container_init_run + exec ipfs "$@" diff --git a/bin/container_init_run b/bin/container_init_run new file mode 100755 index 00000000000..9d20660ccfd --- /dev/null +++ b/bin/container_init_run @@ -0,0 +1,14 @@ +#!/bin/sh + +set -e + +# used by the container startup script for running initialization scripts + +script="$1" +if [ -x "$script" ] ; then + printf "Executing '%s'...\n" "$script" + "$script" +else + printf "Sourcing '%s'...\n" "$script" + . "$script" +fi diff --git a/test/ipfs-test-lib.sh b/test/ipfs-test-lib.sh index 960cf7caa86..eabf17020d2 100644 --- a/test/ipfs-test-lib.sh +++ b/test/ipfs-test-lib.sh @@ -70,6 +70,16 @@ docker_stop() { docker stop "$1" } +# This takes a docker ID as argument +docker_rm() { + docker rm -f -v "$1" > /dev/null +} + +# This takes a docker image name as argument +docker_rmi() { + docker rmi -f "$1" > /dev/null +} + # Test whether all the expected lines are included in a file. The file # can have extra lines. # diff --git a/test/sharness/t0300-docker-image.sh b/test/sharness/t0300-docker-image.sh index 2a25dd28406..a3a802b287f 100755 --- a/test/sharness/t0300-docker-image.sh +++ b/test/sharness/t0300-docker-image.sh @@ -29,7 +29,7 @@ TEST_TESTS_DIR=$(dirname "$TEST_SCRIPTS_DIR") APP_ROOT_DIR=$(dirname "$TEST_TESTS_DIR") test_expect_success "docker image build succeeds" ' - docker_build "$TEST_TESTS_DIR/../Dockerfile" "$APP_ROOT_DIR" >build-actual || + docker_build "$TEST_TESTS_DIR/../Dockerfile" "$APP_ROOT_DIR" | tee build-actual || test_fsh echo "TEST_TESTS_DIR: $TEST_TESTS_DIR" || test_fsh echo "APP_ROOT_DIR : $APP_ROOT_DIR" || test_fsh cat build-actual @@ -41,8 +41,18 @@ test_expect_success "docker image build output looks good" ' test_fsh cat build-actual ' +test_expect_success "write init scripts" ' + echo "ipfs config Foo Bar" > 001.sh && + echo "ipfs config Baz Qux" > 002.sh && + chmod +x 002.sh +' + test_expect_success "docker image runs" ' - DOC_ID=$(docker run -d -p 127.0.0.1:5001:5001 -p 127.0.0.1:8080:8080 "$IMAGE_ID") + DOC_ID=$(docker run -d \ + -p 127.0.0.1:5001:5001 -p 127.0.0.1:8080:8080 \ + -v "$PWD/001.sh":/container-init.d/001.sh \ + -v "$PWD/002.sh":/container-init.d/002.sh \ + "$IMAGE_ID") ' test_expect_success "docker container gateway is up" ' @@ -53,6 +63,21 @@ test_expect_success "docker container API is up" ' pollEndpoint -host=/ip4/127.0.0.1/tcp/5001 -http-url http://localhost:5001/version -v -tries 30 -tout 1s ' +test_expect_success "check that init scripts were run correctly and in the correct order" " + echo -e \"Sourcing '/container-init.d/001.sh'...\nExecuting '/container-init.d/002.sh'...\" > expected && + docker logs $DOC_ID 2>/dev/null | grep -e 001.sh -e 002.sh > actual && + test_cmp actual expected +" + +test_expect_success "check that init script configs were applied" ' + echo Bar > expected && + docker exec "$DOC_ID" ipfs config Foo > actual && + test_cmp actual expected && + echo Qux > expected && + docker exec "$DOC_ID" ipfs config Baz > actual && + test_cmp actual expected +' + test_expect_success "simple ipfs add/cat can be run in docker container" ' expected="Hello Worlds" && HASH=$(docker_exec "$DOC_ID" "echo $(cat expected) | ipfs add | cut -d' ' -f2") && @@ -74,5 +99,7 @@ test_expect_success "stop docker container" ' docker_stop "$DOC_ID" ' +docker_rm "$DOC_ID" +docker_rmi "$IMAGE_ID" test_done diff --git a/test/sharness/t0301-docker-migrate.sh b/test/sharness/t0301-docker-migrate.sh index 4fb9ab155e4..3f7d32f214b 100755 --- a/test/sharness/t0301-docker-migrate.sh +++ b/test/sharness/t0301-docker-migrate.sh @@ -77,5 +77,7 @@ test_expect_success "correct version was requested" ' grep "/fs-repo-6-to-7/v1.1.1/fs-repo-6-to-7_v1.1.1_linux-amd64.tar.gz" dist_serv_out > /dev/null ' +docker_rm "$DOC_ID" +docker_rmi "$IMAGE_ID" test_done From 9470fa3271db70233a1ec363b735c804147f4e42 Mon Sep 17 00:00:00 2001 From: Piotr Galar Date: Thu, 14 Apr 2022 13:39:36 +0200 Subject: [PATCH 354/414] Use testground-github-action from testground --- .github/workflows/testground-on-push.yml | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/.github/workflows/testground-on-push.yml b/.github/workflows/testground-on-push.yml index ac4dffaa86a..ae1c80dd99c 100644 --- a/.github/workflows/testground-on-push.yml +++ b/.github/workflows/testground-on-push.yml @@ -25,8 +25,7 @@ jobs: steps: - uses: actions/checkout@v2 - name: testground run - # restore the mainline once https://github.com/coryschwartz/testground-github-action/pull/2 is released - uses: galargh/testground-github-action@6bdc2d4f12280a3e0ec654fd75fe170d4b7931df + uses: testground/testground-github-action@v1 timeout-minutes: 5 with: backend_addr: ${{ matrix.backend_addr }} From e07baf5835f646352df14fa21ed641053cd0f81b Mon Sep 17 00:00:00 2001 From: Justin Johnson Date: Fri, 15 Apr 2022 09:06:43 -0500 Subject: [PATCH 355/414] chore(gw): extract logical functions to improve readability (#8885) * Extract functions from getOrHeadHandler to improve readability and prepare for later refactorings * Address PR feedback on when to return errors or booleans * Be explicit about use of *requestError vs error --- core/corehttp/gateway_handler.go | 212 ++++++++++++++++++++----------- 1 file changed, 139 insertions(+), 73 deletions(-) diff --git a/core/corehttp/gateway_handler.go b/core/corehttp/gateway_handler.go index 0c34cc9b175..52d86257b6d 100644 --- a/core/corehttp/gateway_handler.go +++ b/core/corehttp/gateway_handler.go @@ -28,6 +28,7 @@ import ( prometheus "github.com/prometheus/client_golang/prometheus" "go.opentelemetry.io/otel/attribute" "go.opentelemetry.io/otel/trace" + "go.uber.org/zap" ) const ( @@ -85,6 +86,25 @@ type statusResponseWriter struct { http.ResponseWriter } +// Custom type for collecting error details to be handled by `webRequestError` +type requestError struct { + Message string + StatusCode int + Err error +} + +func (r *requestError) Error() string { + return r.Err.Error() +} + +func newRequestError(message string, err error, statusCode int) *requestError { + return &requestError{ + Message: message, + Err: err, + StatusCode: statusCode, + } +} + func (sw *statusResponseWriter) WriteHeader(code int) { // Check if we need to adjust Status Code to account for scheduled redirect // This enables us to return payload along with HTTP 301 @@ -324,61 +344,22 @@ func (i *gatewayHandler) getOrHeadHandler(w http.ResponseWriter, r *http.Request logger := log.With("from", r.RequestURI) logger.Debug("http request received") - // X-Ipfs-Gateway-Prefix was removed (https://github.com/ipfs/go-ipfs/issues/7702) - // TODO: remove this after go-ipfs 0.13 ships - if prfx := r.Header.Get("X-Ipfs-Gateway-Prefix"); prfx != "" { - err := fmt.Errorf("X-Ipfs-Gateway-Prefix support was removed: https://github.com/ipfs/go-ipfs/issues/7702") - webError(w, "unsupported HTTP header", err, http.StatusBadRequest) + if err := handleUnsupportedHeaders(r); err != nil { + webRequestError(w, err) return } - // ?uri query param support for requests produced by web browsers - // via navigator.registerProtocolHandler Web API - // https://developer.mozilla.org/en-US/docs/Web/API/Navigator/registerProtocolHandler - // TLDR: redirect /ipfs/?uri=ipfs%3A%2F%2Fcid%3Fquery%3Dval to /ipfs/cid?query=val - if uriParam := r.URL.Query().Get("uri"); uriParam != "" { - u, err := url.Parse(uriParam) - if err != nil { - webError(w, "failed to parse uri query parameter", err, http.StatusBadRequest) - return - } - if u.Scheme != "ipfs" && u.Scheme != "ipns" { - webError(w, "uri query parameter scheme must be ipfs or ipns", err, http.StatusBadRequest) - return - } - path := u.Path - if u.RawQuery != "" { // preserve query if present - path = path + "?" + u.RawQuery - } - - redirectURL := gopath.Join("/", u.Scheme, u.Host, path) - logger.Debugw("uri param, redirect", "to", redirectURL, "status", http.StatusMovedPermanently) - http.Redirect(w, r, redirectURL, http.StatusMovedPermanently) + if requestHandled := handleProtocolHandlerRedirect(w, r, logger); requestHandled { return } - // Service Worker registration request - if r.Header.Get("Service-Worker") == "script" { - // Disallow Service Worker registration on namespace roots - // https://github.com/ipfs/go-ipfs/issues/4025 - matched, _ := regexp.MatchString(`^/ip[fn]s/[^/]+$`, r.URL.Path) - if matched { - err := fmt.Errorf("registration is not allowed for this scope") - webError(w, "navigator.serviceWorker", err, http.StatusBadRequest) - return - } + if err := handleServiceWorkerRegistration(r); err != nil { + webRequestError(w, err) + return } contentPath := ipath.New(r.URL.Path) - if pathErr := contentPath.IsValid(); pathErr != nil { - if fixupSuperfluousNamespace(w, r.URL.Path, r.URL.RawQuery) { - // the error was due to redundant namespace, which we were able to fix - // by returning error/redirect page, nothing left to do here - logger.Debugw("redundant namespace; noop") - return - } - // unable to fix path, returning error - webError(w, "invalid ipfs path", pathErr, http.StatusBadRequest) + if requestHandled := handleSuperfluousNamespace(w, r, contentPath); requestHandled { return } @@ -416,26 +397,13 @@ func (i *gatewayHandler) getOrHeadHandler(w http.ResponseWriter, r *http.Request return } - // Update the global metric of the time it takes to read the final root block of the requested resource - // NOTE: for legacy reasons this happens before we go into content-type specific code paths - _, err = i.api.Block().Get(r.Context(), resolvedPath) - if err != nil { - webError(w, "ipfs block get "+resolvedPath.Cid().String(), err, http.StatusInternalServerError) + if err := i.handleGettingFirstBlock(r, begin, contentPath, resolvedPath); err != nil { + webRequestError(w, err) return } - ns := contentPath.Namespace() - timeToGetFirstContentBlock := time.Since(begin).Seconds() - i.unixfsGetMetric.WithLabelValues(ns).Observe(timeToGetFirstContentBlock) // deprecated, use firstContentBlockGetMetric instead - i.firstContentBlockGetMetric.WithLabelValues(ns).Observe(timeToGetFirstContentBlock) - // HTTP Headers - i.addUserHeaders(w) // ok, _now_ write user's headers. - w.Header().Set("X-Ipfs-Path", contentPath.String()) - - if rootCids, err := i.buildIpfsRootsHeader(contentPath.String(), r); err == nil { - w.Header().Set("X-Ipfs-Roots", rootCids) - } else { // this should never happen, as we resolved the contentPath already - webError(w, "error while resolving X-Ipfs-Roots", err, http.StatusInternalServerError) + if err := i.setCommonHeaders(w, r, contentPath); err != nil { + webRequestError(w, err) return } @@ -785,6 +753,10 @@ func (i *gatewayHandler) buildIpfsRootsHeader(contentPath string, r *http.Reques return rootCidList, nil } +func webRequestError(w http.ResponseWriter, err *requestError) { + webError(w, err.Message, err.Err, err.StatusCode) +} + func webError(w http.ResponseWriter, message string, err error, defaultCode int) { if _, ok := err.(resolver.ErrNoLink); ok { webErrorWithCode(w, message, err, http.StatusNotFound) @@ -911,32 +883,126 @@ func debugStr(path string) string { return q } +func handleUnsupportedHeaders(r *http.Request) (err *requestError) { + // X-Ipfs-Gateway-Prefix was removed (https://github.com/ipfs/go-ipfs/issues/7702) + // TODO: remove this after go-ipfs 0.13 ships + if prfx := r.Header.Get("X-Ipfs-Gateway-Prefix"); prfx != "" { + err := fmt.Errorf("X-Ipfs-Gateway-Prefix support was removed: https://github.com/ipfs/go-ipfs/issues/7702") + return newRequestError("unsupported HTTP header", err, http.StatusBadRequest) + } + return nil +} + +// ?uri query param support for requests produced by web browsers +// via navigator.registerProtocolHandler Web API +// https://developer.mozilla.org/en-US/docs/Web/API/Navigator/registerProtocolHandler +// TLDR: redirect /ipfs/?uri=ipfs%3A%2F%2Fcid%3Fquery%3Dval to /ipfs/cid?query=val +func handleProtocolHandlerRedirect(w http.ResponseWriter, r *http.Request, logger *zap.SugaredLogger) (requestHandled bool) { + if uriParam := r.URL.Query().Get("uri"); uriParam != "" { + u, err := url.Parse(uriParam) + if err != nil { + webError(w, "failed to parse uri query parameter", err, http.StatusBadRequest) + return true + } + if u.Scheme != "ipfs" && u.Scheme != "ipns" { + webError(w, "uri query parameter scheme must be ipfs or ipns", err, http.StatusBadRequest) + return true + } + path := u.Path + if u.RawQuery != "" { // preserve query if present + path = path + "?" + u.RawQuery + } + + redirectURL := gopath.Join("/", u.Scheme, u.Host, path) + logger.Debugw("uri param, redirect", "to", redirectURL, "status", http.StatusMovedPermanently) + http.Redirect(w, r, redirectURL, http.StatusMovedPermanently) + return true + } + + return false +} + +// Disallow Service Worker registration on namespace roots +// https://github.com/ipfs/go-ipfs/issues/4025 +func handleServiceWorkerRegistration(r *http.Request) (err *requestError) { + if r.Header.Get("Service-Worker") == "script" { + matched, _ := regexp.MatchString(`^/ip[fn]s/[^/]+$`, r.URL.Path) + if matched { + err := fmt.Errorf("registration is not allowed for this scope") + return newRequestError("navigator.serviceWorker", err, http.StatusBadRequest) + } + } + + return nil +} + // Attempt to fix redundant /ipfs/ namespace as long as resulting // 'intended' path is valid. This is in case gremlins were tickled // wrong way and user ended up at /ipfs/ipfs/{cid} or /ipfs/ipns/{id} // like in bafybeien3m7mdn6imm425vc2s22erzyhbvk5n3ofzgikkhmdkh5cuqbpbq :^)) -func fixupSuperfluousNamespace(w http.ResponseWriter, urlPath string, urlQuery string) bool { - if !(strings.HasPrefix(urlPath, "/ipfs/ipfs/") || strings.HasPrefix(urlPath, "/ipfs/ipns/")) { - return false // not a superfluous namespace +func handleSuperfluousNamespace(w http.ResponseWriter, r *http.Request, contentPath ipath.Path) (requestHandled bool) { + // If the path is valid, there's nothing to do + if pathErr := contentPath.IsValid(); pathErr == nil { + return false + } + + // If there's no superflous namespace, there's nothing to do + if !(strings.HasPrefix(r.URL.Path, "/ipfs/ipfs/") || strings.HasPrefix(r.URL.Path, "/ipfs/ipns/")) { + return false } - intendedPath := ipath.New(strings.TrimPrefix(urlPath, "/ipfs")) + + // Attempt to fix the superflous namespace + intendedPath := ipath.New(strings.TrimPrefix(r.URL.Path, "/ipfs")) if err := intendedPath.IsValid(); err != nil { - return false // not a valid path + webError(w, "invalid ipfs path", err, http.StatusBadRequest) + return true } intendedURL := intendedPath.String() - if urlQuery != "" { + if r.URL.RawQuery != "" { // we render HTML, so ensure query entries are properly escaped - q, _ := url.ParseQuery(urlQuery) + q, _ := url.ParseQuery(r.URL.RawQuery) intendedURL = intendedURL + "?" + q.Encode() } // return HTTP 400 (Bad Request) with HTML error page that: // - points at correct canonical path via header // - displays human-readable error // - redirects to intendedURL after a short delay + w.WriteHeader(http.StatusBadRequest) - return redirectTemplate.Execute(w, redirectTemplateData{ + if err := redirectTemplate.Execute(w, redirectTemplateData{ RedirectURL: intendedURL, SuggestedPath: intendedPath.String(), - ErrorMsg: fmt.Sprintf("invalid path: %q should be %q", urlPath, intendedPath.String()), - }) == nil + ErrorMsg: fmt.Sprintf("invalid path: %q should be %q", r.URL.Path, intendedPath.String()), + }); err != nil { + webError(w, "failed to redirect when fixing superfluous namespace", err, http.StatusBadRequest) + } + + return true +} + +func (i *gatewayHandler) handleGettingFirstBlock(r *http.Request, begin time.Time, contentPath ipath.Path, resolvedPath ipath.Resolved) *requestError { + // Update the global metric of the time it takes to read the final root block of the requested resource + // NOTE: for legacy reasons this happens before we go into content-type specific code paths + _, err := i.api.Block().Get(r.Context(), resolvedPath) + if err != nil { + return newRequestError("ipfs block get "+resolvedPath.Cid().String(), err, http.StatusInternalServerError) + } + ns := contentPath.Namespace() + timeToGetFirstContentBlock := time.Since(begin).Seconds() + i.unixfsGetMetric.WithLabelValues(ns).Observe(timeToGetFirstContentBlock) // deprecated, use firstContentBlockGetMetric instead + i.firstContentBlockGetMetric.WithLabelValues(ns).Observe(timeToGetFirstContentBlock) + return nil +} + +func (i *gatewayHandler) setCommonHeaders(w http.ResponseWriter, r *http.Request, contentPath ipath.Path) *requestError { + i.addUserHeaders(w) // ok, _now_ write user's headers. + w.Header().Set("X-Ipfs-Path", contentPath.String()) + + if rootCids, err := i.buildIpfsRootsHeader(contentPath.String(), r); err == nil { + w.Header().Set("X-Ipfs-Roots", rootCids) + } else { // this should never happen, as we resolved the contentPath already + return newRequestError("error while resolving X-Ipfs-Roots", err, http.StatusInternalServerError) + } + + return nil } From d59730f51eb537a5776091503887edb76bbc1bf6 Mon Sep 17 00:00:00 2001 From: Adin Schmahmann Date: Fri, 15 Apr 2022 14:32:00 -0400 Subject: [PATCH 356/414] Update Go version to 1.17 (#8815) * remove building the pre-bundled plugins as shared objects in makefile * chore: update go version to minimum of 1.17 --- .circleci/main.yml | 10 +- Dockerfile | 2 +- assets/dir-index-html/test/go.mod | 2 +- docs/examples/go-ipfs-as-a-library/go.mod | 201 +++++++++++++++++++++- go.mod | 147 +++++++++++++++- mk/golang.mk | 2 +- plugin/plugins/Rules.mk | 2 +- snap/snapcraft.yaml | 2 +- 8 files changed, 356 insertions(+), 12 deletions(-) diff --git a/.circleci/main.yml b/.circleci/main.yml index 060f4ddc4cc..ab7bc622b2a 100644 --- a/.circleci/main.yml +++ b/.circleci/main.yml @@ -36,7 +36,7 @@ default_environment: &default_environment executors: golang: docker: - - image: cimg/go:1.16.15 + - image: cimg/go:1.17.9 working_directory: ~/ipfs/go-ipfs environment: <<: *default_environment @@ -61,7 +61,7 @@ executors: E2E_IPFSD_TYPE: go dockerizer: docker: - - image: cimg/go:1.16.15 + - image: cimg/go:1.17.9 environment: IMAGE_NAME: ipfs/go-ipfs WIP_IMAGE_TAG: wip @@ -161,8 +161,8 @@ jobs: - run: sudo apt update - run: | mkdir ~/localgo && cd ~/localgo - wget https://golang.org/dl/go1.16.15.linux-amd64.tar.gz - tar xfz go1.16.15.linux-amd64.tar.gz + wget https://golang.org/dl/go1.17.9.linux-amd64.tar.gz + tar xfz go1.17.9.linux-amd64.tar.gz echo "export PATH=$(pwd)/go/bin:\$PATH" >> ~/.bashrc - run: go version - run: sudo apt install socat net-tools @@ -228,7 +228,7 @@ jobs: - *store_gomod interop: docker: - - image: cimg/go:1.16-node + - image: cimg/go:1.17.9-node parallelism: 4 resource_class: large steps: diff --git a/Dockerfile b/Dockerfile index dce35b54c71..4f7725f289a 100644 --- a/Dockerfile +++ b/Dockerfile @@ -1,5 +1,5 @@ # Note: when updating the go minor version here, also update the go-channel in snap/snapcraft.yml -FROM golang:1.16.15-buster +FROM golang:1.17.9-buster LABEL maintainer="Steven Allen " # Install deps diff --git a/assets/dir-index-html/test/go.mod b/assets/dir-index-html/test/go.mod index fde71afe910..c1cff1b746f 100644 --- a/assets/dir-index-html/test/go.mod +++ b/assets/dir-index-html/test/go.mod @@ -1,3 +1,3 @@ module github.com/ipfs/dir-index-html/test -go 1.16 +go 1.17 diff --git a/docs/examples/go-ipfs-as-a-library/go.mod b/docs/examples/go-ipfs-as-a-library/go.mod index 9ebae5489a5..c332efc8c8e 100644 --- a/docs/examples/go-ipfs-as-a-library/go.mod +++ b/docs/examples/go-ipfs-as-a-library/go.mod @@ -1,6 +1,6 @@ module github.com/ipfs/go-ipfs/examples/go-ipfs-as-a-library -go 1.16 +go 1.17 require ( github.com/ipfs/go-ipfs v0.11.0 @@ -10,3 +10,202 @@ require ( github.com/libp2p/go-libp2p-core v0.11.0 github.com/multiformats/go-multiaddr v0.4.1 ) + +require ( + bazil.org/fuse v0.0.0-20200117225306-7b5117fecadc // indirect + github.com/AndreasBriese/bbloom v0.0.0-20190825152654-46b345b51c96 // indirect + github.com/Stebalien/go-bitfield v0.0.1 // indirect + github.com/alecthomas/units v0.0.0-20210927113745-59d0afb8317a // indirect + github.com/alexbrainman/goissue34681 v0.0.0-20191006012335-3fc7a47baff5 // indirect + github.com/benbjohnson/clock v1.1.0 // indirect + github.com/beorn7/perks v1.0.1 // indirect + github.com/blang/semver/v4 v4.0.0 // indirect + github.com/btcsuite/btcd v0.22.0-beta // indirect + github.com/cenkalti/backoff v2.2.1+incompatible // indirect + github.com/ceramicnetwork/go-dag-jose v0.1.0 // indirect + github.com/cespare/xxhash v1.1.0 // indirect + github.com/cespare/xxhash/v2 v2.1.1 // indirect + github.com/cheekybits/genny v1.0.0 // indirect + github.com/crackcomm/go-gitignore v0.0.0-20170627025303-887ab5e44cc3 // indirect + github.com/cskr/pubsub v1.0.2 // indirect + github.com/davidlazar/go-crypto v0.0.0-20200604182044-b73af7476f6c // indirect + github.com/dgraph-io/badger v1.6.2 // indirect + github.com/dgraph-io/ristretto v0.0.2 // indirect + github.com/dustin/go-humanize v1.0.0 // indirect + github.com/facebookgo/atomicfile v0.0.0-20151019160806-2de1f203e7d5 // indirect + github.com/flynn/noise v1.0.0 // indirect + github.com/francoispqt/gojay v1.2.13 // indirect + github.com/fsnotify/fsnotify v1.5.1 // indirect + github.com/go-task/slim-sprig v0.0.0-20210107165309-348f09dbbbc0 // indirect + github.com/gogo/protobuf v1.3.2 // indirect + github.com/golang/protobuf v1.5.2 // indirect + github.com/golang/snappy v0.0.0-20180518054509-2e65f85255db // indirect + github.com/google/gopacket v1.1.19 // indirect + github.com/google/uuid v1.3.0 // indirect + github.com/gorilla/websocket v1.4.2 // indirect + github.com/hannahhoward/go-pubsub v0.0.0-20200423002714-8d62886cc36e // indirect + github.com/hashicorp/errwrap v1.0.0 // indirect + github.com/hashicorp/go-multierror v1.1.1 // indirect + github.com/hashicorp/golang-lru v0.5.4 // indirect + github.com/huin/goupnp v1.0.2 // indirect + github.com/ipfs/bbloom v0.0.4 // indirect + github.com/ipfs/go-bitfield v1.0.0 // indirect + github.com/ipfs/go-bitswap v0.5.1 // indirect + github.com/ipfs/go-block-format v0.0.3 // indirect + github.com/ipfs/go-blockservice v0.2.1 // indirect + github.com/ipfs/go-cid v0.1.0 // indirect + github.com/ipfs/go-cidutil v0.0.2 // indirect + github.com/ipfs/go-datastore v0.5.1 // indirect + github.com/ipfs/go-ds-badger v0.3.0 // indirect + github.com/ipfs/go-ds-flatfs v0.5.1 // indirect + github.com/ipfs/go-ds-leveldb v0.5.0 // indirect + github.com/ipfs/go-ds-measure v0.2.0 // indirect + github.com/ipfs/go-fetcher v1.6.1 // indirect + github.com/ipfs/go-filestore v0.1.0 // indirect + github.com/ipfs/go-fs-lock v0.0.7 // indirect + github.com/ipfs/go-graphsync v0.11.0 // indirect + github.com/ipfs/go-ipfs-blockstore v0.2.1 // indirect + github.com/ipfs/go-ipfs-chunker v0.0.5 // indirect + github.com/ipfs/go-ipfs-delay v0.0.1 // indirect + github.com/ipfs/go-ipfs-ds-help v0.1.1 // indirect + github.com/ipfs/go-ipfs-exchange-interface v0.1.0 // indirect + github.com/ipfs/go-ipfs-exchange-offline v0.1.1 // indirect + github.com/ipfs/go-ipfs-keystore v0.0.2 // indirect + github.com/ipfs/go-ipfs-pinner v0.2.1 // indirect + github.com/ipfs/go-ipfs-posinfo v0.0.1 // indirect + github.com/ipfs/go-ipfs-pq v0.0.2 // indirect + github.com/ipfs/go-ipfs-provider v0.7.1 // indirect + github.com/ipfs/go-ipfs-routing v0.2.1 // indirect + github.com/ipfs/go-ipfs-util v0.0.2 // indirect + github.com/ipfs/go-ipld-cbor v0.0.5 // indirect + github.com/ipfs/go-ipld-format v0.2.0 // indirect + github.com/ipfs/go-ipld-git v0.1.1 // indirect + github.com/ipfs/go-ipld-legacy v0.1.0 // indirect + github.com/ipfs/go-ipns v0.1.2 // indirect + github.com/ipfs/go-log v1.0.5 // indirect + github.com/ipfs/go-log/v2 v2.3.0 // indirect + github.com/ipfs/go-merkledag v0.5.1 // indirect + github.com/ipfs/go-metrics-interface v0.0.1 // indirect + github.com/ipfs/go-mfs v0.2.1 // indirect + github.com/ipfs/go-namesys v0.4.0 // indirect + github.com/ipfs/go-path v0.2.1 // indirect + github.com/ipfs/go-peertaskqueue v0.7.0 // indirect + github.com/ipfs/go-unixfs v0.3.1 // indirect + github.com/ipfs/go-unixfsnode v1.1.3 // indirect + github.com/ipfs/go-verifcid v0.0.1 // indirect + github.com/ipld/go-codec-dagpb v1.3.0 // indirect + github.com/ipld/go-ipld-prime v0.14.2 // indirect + github.com/jackpal/go-nat-pmp v1.0.2 // indirect + github.com/jbenet/go-temp-err-catcher v0.1.0 // indirect + github.com/jbenet/goprocess v0.1.4 // indirect + github.com/klauspost/compress v1.11.7 // indirect + github.com/klauspost/cpuid/v2 v2.0.9 // indirect + github.com/koron/go-ssdp v0.0.2 // indirect + github.com/libp2p/go-addr-util v0.1.0 // indirect + github.com/libp2p/go-buffer-pool v0.0.2 // indirect + github.com/libp2p/go-cidranger v1.1.0 // indirect + github.com/libp2p/go-conn-security-multistream v0.3.0 // indirect + github.com/libp2p/go-doh-resolver v0.3.1 // indirect + github.com/libp2p/go-eventbus v0.2.1 // indirect + github.com/libp2p/go-flow-metrics v0.0.3 // indirect + github.com/libp2p/go-libp2p v0.16.0 // indirect + github.com/libp2p/go-libp2p-asn-util v0.1.0 // indirect + github.com/libp2p/go-libp2p-autonat v0.6.0 // indirect + github.com/libp2p/go-libp2p-blankhost v0.2.0 // indirect + github.com/libp2p/go-libp2p-connmgr v0.2.4 // indirect + github.com/libp2p/go-libp2p-discovery v0.6.0 // indirect + github.com/libp2p/go-libp2p-kad-dht v0.15.0 // indirect + github.com/libp2p/go-libp2p-kbucket v0.4.7 // indirect + github.com/libp2p/go-libp2p-loggables v0.1.0 // indirect + github.com/libp2p/go-libp2p-mplex v0.4.1 // indirect + github.com/libp2p/go-libp2p-nat v0.1.0 // indirect + github.com/libp2p/go-libp2p-noise v0.3.0 // indirect + github.com/libp2p/go-libp2p-peerstore v0.4.0 // indirect + github.com/libp2p/go-libp2p-pnet v0.2.0 // indirect + github.com/libp2p/go-libp2p-pubsub v0.6.0 // indirect + github.com/libp2p/go-libp2p-pubsub-router v0.5.0 // indirect + github.com/libp2p/go-libp2p-quic-transport v0.15.0 // indirect + github.com/libp2p/go-libp2p-record v0.1.3 // indirect + github.com/libp2p/go-libp2p-routing-helpers v0.2.3 // indirect + github.com/libp2p/go-libp2p-swarm v0.8.0 // indirect + github.com/libp2p/go-libp2p-tls v0.3.1 // indirect + github.com/libp2p/go-libp2p-transport-upgrader v0.5.0 // indirect + github.com/libp2p/go-libp2p-xor v0.0.0-20210714161855-5c005aca55db // indirect + github.com/libp2p/go-libp2p-yamux v0.6.0 // indirect + github.com/libp2p/go-maddr-filter v0.1.0 // indirect + github.com/libp2p/go-mplex v0.3.0 // indirect + github.com/libp2p/go-msgio v0.1.0 // indirect + github.com/libp2p/go-nat v0.1.0 // indirect + github.com/libp2p/go-netroute v0.1.6 // indirect + github.com/libp2p/go-openssl v0.0.7 // indirect + github.com/libp2p/go-reuseport v0.1.0 // indirect + github.com/libp2p/go-reuseport-transport v0.1.0 // indirect + github.com/libp2p/go-sockaddr v0.1.1 // indirect + github.com/libp2p/go-stream-muxer-multistream v0.3.0 // indirect + github.com/libp2p/go-tcp-transport v0.4.0 // indirect + github.com/libp2p/go-ws-transport v0.5.0 // indirect + github.com/libp2p/go-yamux/v2 v2.3.0 // indirect + github.com/libp2p/zeroconf/v2 v2.1.1 // indirect + github.com/lucas-clemente/quic-go v0.24.0 // indirect + github.com/marten-seemann/qtls-go1-16 v0.1.4 // indirect + github.com/marten-seemann/qtls-go1-17 v0.1.0 // indirect + github.com/marten-seemann/tcp v0.0.0-20210406111302-dfbc87cc63fd // indirect + github.com/mattn/go-isatty v0.0.13 // indirect + github.com/matttproud/golang_protobuf_extensions v1.0.1 // indirect + github.com/miekg/dns v1.1.43 // indirect + github.com/mikioh/tcpinfo v0.0.0-20190314235526-30a79bb1804b // indirect + github.com/mikioh/tcpopt v0.0.0-20190314235656-172688c1accc // indirect + github.com/minio/blake2b-simd v0.0.0-20160723061019-3f5f724cb5b1 // indirect + github.com/minio/sha256-simd v1.0.0 // indirect + github.com/mitchellh/go-homedir v1.1.0 // indirect + github.com/mr-tron/base58 v1.2.0 // indirect + github.com/multiformats/go-base32 v0.0.3 // indirect + github.com/multiformats/go-base36 v0.1.0 // indirect + github.com/multiformats/go-multiaddr-dns v0.3.1 // indirect + github.com/multiformats/go-multiaddr-fmt v0.1.0 // indirect + github.com/multiformats/go-multibase v0.0.3 // indirect + github.com/multiformats/go-multicodec v0.3.0 // indirect + github.com/multiformats/go-multihash v0.1.0 // indirect + github.com/multiformats/go-multistream v0.2.2 // indirect + github.com/multiformats/go-varint v0.0.6 // indirect + github.com/nxadm/tail v1.4.8 // indirect + github.com/onsi/ginkgo v1.16.4 // indirect + github.com/opentracing/opentracing-go v1.2.0 // indirect + github.com/pkg/errors v0.9.1 // indirect + github.com/polydawn/refmt v0.0.0-20201211092308-30ac6d18308e // indirect + github.com/prometheus/client_golang v1.11.0 // indirect + github.com/prometheus/client_model v0.2.0 // indirect + github.com/prometheus/common v0.30.0 // indirect + github.com/prometheus/procfs v0.7.3 // indirect + github.com/spacemonkeygo/spacelog v0.0.0-20180420211403-2296661a0572 // indirect + github.com/spaolacci/murmur3 v1.1.0 // indirect + github.com/syndtr/goleveldb v1.0.0 // indirect + github.com/whyrusleeping/base32 v0.0.0-20170828182744-c30ac30633cc // indirect + github.com/whyrusleeping/cbor-gen v0.0.0-20210219115102-f37d292932f2 // indirect + github.com/whyrusleeping/chunker v0.0.0-20181014151217-fe64bd25879f // indirect + github.com/whyrusleeping/go-keyspace v0.0.0-20160322163242-5b898ac5add1 // indirect + github.com/whyrusleeping/mdns v0.0.0-20190826153040-b9b60ed33aa9 // indirect + github.com/whyrusleeping/multiaddr-filter v0.0.0-20160516205228-e903e4adabd7 // indirect + github.com/whyrusleeping/timecache v0.0.0-20160911033111-cfcb2f1abfee // indirect + go.opencensus.io v0.23.0 // indirect + go.opentelemetry.io/otel v0.20.0 // indirect + go.opentelemetry.io/otel/metric v0.20.0 // indirect + go.opentelemetry.io/otel/trace v0.20.0 // indirect + go.uber.org/atomic v1.9.0 // indirect + go.uber.org/dig v1.12.0 // indirect + go.uber.org/fx v1.15.0 // indirect + go.uber.org/multierr v1.7.0 // indirect + go.uber.org/zap v1.19.1 // indirect + go4.org v0.0.0-20200411211856-f5505b9728dd // indirect + golang.org/x/crypto v0.0.0-20210921155107-089bfa567519 // indirect + golang.org/x/mod v0.4.2 // indirect + golang.org/x/net v0.0.0-20210813160813-60bc85c4be6d // indirect + golang.org/x/sync v0.0.0-20210220032951-036812b2e83c // indirect + golang.org/x/sys v0.0.0-20211025112917-711f33c9992c // indirect + golang.org/x/tools v0.1.5 // indirect + golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1 // indirect + google.golang.org/protobuf v1.27.1 // indirect + gopkg.in/square/go-jose.v2 v2.5.1 // indirect + gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7 // indirect + lukechampine.com/blake3 v1.1.6 // indirect +) diff --git a/go.mod b/go.mod index 1756df7f291..86c903c7cb7 100644 --- a/go.mod +++ b/go.mod @@ -123,4 +123,149 @@ require ( golang.org/x/sys v0.0.0-20211025112917-711f33c9992c ) -go 1.16 +require ( + github.com/AndreasBriese/bbloom v0.0.0-20190825152654-46b345b51c96 // indirect + github.com/Kubuxu/go-os-helper v0.0.1 // indirect + github.com/Stebalien/go-bitfield v0.0.1 // indirect + github.com/alecthomas/units v0.0.0-20210927113745-59d0afb8317a // indirect + github.com/alexbrainman/goissue34681 v0.0.0-20191006012335-3fc7a47baff5 // indirect + github.com/benbjohnson/clock v1.3.0 // indirect + github.com/beorn7/perks v1.0.1 // indirect + github.com/btcsuite/btcd v0.22.0-beta // indirect + github.com/cenkalti/backoff v2.2.1+incompatible // indirect + github.com/cenkalti/backoff/v4 v4.1.1 // indirect + github.com/cespare/xxhash/v2 v2.1.1 // indirect + github.com/cheekybits/genny v1.0.0 // indirect + github.com/containerd/cgroups v0.0.0-20201119153540-4cbc285b3327 // indirect + github.com/crackcomm/go-gitignore v0.0.0-20170627025303-887ab5e44cc3 // indirect + github.com/cskr/pubsub v1.0.2 // indirect + github.com/davecgh/go-spew v1.1.1 // indirect + github.com/davidlazar/go-crypto v0.0.0-20200604182044-b73af7476f6c // indirect + github.com/dgraph-io/badger v1.6.2 // indirect + github.com/dgraph-io/ristretto v0.0.2 // indirect + github.com/docker/go-units v0.4.0 // indirect + github.com/elastic/gosigar v0.12.0 // indirect + github.com/felixge/httpsnoop v1.0.2 // indirect + github.com/flynn/noise v1.0.0 // indirect + github.com/francoispqt/gojay v1.2.13 // indirect + github.com/go-kit/log v0.1.0 // indirect + github.com/go-logfmt/logfmt v0.5.0 // indirect + github.com/go-task/slim-sprig v0.0.0-20210107165309-348f09dbbbc0 // indirect + github.com/godbus/dbus/v5 v5.0.4 // indirect + github.com/gogo/protobuf v1.3.2 // indirect + github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da // indirect + github.com/golang/protobuf v1.5.2 // indirect + github.com/golang/snappy v0.0.0-20180518054509-2e65f85255db // indirect + github.com/google/gopacket v1.1.19 // indirect + github.com/google/uuid v1.3.0 // indirect + github.com/gorilla/websocket v1.4.2 // indirect + github.com/grpc-ecosystem/grpc-gateway v1.16.0 // indirect + github.com/hannahhoward/go-pubsub v0.0.0-20200423002714-8d62886cc36e // indirect + github.com/hashicorp/errwrap v1.0.0 // indirect + github.com/hashicorp/golang-lru v0.5.4 // indirect + github.com/huin/goupnp v1.0.2 // indirect + github.com/ipfs/bbloom v0.0.4 // indirect + github.com/ipfs/go-bitfield v1.0.0 // indirect + github.com/ipfs/go-ipfs-delay v0.0.1 // indirect + github.com/ipfs/go-ipfs-ds-help v1.1.0 // indirect + github.com/ipfs/go-ipfs-pq v0.0.2 // indirect + github.com/ipfs/go-log/v2 v2.5.0 // indirect + github.com/ipfs/go-peertaskqueue v0.7.0 // indirect + github.com/jackpal/go-nat-pmp v1.0.2 // indirect + github.com/klauspost/compress v1.13.6 // indirect + github.com/klauspost/cpuid/v2 v2.0.9 // indirect + github.com/koron/go-ssdp v0.0.2 // indirect + github.com/libp2p/go-buffer-pool v0.0.2 // indirect + github.com/libp2p/go-cidranger v1.1.0 // indirect + github.com/libp2p/go-conn-security-multistream v0.3.0 // indirect + github.com/libp2p/go-eventbus v0.2.1 // indirect + github.com/libp2p/go-flow-metrics v0.0.3 // indirect + github.com/libp2p/go-libp2p-asn-util v0.1.0 // indirect + github.com/libp2p/go-libp2p-blankhost v0.3.0 // indirect + github.com/libp2p/go-libp2p-gostream v0.3.0 // indirect + github.com/libp2p/go-libp2p-nat v0.1.0 // indirect + github.com/libp2p/go-libp2p-pnet v0.2.0 // indirect + github.com/libp2p/go-libp2p-transport-upgrader v0.7.1 // indirect + github.com/libp2p/go-libp2p-xor v0.0.0-20210714161855-5c005aca55db // indirect + github.com/libp2p/go-mplex v0.6.0 // indirect + github.com/libp2p/go-msgio v0.1.0 // indirect + github.com/libp2p/go-nat v0.1.0 // indirect + github.com/libp2p/go-netroute v0.2.0 // indirect + github.com/libp2p/go-openssl v0.0.7 // indirect + github.com/libp2p/go-reuseport v0.1.0 // indirect + github.com/libp2p/go-reuseport-transport v0.1.0 // indirect + github.com/libp2p/go-stream-muxer-multistream v0.4.0 // indirect + github.com/libp2p/go-yamux/v3 v3.0.2 // indirect + github.com/libp2p/zeroconf/v2 v2.1.1 // indirect + github.com/lucas-clemente/quic-go v0.25.0 // indirect + github.com/marten-seemann/qtls-go1-16 v0.1.4 // indirect + github.com/marten-seemann/qtls-go1-17 v0.1.0 // indirect + github.com/marten-seemann/qtls-go1-18 v0.1.0-beta.1 // indirect + github.com/marten-seemann/tcp v0.0.0-20210406111302-dfbc87cc63fd // indirect + github.com/mattn/go-colorable v0.1.4 // indirect + github.com/mattn/go-isatty v0.0.14 // indirect + github.com/mattn/go-runewidth v0.0.4 // indirect + github.com/matttproud/golang_protobuf_extensions v1.0.1 // indirect + github.com/mgutz/ansi v0.0.0-20170206155736-9520e82c474b // indirect + github.com/mikioh/tcpinfo v0.0.0-20190314235526-30a79bb1804b // indirect + github.com/mikioh/tcpopt v0.0.0-20190314235656-172688c1accc // indirect + github.com/minio/blake2b-simd v0.0.0-20160723061019-3f5f724cb5b1 // indirect + github.com/minio/sha256-simd v1.0.0 // indirect + github.com/mr-tron/base58 v1.2.0 // indirect + github.com/multiformats/go-base32 v0.0.3 // indirect + github.com/multiformats/go-base36 v0.1.0 // indirect + github.com/multiformats/go-multiaddr-fmt v0.1.0 // indirect + github.com/multiformats/go-multistream v0.2.2 // indirect + github.com/multiformats/go-varint v0.0.6 // indirect + github.com/nxadm/tail v1.4.8 // indirect + github.com/onsi/ginkgo v1.16.4 // indirect + github.com/opencontainers/runtime-spec v1.0.2 // indirect + github.com/pbnjay/memory v0.0.0-20210728143218-7b4eea64cf58 // indirect + github.com/pmezard/go-difflib v1.0.0 // indirect + github.com/polydawn/refmt v0.0.0-20201211092308-30ac6d18308e // indirect + github.com/prometheus/client_model v0.2.0 // indirect + github.com/prometheus/common v0.30.0 // indirect + github.com/prometheus/procfs v0.7.3 // indirect + github.com/prometheus/statsd_exporter v0.21.0 // indirect + github.com/raulk/clock v1.1.0 // indirect + github.com/raulk/go-watchdog v1.2.0 // indirect + github.com/rs/cors v1.7.0 // indirect + github.com/spacemonkeygo/spacelog v0.0.0-20180420211403-2296661a0572 // indirect + github.com/spaolacci/murmur3 v1.1.0 // indirect + github.com/texttheater/golang-levenshtein v0.0.0-20180516184445-d188e65d659e // indirect + github.com/tidwall/gjson v1.14.0 // indirect + github.com/tidwall/match v1.1.1 // indirect + github.com/tidwall/pretty v1.2.0 // indirect + github.com/whyrusleeping/base32 v0.0.0-20170828182744-c30ac30633cc // indirect + github.com/whyrusleeping/cbor-gen v0.0.0-20210219115102-f37d292932f2 // indirect + github.com/whyrusleeping/chunker v0.0.0-20181014151217-fe64bd25879f // indirect + github.com/whyrusleeping/go-keyspace v0.0.0-20160322163242-5b898ac5add1 // indirect + github.com/whyrusleeping/mdns v0.0.0-20190826153040-b9b60ed33aa9 // indirect + github.com/whyrusleeping/timecache v0.0.0-20160911033111-cfcb2f1abfee // indirect + go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.2.0 // indirect + go.opentelemetry.io/otel/internal/metric v0.25.0 // indirect + go.opentelemetry.io/otel/metric v0.25.0 // indirect + go.opentelemetry.io/proto/otlp v0.10.0 // indirect + go.uber.org/atomic v1.9.0 // indirect + go.uber.org/multierr v1.7.0 // indirect + go4.org v0.0.0-20200411211856-f5505b9728dd // indirect + golang.org/x/exp v0.0.0-20210615023648-acb5c1269671 // indirect + golang.org/x/mod v0.4.2 // indirect + golang.org/x/net v0.0.0-20210813160813-60bc85c4be6d // indirect + golang.org/x/oauth2 v0.0.0-20210514164344-f6687ab2804c // indirect + golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1 // indirect + golang.org/x/text v0.3.7 // indirect + golang.org/x/tools v0.1.5 // indirect + golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1 // indirect + google.golang.org/appengine v1.6.6 // indirect + google.golang.org/genproto v0.0.0-20200825200019-8632dd797987 // indirect + google.golang.org/grpc v1.42.0 // indirect + google.golang.org/protobuf v1.27.1 // indirect + gopkg.in/square/go-jose.v2 v2.5.1 // indirect + gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7 // indirect + gopkg.in/yaml.v2 v2.4.0 // indirect + gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b // indirect + lukechampine.com/blake3 v1.1.6 // indirect +) + +go 1.17 diff --git a/mk/golang.mk b/mk/golang.mk index 7ede944637f..93753e5c1b3 100644 --- a/mk/golang.mk +++ b/mk/golang.mk @@ -1,5 +1,5 @@ # golang utilities -GO_MIN_VERSION = 1.15.2 +GO_MIN_VERSION = 1.17 export GO111MODULE=on diff --git a/plugin/plugins/Rules.mk b/plugin/plugins/Rules.mk index 4a4ed816140..05b11e340ce 100644 --- a/plugin/plugins/Rules.mk +++ b/plugin/plugins/Rules.mk @@ -1,6 +1,6 @@ include mk/header.mk -$(d)_plugins:=$(d)/git $(d)/dagjose $(d)/badgerds $(d)/flatfs $(d)/levelds $(d)/peerlog +$(d)_plugins:= $(d)_plugins_so:=$(addsuffix .so,$($(d)_plugins)) $(d)_plugins_main:=$(addsuffix /main/main.go,$($(d)_plugins)) diff --git a/snap/snapcraft.yaml b/snap/snapcraft.yaml index 3ebe0440969..5852fa8846b 100644 --- a/snap/snapcraft.yaml +++ b/snap/snapcraft.yaml @@ -29,7 +29,7 @@ parts: source-tag: master plugin: go # keep me up to date with the go version that go-ipfs expects to be built with. - go-channel: 1.16/stable + go-channel: 1.17/stable go-importpath: github.com/ipfs/go-ipfs build-packages: - build-essential From 67fdb6efcdd1d4c0c0ee6fef7190b92c13184dbd Mon Sep 17 00:00:00 2001 From: Marcin Rataj Date: Tue, 19 Apr 2022 20:57:11 +0200 Subject: [PATCH 357/414] feat(gw): improved If-None-Match support (#8891) Improves the way we handle If-None-Match header: - Support for more than one Etag passed in If-None-Match - Match both strong and weak Etags to maximize caching across various HTTP clients and libraries (some send weak Etags by default) - Support for wildcard '*' - Tests for If-None-Match behavior --- core/corehttp/gateway_handler.go | 83 +++++++++++++++++++-- core/corehttp/gateway_handler_unixfs_dir.go | 12 +-- core/corehttp/gateway_test.go | 25 +++++++ test/sharness/t0116-gateway-cache.sh | 49 ++++++++++++ 4 files changed, 155 insertions(+), 14 deletions(-) diff --git a/core/corehttp/gateway_handler.go b/core/corehttp/gateway_handler.go index 52d86257b6d..f32fac54ecd 100644 --- a/core/corehttp/gateway_handler.go +++ b/core/corehttp/gateway_handler.go @@ -7,6 +7,7 @@ import ( "io" "mime" "net/http" + "net/textproto" "net/url" "os" gopath "path" @@ -390,11 +391,18 @@ func (i *gatewayHandler) getOrHeadHandler(w http.ResponseWriter, r *http.Request trace.SpanFromContext(r.Context()).SetAttributes(attribute.String("ResponseFormat", responseFormat)) trace.SpanFromContext(r.Context()).SetAttributes(attribute.String("ResolvedPath", resolvedPath.String())) - // Finish early if client already has matching Etag - ifNoneMatch := r.Header.Get("If-None-Match") - if ifNoneMatch == getEtag(r, resolvedPath.Cid()) || ifNoneMatch == getDirListingEtag(resolvedPath.Cid()) { - w.WriteHeader(http.StatusNotModified) - return + // Detect when If-None-Match HTTP header allows returning HTTP 304 Not Modified + if inm := r.Header.Get("If-None-Match"); inm != "" { + pathCid := resolvedPath.Cid() + // need to check against both File and Dir Etag variants + // because this inexpensive check happens before we do any I/O + cidEtag := getEtag(r, pathCid) + dirEtag := getDirListingEtag(pathCid) + if etagMatch(inm, cidEtag, dirEtag) { + // Finish early if client already has a matching Etag + w.WriteHeader(http.StatusNotModified) + return + } } if err := i.handleGettingFirstBlock(r, begin, contentPath, resolvedPath); err != nil { @@ -790,6 +798,71 @@ func getFilename(contentPath ipath.Path) string { return gopath.Base(s) } +// etagMatch evaluates if we can respond with HTTP 304 Not Modified +// It supports multiple weak and strong etags passed in If-None-Matc stringh +// including the wildcard one. +func etagMatch(ifNoneMatchHeader string, cidEtag string, dirEtag string) bool { + buf := ifNoneMatchHeader + for { + buf = textproto.TrimString(buf) + if len(buf) == 0 { + break + } + if buf[0] == ',' { + buf = buf[1:] + continue + } + // If-None-Match: * should match against any etag + if buf[0] == '*' { + return true + } + etag, remain := scanETag(buf) + if etag == "" { + break + } + // Check for match both strong and weak etags + if etagWeakMatch(etag, cidEtag) || etagWeakMatch(etag, dirEtag) { + return true + } + buf = remain + } + return false +} + +// scanETag determines if a syntactically valid ETag is present at s. If so, +// the ETag and remaining text after consuming ETag is returned. Otherwise, +// it returns "", "". +// (This is the same logic as one executed inside of http.ServeContent) +func scanETag(s string) (etag string, remain string) { + s = textproto.TrimString(s) + start := 0 + if strings.HasPrefix(s, "W/") { + start = 2 + } + if len(s[start:]) < 2 || s[start] != '"' { + return "", "" + } + // ETag is either W/"text" or "text". + // See RFC 7232 2.3. + for i := start + 1; i < len(s); i++ { + c := s[i] + switch { + // Character values allowed in ETags. + case c == 0x21 || c >= 0x23 && c <= 0x7E || c >= 0x80: + case c == '"': + return s[:i+1], s[i+1:] + default: + return "", "" + } + } + return "", "" +} + +// etagWeakMatch reports whether a and b match using weak ETag comparison. +func etagWeakMatch(a, b string) bool { + return strings.TrimPrefix(a, "W/") == strings.TrimPrefix(b, "W/") +} + // generate Etag value based on HTTP request and CID func getEtag(r *http.Request, cid cid.Cid) string { prefix := `"` diff --git a/core/corehttp/gateway_handler_unixfs_dir.go b/core/corehttp/gateway_handler_unixfs_dir.go index f462e52f8f6..d2cce586801 100644 --- a/core/corehttp/gateway_handler_unixfs_dir.go +++ b/core/corehttp/gateway_handler_unixfs_dir.go @@ -93,15 +93,9 @@ func (i *gatewayHandler) serveDirectory(ctx context.Context, w http.ResponseWrit // type instead of relying on autodetection (which may fail). w.Header().Set("Content-Type", "text/html") - // Generated dir index requires custom Etag (it may change between go-ipfs versions) - if assets.AssetHash != "" { - dirEtag := getDirListingEtag(resolvedPath.Cid()) - w.Header().Set("Etag", dirEtag) - if r.Header.Get("If-None-Match") == dirEtag { - w.WriteHeader(http.StatusNotModified) - return - } - } + // Generated dir index requires custom Etag (output may change between go-ipfs versions) + dirEtag := getDirListingEtag(resolvedPath.Cid()) + w.Header().Set("Etag", dirEtag) if r.Method == http.MethodHead { logger.Debug("return as request's HTTP method is HEAD") diff --git a/core/corehttp/gateway_test.go b/core/corehttp/gateway_test.go index 2cba931ddc4..303e4a1ac11 100644 --- a/core/corehttp/gateway_test.go +++ b/core/corehttp/gateway_test.go @@ -656,3 +656,28 @@ func TestVersion(t *testing.T) { t.Fatalf("response doesn't contain protocol version:\n%s", s) } } + +func TestEtagMatch(t *testing.T) { + for _, test := range []struct { + header string // value in If-None-Match HTTP header + cidEtag string + dirEtag string + expected bool // expected result of etagMatch(header, cidEtag, dirEtag) + }{ + {"", `"etag"`, "", false}, // no If-None-Match + {"", "", `"etag"`, false}, // no If-None-Match + {`"etag"`, `"etag"`, "", true}, // file etag match + {`W/"etag"`, `"etag"`, "", true}, // file etag match + {`"foo", W/"bar", W/"etag"`, `"etag"`, "", true}, // file etag match (array) + {`"foo",W/"bar",W/"etag"`, `"etag"`, "", true}, // file etag match (compact array) + {`"etag"`, "", `W/"etag"`, true}, // dir etag match + {`"etag"`, "", `W/"etag"`, true}, // dir etag match + {`W/"etag"`, "", `W/"etag"`, true}, // dir etag match + {`*`, `"etag"`, "", true}, // wildcard etag match + } { + result := etagMatch(test.header, test.cidEtag, test.dirEtag) + if result != test.expected { + t.Fatalf("unexpected result of etagMatch(%q, %q, %q), got %t, expected %t", test.header, test.cidEtag, test.dirEtag, result, test.expected) + } + } +} diff --git a/test/sharness/t0116-gateway-cache.sh b/test/sharness/t0116-gateway-cache.sh index 3e9e2af48b8..e5471088e2d 100755 --- a/test/sharness/t0116-gateway-cache.sh +++ b/test/sharness/t0116-gateway-cache.sh @@ -145,6 +145,55 @@ test_expect_success "Prepare IPNS unixfs content path for testing" ' grep "< Etag: \"${FILE_CID}\"" curl_ipns_file_output ' +# If-None-Match (return 304 Not Modified when client sends matching Etag they already have) + + test_expect_success "GET for /ipfs/ file with matching Etag in If-None-Match returns 304 Not Modified" ' + curl -svX GET -H "If-None-Match: \"$FILE_CID\"" "http://127.0.0.1:$GWAY_PORT/ipfs/$ROOT1_CID/root2/root3/root4/index.html" >/dev/null 2>curl_output && + test_should_contain "304 Not Modified" curl_output + ' + + test_expect_success "GET for /ipfs/ dir with index.html file with matching Etag in If-None-Match returns 304 Not Modified" ' + curl -svX GET -H "If-None-Match: \"$ROOT4_CID\"" "http://127.0.0.1:$GWAY_PORT/ipfs/$ROOT1_CID/root2/root3/root4/" >/dev/null 2>curl_output && + test_should_contain "304 Not Modified" curl_output + ' + + test_expect_success "GET for /ipfs/ file with matching third Etag in If-None-Match returns 304 Not Modified" ' + curl -svX GET -H "If-None-Match: \"fakeEtag1\", \"fakeEtag2\", \"$FILE_CID\"" "http://127.0.0.1:$GWAY_PORT/ipfs/$ROOT1_CID/root2/root3/root4/index.html" >/dev/null 2>curl_output && + test_should_contain "304 Not Modified" curl_output + ' + + test_expect_success "GET for /ipfs/ file with matching weak Etag in If-None-Match returns 304 Not Modified" ' + curl -svX GET -H "If-None-Match: W/\"$FILE_CID\"" "http://127.0.0.1:$GWAY_PORT/ipfs/$ROOT1_CID/root2/root3/root4/index.html" >/dev/null 2>curl_output && + test_should_contain "304 Not Modified" curl_output + ' + + test_expect_success "GET for /ipfs/ file with wildcard Etag in If-None-Match returns 304 Not Modified" ' + curl -svX GET -H "If-None-Match: *" "http://127.0.0.1:$GWAY_PORT/ipfs/$ROOT1_CID/root2/root3/root4/index.html" >/dev/null 2>curl_output && + test_should_contain "304 Not Modified" curl_output + ' + + test_expect_success "GET for /ipns/ file with matching Etag in If-None-Match returns 304 Not Modified" ' + curl -svX GET -H "If-None-Match: \"$FILE_CID\"" "http://127.0.0.1:$GWAY_PORT/ipns/$TEST_IPNS_ID/root2/root3/root4/index.html" >/dev/null 2>curl_output && + test_should_contain "304 Not Modified" curl_output + ' + + test_expect_success "GET for /ipfs/ dir listing with matching weak Etag in If-None-Match returns 304 Not Modified" ' + curl -svX GET -H "If-None-Match: W/\"$ROOT3_CID\"" "http://127.0.0.1:$GWAY_PORT/ipfs/$ROOT1_CID/root2/root3/" >/dev/null 2>curl_output && + test_should_contain "304 Not Modified" curl_output + ' + + # DirIndex etag is based on xxhash(./assets/dir-index-html), so we need to fetch it dynamically + test_expect_success "GET for /ipfs/ dir listing with matching strong Etag in If-None-Match returns 304 Not Modified" ' + curl -Is "http://127.0.0.1:$GWAY_PORT/ipfs/$ROOT1_CID/root2/root3/"| grep -i Etag | cut -f2- -d: | tr -d "[:space:]\"" > dir_index_etag && + curl -svX GET -H "If-None-Match: \"$(/dev/null 2>curl_output && + test_should_contain "304 Not Modified" curl_output + ' + test_expect_success "GET for /ipfs/ dir listing with matching weak Etag in If-None-Match returns 304 Not Modified" ' + curl -Is "http://127.0.0.1:$GWAY_PORT/ipfs/$ROOT1_CID/root2/root3/"| grep -i Etag | cut -f2- -d: | tr -d "[:space:]\"" > dir_index_etag && + curl -svX GET -H "If-None-Match: W/\"$(/dev/null 2>curl_output && + test_should_contain "304 Not Modified" curl_output + ' + test_kill_ipfs_daemon test_done From 7b5fe809f0a88ab738f537e942313231cc771f7d Mon Sep 17 00:00:00 2001 From: Lucas Molas Date: Thu, 21 Apr 2022 13:19:40 -0300 Subject: [PATCH 358/414] fix(cmds): CIDv1 and correct multicodecs in 'block put' and 'cid codecs' (#8568) BREAKING CHANGES: - see https://github.com/ipfs/go-ipfs/pull/8568#issue-1063653194 Co-authored-by: Marcin Rataj --- CHANGELOG.md | 17 ++++++++++ core/commands/block.go | 62 ++++++++++++++++++++-------------- core/commands/cid.go | 60 +++++++++++++++++++++++++------- core/coreapi/block.go | 4 +-- go.mod | 4 +-- go.sum | 8 ++--- test/sharness/t0050-block.sh | 58 ++++++++++++++++++++++++++----- test/sharness/t0110-gateway.sh | 2 +- test/sharness/t0290-cid.sh | 47 +++++++++++++++++++++++--- 9 files changed, 204 insertions(+), 58 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 35ccaa6b351..b12fce5723a 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,22 @@ # go-ipfs changelog +## v0.13 (DRAFT) + +### BREAKING CHANGES + +- `ipfs block put` command produces CIDv1 with `raw` codec by default now + - `ipfs block put --cid-codec` makes `block put` return CID with alternative codec + - this impacts only the returned CID, it does not trigger any validation or data transformation + - codec names are validated against tables from https://github.com/multiformats/go-multicodec + - `ipfs block put --format` is deprecated. It used incorrect codec names and should be avoided for new deployments. Use it only if you need the old, invalid behavior, namely: + - `ipfs block put --format=v0` will produce CIDv0 (implicit dag-pb) + - `ipfs block put --format=cbor` will produce CIDv1 with dag-cbor (!) + - `ipfs block put --format=protobuf` will produce CIDv1 with dag-pb (!) +- `ipfs cid codecs` command + - it now lists codecs from https://github.com/multiformats/go-multicodec + - `ipfs cid codecs --supported` can be passed to only show codecs supported in various go-ipfs commands + + ## v0.12.2 and v0.11.1 2022-04-08 This patch release fixes a security issue wherein traversing some malformed DAGs can cause the node to panic. diff --git a/core/commands/block.go b/core/commands/block.go index 945dbf64f80..92e5f9cb3c9 100644 --- a/core/commands/block.go +++ b/core/commands/block.go @@ -31,8 +31,8 @@ var BlockCmd = &cmds.Command{ Tagline: "Interact with raw IPFS blocks.", ShortDescription: ` 'ipfs block' is a plumbing command used to manipulate raw IPFS blocks. -Reads from stdin or writes to stdout, and is a base58 encoded -multihash. +Reads from stdin or writes to stdout. A block is identified by a Multihash +passed with a valid CID. `, }, @@ -51,14 +51,14 @@ var blockStatCmd = &cmds.Command{ 'ipfs block stat' is a plumbing command for retrieving information on raw IPFS blocks. It outputs the following to stdout: - Key - the base58 encoded multihash + Key - the CID of the block Size - the size of the block in bytes `, }, Arguments: []cmds.Argument{ - cmds.StringArg("key", true, false, "The base58 multihash of an existing block to stat.").EnableStdin(), + cmds.StringArg("cid", true, false, "The CID of an existing block to stat.").EnableStdin(), }, Run: func(req *cmds.Request, res cmds.ResponseEmitter, env cmds.Environment) error { api, err := cmdenv.GetApi(env, req) @@ -90,12 +90,12 @@ var blockGetCmd = &cmds.Command{ Tagline: "Get a raw IPFS block.", ShortDescription: ` 'ipfs block get' is a plumbing command for retrieving raw IPFS blocks. -It outputs to stdout, and is a base58 encoded multihash. +It takes a , and outputs the block to stdout. `, }, Arguments: []cmds.Argument{ - cmds.StringArg("key", true, false, "The base58 multihash of an existing block to get.").EnableStdin(), + cmds.StringArg("cid", true, false, "The CID of an existing block to get.").EnableStdin(), }, Run: func(req *cmds.Request, res cmds.ResponseEmitter, env cmds.Environment) error { api, err := cmdenv.GetApi(env, req) @@ -113,9 +113,10 @@ It outputs to stdout, and is a base58 encoded multihash. } const ( - blockFormatOptionName = "format" - mhtypeOptionName = "mhtype" - mhlenOptionName = "mhlen" + blockFormatOptionName = "format" + blockCidCodecOptionName = "cid-codec" + mhtypeOptionName = "mhtype" + mhlenOptionName = "mhlen" ) var blockPutCmd = &cmds.Command{ @@ -123,10 +124,17 @@ var blockPutCmd = &cmds.Command{ Tagline: "Store input as an IPFS block.", ShortDescription: ` 'ipfs block put' is a plumbing command for storing raw IPFS blocks. -It reads from stdin, and outputs the block's CID to stdout. +It reads data from stdin, and outputs the block's CID to stdout. -Unless specified, this command returns dag-pb CIDv0 CIDs. Setting 'mhtype' to anything -other than 'sha2-256' or format to anything other than 'v0' will result in CIDv1. +Unless cid-codec is specified, this command returns raw (0x55) CIDv1 CIDs. + +Passing alternative --cid-codec does not modify imported data, nor run any +validation. It is provided solely for convenience for users who create blocks +in userland. + +NOTE: +Do not use --format for any new code. It got superseded by --cid-codec and left +only for backward compatibility when a legacy CIDv0 is required (--format=v0). `, }, @@ -134,11 +142,12 @@ other than 'sha2-256' or format to anything other than 'v0' will result in CIDv1 cmds.FileArg("data", true, true, "The data to be stored as an IPFS block.").EnableStdin(), }, Options: []cmds.Option{ - cmds.StringOption(blockFormatOptionName, "f", "cid format for blocks to be created with."), - cmds.StringOption(mhtypeOptionName, "multihash hash function").WithDefault("sha2-256"), - cmds.IntOption(mhlenOptionName, "multihash hash length").WithDefault(-1), - cmds.BoolOption(pinOptionName, "pin added blocks recursively").WithDefault(false), + cmds.StringOption(blockCidCodecOptionName, "Multicodec to use in returned CID").WithDefault("raw"), + cmds.StringOption(mhtypeOptionName, "Multihash hash function").WithDefault("sha2-256"), + cmds.IntOption(mhlenOptionName, "Multihash hash length").WithDefault(-1), + cmds.BoolOption(pinOptionName, "Pin added blocks recursively").WithDefault(false), cmdutils.AllowBigBlockOption, + cmds.StringOption(blockFormatOptionName, "f", "Use legacy format for returned CID (DEPRECATED)"), }, Run: func(req *cmds.Request, res cmds.ResponseEmitter, env cmds.Environment) error { api, err := cmdenv.GetApi(env, req) @@ -157,13 +166,15 @@ other than 'sha2-256' or format to anything other than 'v0' will result in CIDv1 return errors.New("missing option \"mhlen\"") } - format, formatSet := req.Options[blockFormatOptionName].(string) - if !formatSet { - if mhtval != mh.SHA2_256 || (mhlen != -1 && mhlen != 32) { - format = "protobuf" - } else { - format = "v0" + cidCodec, _ := req.Options[blockCidCodecOptionName].(string) + format, _ := req.Options[blockFormatOptionName].(string) // deprecated + + // use of legacy 'format' needs to supress 'cid-codec' + if format != "" { + if cidCodec != "" && cidCodec != "raw" { + return fmt.Errorf("unable to use %q (deprecated) and a custom %q at the same time", blockFormatOptionName, blockCidCodecOptionName) } + cidCodec = "" // makes it no-op } pin, _ := req.Options[pinOptionName].(bool) @@ -177,6 +188,7 @@ other than 'sha2-256' or format to anything other than 'v0' will result in CIDv1 p, err := api.Block().Put(req.Context, file, options.Block.Hash(mhtval, mhlen), + options.Block.CidCodec(cidCodec), options.Block.Format(format), options.Block.Pin(pin)) if err != nil { @@ -219,14 +231,14 @@ type removedBlock struct { var blockRmCmd = &cmds.Command{ Helptext: cmds.HelpText{ - Tagline: "Remove IPFS block(s).", + Tagline: "Remove IPFS block(s) from the local datastore.", ShortDescription: ` 'ipfs block rm' is a plumbing command for removing raw ipfs blocks. -It takes a list of base58 encoded multihashes to remove. +It takes a list of CIDs to remove from the local datastore.. `, }, Arguments: []cmds.Argument{ - cmds.StringArg("hash", true, true, "Bash58 encoded multihash of block(s) to remove."), + cmds.StringArg("cid", true, true, "CIDs of block(s) to remove."), }, Options: []cmds.Option{ cmds.BoolOption(forceOptionName, "f", "Ignore nonexistent blocks."), diff --git a/core/commands/cid.go b/core/commands/cid.go index 13c3e83a918..64508609094 100644 --- a/core/commands/cid.go +++ b/core/commands/cid.go @@ -11,7 +11,9 @@ import ( cidutil "github.com/ipfs/go-cidutil" cmds "github.com/ipfs/go-ipfs-cmds" verifcid "github.com/ipfs/go-verifcid" + "github.com/ipld/go-ipld-prime/multicodec" mbase "github.com/multiformats/go-multibase" + mc "github.com/multiformats/go-multicodec" mhash "github.com/multiformats/go-multihash" ) @@ -46,7 +48,7 @@ The optional format string is a printf style format string: ` + cidutil.FormatRef, }, Arguments: []cmds.Argument{ - cmds.StringArg("cid", true, true, "Cids to format.").EnableStdin(), + cmds.StringArg("cid", true, true, "CIDs to format.").EnableStdin(), }, Options: []cmds.Option{ cmds.StringOption(cidFormatOptionName, "Printf style format string.").WithDefault("%s"), @@ -63,14 +65,14 @@ The optional format string is a printf style format string: opts := cidFormatOpts{} if strings.IndexByte(fmtStr, '%') == -1 { - return fmt.Errorf("invalid format string: %s", fmtStr) + return fmt.Errorf("invalid format string: %q", fmtStr) } opts.fmtStr = fmtStr if codecStr != "" { codec, ok := cid.Codecs[codecStr] if !ok { - return fmt.Errorf("unknown IPLD codec: %s", codecStr) + return fmt.Errorf("unknown IPLD codec: %q", codecStr) } opts.newCodec = codec } // otherwise, leave it as 0 (not a valid IPLD codec) @@ -80,13 +82,13 @@ The optional format string is a printf style format string: // noop case "0": if opts.newCodec != 0 && opts.newCodec != cid.DagProtobuf { - return fmt.Errorf("cannot convert to CIDv0 with any codec other than DagPB") + return fmt.Errorf("cannot convert to CIDv0 with any codec other than dag-pb") } opts.verConv = toCidV0 case "1": opts.verConv = toCidV1 default: - return fmt.Errorf("invalid cid version: %s", verStr) + return fmt.Errorf("invalid cid version: %q", verStr) } if baseStr != "" { @@ -123,9 +125,13 @@ type CidFormatRes struct { var base32Cmd = &cmds.Command{ Helptext: cmds.HelpText{ Tagline: "Convert CIDs to Base32 CID version 1.", + ShortDescription: ` +'ipfs cid base32' normalizes passes CIDs to their canonical case-insensitive encoding. +Useful when processing third-party CIDs which could come with arbitrary formats. +`, }, Arguments: []cmds.Argument{ - cmds.StringArg("cid", true, true, "Cids to convert.").EnableStdin(), + cmds.StringArg("cid", true, true, "CIDs to convert.").EnableStdin(), }, Run: func(req *cmds.Request, resp cmds.ResponseEmitter, env cmds.Environment) error { opts := cidFormatOpts{ @@ -232,7 +238,7 @@ func emitCids(req *cmds.Request, resp cmds.ResponseEmitter, opts cidFormatOpts) func toCidV0(c cid.Cid) (cid.Cid, error) { if c.Type() != cid.DagProtobuf { - return cid.Cid{}, fmt.Errorf("can't convert non-protobuf nodes to cidv0") + return cid.Cid{}, fmt.Errorf("can't convert non-dag-pb nodes to cidv0") } return cid.NewCidV0(c.Hash()), nil } @@ -254,6 +260,9 @@ const ( var basesCmd = &cmds.Command{ Helptext: cmds.HelpText{ Tagline: "List available multibase encodings.", + ShortDescription: ` +'ipfs cid bases' relies on https://github.com/multiformats/go-multibase +`, }, Options: []cmds.Option{ cmds.BoolOption(prefixOptionName, "also include the single letter prefixes in addition to the code"), @@ -296,21 +305,45 @@ var basesCmd = &cmds.Command{ } const ( - codecsNumericOptionName = "numeric" + codecsNumericOptionName = "numeric" + codecsSupportedOptionName = "supported" ) var codecsCmd = &cmds.Command{ Helptext: cmds.HelpText{ Tagline: "List available CID codecs.", + ShortDescription: ` +'ipfs cid codecs' relies on https://github.com/multiformats/go-multicodec +`, }, Options: []cmds.Option{ - cmds.BoolOption(codecsNumericOptionName, "also include numeric codes"), + cmds.BoolOption(codecsNumericOptionName, "n", "also include numeric codes"), + cmds.BoolOption(codecsSupportedOptionName, "s", "list only codecs supported by go-ipfs commands"), }, Run: func(req *cmds.Request, resp cmds.ResponseEmitter, env cmds.Environment) error { + listSupported, _ := req.Options[codecsSupportedOptionName].(bool) + supportedCodecs := make(map[uint64]struct{}) + if listSupported { + for _, code := range multicodec.ListEncoders() { + supportedCodecs[code] = struct{}{} + } + for _, code := range multicodec.ListDecoders() { + supportedCodecs[code] = struct{}{} + } + // add libp2p-key + supportedCodecs[uint64(mc.Libp2pKey)] = struct{}{} + } + var res []CodeAndName - // use CodecToStr as there are multiple names for a given code - for code, name := range cid.CodecToStr { - res = append(res, CodeAndName{int(code), name}) + for _, code := range mc.KnownCodes() { + if code.Tag() == "ipld" { + if listSupported { + if _, ok := supportedCodecs[uint64(code)]; !ok { + continue + } + } + res = append(res, CodeAndName{int(code), mc.Code(code).String()}) + } } return cmds.EmitOnce(resp, res) }, @@ -334,6 +367,9 @@ var codecsCmd = &cmds.Command{ var hashesCmd = &cmds.Command{ Helptext: cmds.HelpText{ Tagline: "List available multihashes.", + ShortDescription: ` +'ipfs cid hashes' relies on https://github.com/multiformats/go-multihash +`, }, Options: codecsCmd.Options, Run: func(req *cmds.Request, resp cmds.ResponseEmitter, env cmds.Environment) error { diff --git a/core/coreapi/block.go b/core/coreapi/block.go index 5560e64cb2b..56520690833 100644 --- a/core/coreapi/block.go +++ b/core/coreapi/block.go @@ -31,7 +31,7 @@ func (api *BlockAPI) Put(ctx context.Context, src io.Reader, opts ...caopts.Bloc ctx, span := tracing.Span(ctx, "CoreAPI.BlockAPI", "Put") defer span.End() - settings, pref, err := caopts.BlockPutOptions(opts...) + settings, err := caopts.BlockPutOptions(opts...) if err != nil { return nil, err } @@ -41,7 +41,7 @@ func (api *BlockAPI) Put(ctx context.Context, src io.Reader, opts ...caopts.Bloc return nil, err } - bcid, err := pref.Sum(data) + bcid, err := settings.CidPrefix.Sum(data) if err != nil { return nil, err } diff --git a/go.mod b/go.mod index 86c903c7cb7..84097cd2c1c 100644 --- a/go.mod +++ b/go.mod @@ -57,7 +57,7 @@ require ( github.com/ipfs/go-unixfs v0.3.1 github.com/ipfs/go-unixfsnode v1.1.3 github.com/ipfs/go-verifcid v0.0.1 - github.com/ipfs/interface-go-ipfs-core v0.6.2 + github.com/ipfs/interface-go-ipfs-core v0.7.0 github.com/ipfs/tar-utils v0.0.2 github.com/ipld/go-car v0.3.2 github.com/ipld/go-car/v2 v2.1.1 @@ -96,7 +96,7 @@ require ( github.com/multiformats/go-multiaddr v0.5.0 github.com/multiformats/go-multiaddr-dns v0.3.1 github.com/multiformats/go-multibase v0.0.3 - github.com/multiformats/go-multicodec v0.4.0 + github.com/multiformats/go-multicodec v0.4.1 github.com/multiformats/go-multihash v0.1.0 github.com/opentracing/opentracing-go v1.2.0 github.com/pkg/errors v0.9.1 diff --git a/go.sum b/go.sum index c66a3626052..b4bb172b402 100644 --- a/go.sum +++ b/go.sum @@ -605,8 +605,8 @@ github.com/ipfs/go-unixfsnode v1.1.3/go.mod h1:ZZxUM5wXBC+G0Co9FjrYTOm+UlhZTjxLf github.com/ipfs/go-verifcid v0.0.1 h1:m2HI7zIuR5TFyQ1b79Da5N9dnnCP1vcu2QqawmWlK2E= github.com/ipfs/go-verifcid v0.0.1/go.mod h1:5Hrva5KBeIog4A+UpqlaIU+DEstipcJYQQZc0g37pY0= github.com/ipfs/interface-go-ipfs-core v0.4.0/go.mod h1:UJBcU6iNennuI05amq3FQ7g0JHUkibHFAfhfUIy927o= -github.com/ipfs/interface-go-ipfs-core v0.6.2 h1:nnkq9zhb5O8lPzkZeynEymc83RqkTRqfYH4x5JNUkT4= -github.com/ipfs/interface-go-ipfs-core v0.6.2/go.mod h1:h3NuO3wzv2KuKazt0zDF2/i8AFRqiKHusyh5DUQQdPA= +github.com/ipfs/interface-go-ipfs-core v0.7.0 h1:7tb+2upz8oCcjIyjo1atdMk+P+u7wPmI+GksBlLE8js= +github.com/ipfs/interface-go-ipfs-core v0.7.0/go.mod h1:lF27E/nnSPbylPqKVXGZghal2hzifs3MmjyiEjnc9FY= github.com/ipfs/tar-utils v0.0.2 h1:UNgHB4x/PPzbMkmJi+7EqC9LNMPDztOVSnx1HAqSNg4= github.com/ipfs/tar-utils v0.0.2/go.mod h1:4qlnRWgTVljIMhSG2SqRYn66NT+3wrv/kZt9V+eqxDM= github.com/ipld/go-car v0.3.2 h1:V9wt/80FNfbMRWSD98W5br6fyjUAyVgI2lDOTZX16Lg= @@ -1188,8 +1188,8 @@ github.com/multiformats/go-multibase v0.0.3/go.mod h1:5+1R4eQrT3PkYZ24C3W2Ue2tPw github.com/multiformats/go-multicodec v0.2.0/go.mod h1:/y4YVwkfMyry5kFbMTbLJKErhycTIftytRV+llXdyS4= github.com/multiformats/go-multicodec v0.3.0/go.mod h1:qGGaQmioCDh+TeFOnxrbU0DaIPw8yFgAZgFG0V7p1qQ= github.com/multiformats/go-multicodec v0.3.1-0.20210902112759-1539a079fd61/go.mod h1:1Hj/eHRaVWSXiSNNfcEPcwZleTmdNP81xlxDLnWU9GQ= -github.com/multiformats/go-multicodec v0.4.0 h1:fbqb6ky7erjdD+/zaEBJgZWu1i8D6i/wmPywGK7sdow= -github.com/multiformats/go-multicodec v0.4.0/go.mod h1:1Hj/eHRaVWSXiSNNfcEPcwZleTmdNP81xlxDLnWU9GQ= +github.com/multiformats/go-multicodec v0.4.1 h1:BSJbf+zpghcZMZrwTYBGwy0CPcVZGWiC72Cp8bBd4R4= +github.com/multiformats/go-multicodec v0.4.1/go.mod h1:1Hj/eHRaVWSXiSNNfcEPcwZleTmdNP81xlxDLnWU9GQ= github.com/multiformats/go-multihash v0.0.1/go.mod h1:w/5tugSrLEbWqlcgJabL3oHFKTwfvkofsjW2Qa1ct4U= github.com/multiformats/go-multihash v0.0.5/go.mod h1:lt/HCbqlQwlPBz7lv0sQCdtfcMtlJvakRUn/0Ual8po= github.com/multiformats/go-multihash v0.0.8/go.mod h1:YSLudS+Pi8NHE7o6tb3D8vrpKa63epEDmG8nTduyAew= diff --git a/test/sharness/t0050-block.sh b/test/sharness/t0050-block.sh index 2b58c7efe1a..9ecf2087596 100755 --- a/test/sharness/t0050-block.sh +++ b/test/sharness/t0050-block.sh @@ -10,16 +10,18 @@ test_description="Test block command" test_init_ipfs -HASH="QmRKqGMAM6EZngbpjSqrvYzq5Qd8b1bSWymjSUY9zQSNDk" -HASHB="QmdnpnsaEj69isdw5sNzp3h3HkaDz7xKq7BmvFFBzNr5e7" +HASH="bafkreibmlvvgdyihetgocpof6xk64kjjzdeq2e4c7hqs3krdheosk4tgj4" +HASHB="bafkreihfsphazrk2ilejpekyltjeh5k4yvwgjuwg26ueafohqioeo3sdca" + +HASHV0="QmRKqGMAM6EZngbpjSqrvYzq5Qd8b1bSWymjSUY9zQSNDk" +HASHBV0="QmdnpnsaEj69isdw5sNzp3h3HkaDz7xKq7BmvFFBzNr5e7" -# # "block put tests" # test_expect_success "'ipfs block put' succeeds" ' echo "Hello Mars!" >expected_in && - ipfs block put actual_out + ipfs block put a && echo "Hello Venus!" > b && - ipfs block put a b >actual_out + ipfs block put a b | tee actual_out ' test_expect_success "'ipfs block put' output looks good" ' @@ -39,6 +41,15 @@ test_expect_success "'ipfs block put' output looks good" ' test_cmp expected_out actual_out ' +test_expect_success "can set cid codec on block put" ' + CODEC_HASH=$(ipfs block put --cid-codec=dag-pb ../t0051-object-data/testPut.pb) +' + +test_expect_success "block get output looks right" ' + ipfs block get $CODEC_HASH > pb_block_out && + test_cmp pb_block_out ../t0051-object-data/testPut.pb +' + # # "block get" tests # @@ -196,7 +207,9 @@ test_expect_success "multi-block 'ipfs block rm -q' produces no output" ' test ! -s block_rm_out ' -test_expect_success "can set cid format on block put" ' +# --format used 'protobuf' for 'dag-pb' which was invalid, but we keep +# for backward-compatibility +test_expect_success "can set deprecated --format=protobuf on block put" ' HASH=$(ipfs block put --format=protobuf ../t0051-object-data/testPut.pb) ' @@ -211,7 +224,22 @@ test_expect_success "block get output looks right" ' test_cmp pb_block_out ../t0051-object-data/testPut.pb ' -test_expect_success "can set multihash type and length on block put" ' +test_expect_success "can set --cid-codec=dag-pb on block put" ' + HASH=$(ipfs block put --cid-codec=dag-pb ../t0051-object-data/testPut.pb) +' + +test_expect_success "created an object correctly!" ' + ipfs object get $HASH > obj_out && + echo "{\"Links\":[],\"Data\":\"test json for sharness test\"}" > obj_exp && + test_cmp obj_out obj_exp +' + +test_expect_success "block get output looks right" ' + ipfs block get $HASH > pb_block_out && + test_cmp pb_block_out ../t0051-object-data/testPut.pb +' + +test_expect_success "can set multihash type and length on block put with --format=raw (deprecated)" ' HASH=$(echo "foooo" | ipfs block put --format=raw --mhtype=sha3 --mhlen=20) ' @@ -219,6 +247,11 @@ test_expect_success "output looks good" ' test "bafkrifctrq4xazzixy2v4ezymjcvzpskqdwlxra" = "$HASH" ' +test_expect_success "can't use both legacy format and custom cid-codec at the same time" ' + test_expect_code 1 ipfs block put --format=dag-cbor --cid-codec=dag-json < ../t0051-object-data/testPut.pb 2> output && + test_should_contain "unable to use \"format\" (deprecated) and a custom \"cid-codec\" at the same time" output +' + test_expect_success "can read block with different hash" ' ipfs block get $HASH > blk_get_out && echo "foooo" > blk_get_exp && @@ -232,14 +265,23 @@ test_expect_success "'ipfs block stat' with nothing from stdin doesn't crash" ' test_expect_code 1 ipfs block stat < /dev/null 2> stat_out ' +# lol test_expect_success "no panic in output" ' test_expect_code 1 grep "panic" stat_out ' -test_expect_success "can set multihash type and length on block put without format" ' +test_expect_success "can set multihash type and length on block put without format or cid-codec" ' HASH=$(echo "foooo" | ipfs block put --mhtype=sha3 --mhlen=20) ' +test_expect_success "output looks good" ' + test "bafkrifctrq4xazzixy2v4ezymjcvzpskqdwlxra" = "$HASH" +' + +test_expect_success "can set multihash type and length on block put with cid-codec=dag-pb" ' + HASH=$(echo "foooo" | ipfs block put --mhtype=sha3 --mhlen=20 --cid-codec=dag-pb) +' + test_expect_success "output looks good" ' test "bafybifctrq4xazzixy2v4ezymjcvzpskqdwlxra" = "$HASH" ' diff --git a/test/sharness/t0110-gateway.sh b/test/sharness/t0110-gateway.sh index e1ee6496244..11220347819 100755 --- a/test/sharness/t0110-gateway.sh +++ b/test/sharness/t0110-gateway.sh @@ -262,7 +262,7 @@ test_expect_success "try fetching it from gateway" ' test_expect_success "Add compact blocks" ' ipfs block put ../t0110-gateway-data/foo.block && - FOO2_HASH=$(ipfs block put ../t0110-gateway-data/foofoo.block) && + FOO2_HASH=$(ipfs block put --cid-codec=dag-pb ../t0110-gateway-data/foofoo.block) && printf "foofoo" > expected ' diff --git a/test/sharness/t0290-cid.sh b/test/sharness/t0290-cid.sh index 680e5308d91..b6518892ef6 100755 --- a/test/sharness/t0290-cid.sh +++ b/test/sharness/t0290-cid.sh @@ -103,11 +103,19 @@ Z 90 base58flickr EOF cat < codecs_expect + 81 cbor 85 raw - 112 protobuf - 113 cbor + 112 dag-pb + 113 dag-cbor + 114 libp2p-key 120 git-raw + 123 torrent-info + 124 torrent-file + 129 leofcoin-block + 130 leofcoin-tx + 131 leofcoin-pr 133 dag-jose + 134 dag-cose 144 eth-block 145 eth-block-list 146 eth-tx-trie @@ -117,16 +125,36 @@ cat < codecs_expect 150 eth-state-trie 151 eth-account-snapshot 152 eth-storage-trie + 153 eth-receipt-log-trie + 154 eth-reciept-log 176 bitcoin-block 177 bitcoin-tx + 178 bitcoin-witness-commitment 192 zcash-block 193 zcash-tx + 208 stellar-block + 209 stellar-tx 224 decred-block 225 decred-tx 240 dash-block 241 dash-tx -61697 fil-commitment-unsealed -61698 fil-commitment-sealed + 250 swarm-manifest + 251 swarm-feed + 297 dag-json + 496 swhid-1-snp + 512 json +EOF + +cat < supported_codecs_expect + 81 cbor + 85 raw + 112 dag-pb + 113 dag-cbor + 114 libp2p-key + 120 git-raw + 133 dag-jose + 297 dag-json + 512 json EOF cat < hashes_expect @@ -232,6 +260,17 @@ test_expect_success "cid codecs --numeric" ' test_cmp codecs_expect actual ' +test_expect_success "cid codecs --supported" ' + cut -c 8- supported_codecs_expect > expect && + ipfs cid codecs --supported > actual + test_cmp expect actual +' + +test_expect_success "cid codecs --supported --numeric" ' + ipfs cid codecs --supported --numeric > actual && + test_cmp supported_codecs_expect actual +' + test_expect_success "cid hashes" ' cut -c 8- hashes_expect > expect && ipfs cid hashes > actual From fd7af6a7333605e3098417163d24fe522c1ce90e Mon Sep 17 00:00:00 2001 From: Jorropo Date: Thu, 21 Apr 2022 21:10:58 +0200 Subject: [PATCH 359/414] chore: update go-libp2p-asn-util to make it init faster --- go.mod | 2 +- go.sum | 3 ++- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/go.mod b/go.mod index 84097cd2c1c..1b22e73de15 100644 --- a/go.mod +++ b/go.mod @@ -180,7 +180,7 @@ require ( github.com/libp2p/go-conn-security-multistream v0.3.0 // indirect github.com/libp2p/go-eventbus v0.2.1 // indirect github.com/libp2p/go-flow-metrics v0.0.3 // indirect - github.com/libp2p/go-libp2p-asn-util v0.1.0 // indirect + github.com/libp2p/go-libp2p-asn-util v0.2.0 // indirect github.com/libp2p/go-libp2p-blankhost v0.3.0 // indirect github.com/libp2p/go-libp2p-gostream v0.3.0 // indirect github.com/libp2p/go-libp2p-nat v0.1.0 // indirect diff --git a/go.sum b/go.sum index b4bb172b402..f185dd54a5e 100644 --- a/go.sum +++ b/go.sum @@ -731,8 +731,9 @@ github.com/libp2p/go-libp2p v0.16.0/go.mod h1:ump42BsirwAWxKzsCiFnTtN1Yc+DuPu76f github.com/libp2p/go-libp2p v0.18.0 h1:moKKKG875KNGsCjZxTIFB75ihHiVjFeWg5I4aR1pDLk= github.com/libp2p/go-libp2p v0.18.0/go.mod h1:+veaZ9z1SZQhmc5PW78jvnnxZ89Mgvmh4cggO11ETmw= github.com/libp2p/go-libp2p-asn-util v0.0.0-20200825225859-85005c6cf052/go.mod h1:nRMRTab+kZuk0LnKZpxhOVH/ndsdr2Nr//Zltc/vwgo= -github.com/libp2p/go-libp2p-asn-util v0.1.0 h1:rABPCO77SjdbJ/eJ/ynIo8vWICy1VEnL5JAxJbQLo1E= github.com/libp2p/go-libp2p-asn-util v0.1.0/go.mod h1:wu+AnM9Ii2KgO5jMmS1rz9dvzTdj8BXqsPR9HR0XB7I= +github.com/libp2p/go-libp2p-asn-util v0.2.0 h1:rg3+Os8jbnO5DxkC7K/Utdi+DkY3q/d1/1q+8WeNAsw= +github.com/libp2p/go-libp2p-asn-util v0.2.0/go.mod h1:WoaWxbHKBymSN41hWSq/lGKJEca7TNm58+gGJi2WsLI= github.com/libp2p/go-libp2p-autonat v0.0.6/go.mod h1:uZneLdOkZHro35xIhpbtTzLlgYturpu4J5+0cZK3MqE= github.com/libp2p/go-libp2p-autonat v0.1.0/go.mod h1:1tLf2yXxiE/oKGtDwPYWTSYG3PtvYlJmg7NeVtPRqH8= github.com/libp2p/go-libp2p-autonat v0.1.1/go.mod h1:OXqkeGOY2xJVWKAGV2inNF5aKN/djNA3fdpCWloIudE= From 76ae33a9f3f9abd166d1f6f23d6a8a0511510e3c Mon Sep 17 00:00:00 2001 From: Marcin Rataj Date: Thu, 21 Apr 2022 23:49:51 +0200 Subject: [PATCH 360/414] chore: deprecate /api/v0/dns (#8893) Closes #8607 --- core/commands/dns.go | 37 +++++++------------------------------ core/commands/root.go | 5 ++--- 2 files changed, 9 insertions(+), 33 deletions(-) diff --git a/core/commands/dns.go b/core/commands/dns.go index 42a7c98c1a2..8fccadf6774 100644 --- a/core/commands/dns.go +++ b/core/commands/dns.go @@ -17,40 +17,17 @@ const ( ) var DNSCmd = &cmds.Command{ + Status: cmds.Deprecated, // https://github.com/ipfs/go-ipfs/issues/8607 Helptext: cmds.HelpText{ - Tagline: "Resolve DNS links.", + Tagline: "Resolve DNSLink records.", ShortDescription: ` -Multihashes are hard to remember, but domain names are usually easy to -remember. To create memorable aliases for multihashes, DNS TXT -records can point to other DNS links, IPFS objects, IPNS keys, etc. -This command resolves those links to the referenced object. -`, - LongDescription: ` -Multihashes are hard to remember, but domain names are usually easy to -remember. To create memorable aliases for multihashes, DNS TXT -records can point to other DNS links, IPFS objects, IPNS keys, etc. -This command resolves those links to the referenced object. - -Note: This command can only recursively resolve DNS links, -it will fail to recursively resolve through IPNS keys etc. -For general-purpose recursive resolution, use ipfs name resolve -r. - -For example, with this DNS TXT record: - - > dig +short TXT _dnslink.ipfs.io - dnslink=/ipfs/QmRzTuh2Lpuz7Gr39stNr6mTFdqAghsZec1JoUnfySUzcy - -The resolver will give: - - > ipfs dns ipfs.io - /ipfs/QmRzTuh2Lpuz7Gr39stNr6mTFdqAghsZec1JoUnfySUzcy +This command can only recursively resolve DNSLink TXT records. +It will fail to recursively resolve through IPNS keys etc. -The resolver can recursively resolve: +DEPRECATED: superseded by 'ipfs resolve' - > dig +short TXT recursive.ipfs.io - dnslink=/ipns/ipfs.io - > ipfs dns -r recursive.ipfs.io - /ipfs/QmRzTuh2Lpuz7Gr39stNr6mTFdqAghsZec1JoUnfySUzcy +For general-purpose recursive resolution, use 'ipfs resolve -r'. +It will work across multiple DNSLinks and IPNS keys. `, }, diff --git a/core/commands/root.go b/core/commands/root.go index 3fe31a8587a..b75c634f123 100644 --- a/core/commands/root.go +++ b/core/commands/root.go @@ -51,14 +51,13 @@ TEXT ENCODING COMMANDS ADVANCED COMMANDS daemon Start a long-running daemon process mount Mount an IPFS read-only mount point - resolve Resolve any type of name + resolve Resolve any type of content path name Publish and resolve IPNS names key Create and list IPNS name keypairs - dns Resolve DNS links pin Pin objects to local storage repo Manipulate the IPFS repository stats Various operational stats - p2p Libp2p stream mounting + p2p Libp2p stream mounting (experimental) filestore Manage the filestore (experimental) NETWORK COMMANDS From 7162a63e9629258bac0b9d135acae4c3c1b9fb33 Mon Sep 17 00:00:00 2001 From: Marcin Rataj Date: Fri, 22 Apr 2022 17:38:47 +0200 Subject: [PATCH 361/414] chore: improve new issue links (#8874) --- .github/ISSUE_TEMPLATE/config.yml | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/.github/ISSUE_TEMPLATE/config.yml b/.github/ISSUE_TEMPLATE/config.yml index e5afd8ffa56..27fef31b01c 100644 --- a/.github/ISSUE_TEMPLATE/config.yml +++ b/.github/ISSUE_TEMPLATE/config.yml @@ -4,14 +4,14 @@ contact_links: url: https://ipfs.io/help about: All information about how and where to get help on IPFS. - name: Go-ipfs configuration reference - url: https://github.com/ipfs/go-ipfs/blob/master/docs/config.md + url: https://github.com/ipfs/go-ipfs/blob/master/docs/config.md#readme about: Documentation on the different configuration settings - name: Go-ipfs experimental features docs - url: https://github.com/ipfs/go-ipfs/blob/master/docs/experimental-features.md + url: https://github.com/ipfs/go-ipfs/blob/master/docs/experimental-features.md#readme about: Documentation on Private Networks, Filestore and other experimental features. - - name: HTTP API Reference - url: https://docs.ipfs.io/reference/http/api/#api-v0-add - about: Documentation of all go-ipfs HTTP API endpoints. + - name: RPC API Reference + url: https://docs.ipfs.io/reference/http/api/ + about: Documentation of all go-ipfs RPC API endpoints. - name: IPFS Official Forum url: https://discuss.ipfs.io about: Please post general questions, support requests, and discussions here. From 6817fd474467face64b08440e5c938e6566c39d5 Mon Sep 17 00:00:00 2001 From: Lucas Molas Date: Mon, 3 Jan 2022 12:00:01 -0300 Subject: [PATCH 362/414] feat(cmds): allow to set the configuration file path --- cmd/ipfs/daemon.go | 5 +- cmd/ipfs/main.go | 2 +- config/config.go | 20 +++++- core/commands/config.go | 6 +- core/commands/root.go | 6 +- repo/fsrepo/fsrepo.go | 67 +++++++++---------- .../migrations/ipfsfetcher/ipfsfetcher.go | 22 +++--- .../ipfsfetcher/ipfsfetcher_test.go | 14 ++-- repo/fsrepo/migrations/migrations.go | 4 +- repo/fsrepo/migrations/migrations_test.go | 10 +-- 10 files changed, 88 insertions(+), 68 deletions(-) diff --git a/cmd/ipfs/daemon.go b/cmd/ipfs/daemon.go index 32cff04ef2c..14054c36fff 100644 --- a/cmd/ipfs/daemon.go +++ b/cmd/ipfs/daemon.go @@ -298,7 +298,8 @@ func daemonFunc(req *cmds.Request, re cmds.ResponseEmitter, env cmds.Environment } // Read Migration section of IPFS config - migrationCfg, err := migrations.ReadMigrationConfig(cctx.ConfigRoot) + configFileOpt, _ := req.Options[commands.ConfigFileOption].(string) + migrationCfg, err := migrations.ReadMigrationConfig(cctx.ConfigRoot, configFileOpt) if err != nil { return err } @@ -309,7 +310,7 @@ func daemonFunc(req *cmds.Request, re cmds.ResponseEmitter, env cmds.Environment // to construct the particular IPFS fetcher implementation used here, // which is called only if an IPFS fetcher is needed. newIpfsFetcher := func(distPath string) migrations.Fetcher { - return ipfsfetcher.NewIpfsFetcher(distPath, 0, &cctx.ConfigRoot) + return ipfsfetcher.NewIpfsFetcher(distPath, 0, &cctx.ConfigRoot, configFileOpt) } // Fetch migrations from current distribution, or location from environ diff --git a/cmd/ipfs/main.go b/cmd/ipfs/main.go index b95129db475..6147a0cbf75 100644 --- a/cmd/ipfs/main.go +++ b/cmd/ipfs/main.go @@ -303,7 +303,7 @@ func makeExecutor(req *cmds.Request, env interface{}) (cmds.Executor, error) { } func getRepoPath(req *cmds.Request) (string, error) { - repoOpt, found := req.Options["config"].(string) + repoOpt, found := req.Options[corecmds.RepoDirOption].(string) if found && repoOpt != "" { return repoOpt, nil } diff --git a/config/config.go b/config/config.go index 419a6a71f3a..1f4d9e83c87 100644 --- a/config/config.go +++ b/config/config.go @@ -76,9 +76,23 @@ func Path(configroot, extension string) (string, error) { } // Filename returns the configuration file path given a configuration root -// directory. If the configuration root directory is empty, use the default one -func Filename(configroot string) (string, error) { - return Path(configroot, DefaultConfigFile) +// directory and a user-provided configuration file path argument with the +// following rules: +// * If the user-provided configuration file path is empty, use the default one. +// * If the configuration root directory is empty, use the default one. +// * If the user-provided configuration file path is only a file name, use the +// configuration root directory, otherwise use only the user-provided path +// and ignore the configuration root. +func Filename(configroot string, userConfigFile string) (string, error) { + if userConfigFile == "" { + return Path(configroot, DefaultConfigFile) + } + + if filepath.Dir(userConfigFile) == "." { + return Path(configroot, userConfigFile) + } + + return userConfigFile, nil } // HumanOutput gets a config value ready for printing diff --git a/core/commands/config.go b/core/commands/config.go index 3f009de9a0d..38e14c31da9 100644 --- a/core/commands/config.go +++ b/core/commands/config.go @@ -186,7 +186,8 @@ NOTE: For security reasons, this command will omit your private key and remote s return err } - fname, err := config.Filename(cfgRoot) + configFileOpt, _ := req.Options[ConfigFileOption].(string) + fname, err := config.Filename(cfgRoot, configFileOpt) if err != nil { return err } @@ -291,7 +292,8 @@ variable set to your preferred text editor. return err } - filename, err := config.Filename(cfgRoot) + configFileOpt, _ := req.Options[ConfigFileOption].(string) + filename, err := config.Filename(cfgRoot, configFileOpt) if err != nil { return err } diff --git a/core/commands/root.go b/core/commands/root.go index b75c634f123..ef17d2f70c7 100644 --- a/core/commands/root.go +++ b/core/commands/root.go @@ -19,6 +19,8 @@ var log = logging.Logger("core/commands") var ErrNotOnline = errors.New("this command must be run in online mode. Try running 'ipfs daemon' first") const ( + RepoDirOption = "repo-dir" + ConfigFileOption = "config-file" ConfigOption = "config" DebugOption = "debug" LocalOption = "local" // DEPRECATED: use OfflineOption @@ -94,7 +96,9 @@ The CLI will exit with one of the following values: `, }, Options: []cmds.Option{ - cmds.StringOption(ConfigOption, "c", "Path to the configuration file to use."), + cmds.StringOption(RepoDirOption, "Path to the repository directory to use."), + cmds.StringOption(ConfigFileOption, "Path to the configuration file to use."), + cmds.StringOption(ConfigOption, "c", "[DEPRECATED] Path to the configuration file to use."), cmds.BoolOption(DebugOption, "D", "Operate in debug mode."), cmds.BoolOption(cmds.OptLongHelp, "Show the full command help text."), cmds.BoolOption(cmds.OptShortHelp, "Show a short version of the command help text."), diff --git a/repo/fsrepo/fsrepo.go b/repo/fsrepo/fsrepo.go index 7ec0e0ab89a..7ad634c843b 100644 --- a/repo/fsrepo/fsrepo.go +++ b/repo/fsrepo/fsrepo.go @@ -96,6 +96,9 @@ type FSRepo struct { closed bool // path is the file-system path path string + // Path to the configuration file that may or may not be inside the FSRepo + // path (see config.Filename for more details). + configFilePath string // lockfile is the file system lock to prevent others from opening // the same fsrepo path concurrently lockfile io.Closer @@ -111,16 +114,25 @@ var _ repo.Repo = (*FSRepo)(nil) // initialized. func Open(repoPath string) (repo.Repo, error) { fn := func() (repo.Repo, error) { - return open(repoPath) + return open(repoPath, "") } return onlyOne.Open(repoPath, fn) } -func open(repoPath string) (repo.Repo, error) { +// OpenWithUserConfig is the equivalent to the Open function above but with the +// option to set the configuration file path instead of using the default. +func OpenWithUserConfig(repoPath string, userConfigFilePath string) (repo.Repo, error) { + fn := func() (repo.Repo, error) { + return open(repoPath, userConfigFilePath) + } + return onlyOne.Open(repoPath, fn) +} + +func open(repoPath string, userConfigFilePath string) (repo.Repo, error) { packageLock.Lock() defer packageLock.Unlock() - r, err := newFSRepo(repoPath) + r, err := newFSRepo(repoPath, userConfigFilePath) if err != nil { return nil, err } @@ -185,13 +197,19 @@ func open(repoPath string) (repo.Repo, error) { return r, nil } -func newFSRepo(rpath string) (*FSRepo, error) { +func newFSRepo(rpath string, userConfigFilePath string) (*FSRepo, error) { expPath, err := homedir.Expand(filepath.Clean(rpath)) if err != nil { return nil, err } - return &FSRepo{path: expPath}, nil + configFilePath, err := config.Filename(rpath, userConfigFilePath) + if err != nil { + // FIXME: Personalize this when the user config path is "". + return nil, fmt.Errorf("finding config filepath from repo %s and user config %s: %w", + rpath, userConfigFilePath, err) + } + return &FSRepo{path: expPath, configFilePath: configFilePath}, nil } func checkInitialized(path string) error { @@ -208,7 +226,7 @@ func checkInitialized(path string) error { // configIsInitialized returns true if the repo is initialized at // provided |path|. func configIsInitialized(path string) bool { - configFilename, err := config.Filename(path) + configFilename, err := config.Filename(path, "") if err != nil { return false } @@ -222,7 +240,7 @@ func initConfig(path string, conf *config.Config) error { if configIsInitialized(path) { return nil } - configFilename, err := config.Filename(path) + configFilename, err := config.Filename(path, "") if err != nil { return err } @@ -372,11 +390,7 @@ func (r *FSRepo) SetAPIAddr(addr ma.Multiaddr) error { // openConfig returns an error if the config file is not present. func (r *FSRepo) openConfig() error { - configFilename, err := config.Filename(r.path) - if err != nil { - return err - } - conf, err := serialize.Load(configFilename) + conf, err := serialize.Load(r.configFilePath) if err != nil { return err } @@ -507,12 +521,7 @@ func (r *FSRepo) BackupConfig(prefix string) (string, error) { } defer temp.Close() - configFilename, err := config.Filename(r.path) - if err != nil { - return "", err - } - - orig, err := os.OpenFile(configFilename, os.O_RDONLY, 0600) + orig, err := os.OpenFile(r.configFilePath, os.O_RDONLY, 0600) if err != nil { return "", err } @@ -546,15 +555,11 @@ func (r *FSRepo) SetConfig(updated *config.Config) error { packageLock.Lock() defer packageLock.Unlock() - configFilename, err := config.Filename(r.path) - if err != nil { - return err - } // to avoid clobbering user-provided keys, must read the config from disk // as a map, write the updated struct values to the map and write the map // to disk. var mapconf map[string]interface{} - if err := serialize.ReadConfigFile(configFilename, &mapconf); err != nil { + if err := serialize.ReadConfigFile(r.configFilePath, &mapconf); err != nil { return err } m, err := config.ToMap(updated) @@ -562,7 +567,7 @@ func (r *FSRepo) SetConfig(updated *config.Config) error { return err } mergedMap := common.MapMergeDeep(mapconf, m) - if err := serialize.WriteConfigFile(configFilename, mergedMap); err != nil { + if err := serialize.WriteConfigFile(r.configFilePath, mergedMap); err != nil { return err } // Do not use `*r.config = ...`. This will modify the *shared* config @@ -580,12 +585,8 @@ func (r *FSRepo) GetConfigKey(key string) (interface{}, error) { return nil, errors.New("repo is closed") } - filename, err := config.Filename(r.path) - if err != nil { - return nil, err - } var cfg map[string]interface{} - if err := serialize.ReadConfigFile(filename, &cfg); err != nil { + if err := serialize.ReadConfigFile(r.configFilePath, &cfg); err != nil { return nil, err } return common.MapGetKV(cfg, key) @@ -600,13 +601,9 @@ func (r *FSRepo) SetConfigKey(key string, value interface{}) error { return errors.New("repo is closed") } - filename, err := config.Filename(r.path) - if err != nil { - return err - } // Load into a map so we don't end up writing any additional defaults to the config file. var mapconf map[string]interface{} - if err := serialize.ReadConfigFile(filename, &mapconf); err != nil { + if err := serialize.ReadConfigFile(r.configFilePath, &mapconf); err != nil { return err } @@ -636,7 +633,7 @@ func (r *FSRepo) SetConfigKey(key string, value interface{}) error { } r.config = conf - if err := serialize.WriteConfigFile(filename, mapconf); err != nil { + if err := serialize.WriteConfigFile(r.configFilePath, mapconf); err != nil { return err } diff --git a/repo/fsrepo/migrations/ipfsfetcher/ipfsfetcher.go b/repo/fsrepo/migrations/ipfsfetcher/ipfsfetcher.go index 21a6038a7eb..da8f83ac034 100644 --- a/repo/fsrepo/migrations/ipfsfetcher/ipfsfetcher.go +++ b/repo/fsrepo/migrations/ipfsfetcher/ipfsfetcher.go @@ -33,9 +33,10 @@ const ( ) type IpfsFetcher struct { - distPath string - limit int64 - repoRoot *string + distPath string + limit int64 + repoRoot *string + userConfigFile string openOnce sync.Once openErr error @@ -62,11 +63,12 @@ var _ migrations.Fetcher = (*IpfsFetcher)(nil) // Bootstrap and peer information in read from the IPFS config file in // repoRoot, unless repoRoot is nil. If repoRoot is empty (""), then read the // config from the default IPFS directory. -func NewIpfsFetcher(distPath string, fetchLimit int64, repoRoot *string) *IpfsFetcher { +func NewIpfsFetcher(distPath string, fetchLimit int64, repoRoot *string, userConfigFile string) *IpfsFetcher { f := &IpfsFetcher{ - limit: defaultFetchLimit, - distPath: migrations.LatestIpfsDist, - repoRoot: repoRoot, + limit: defaultFetchLimit, + distPath: migrations.LatestIpfsDist, + repoRoot: repoRoot, + userConfigFile: userConfigFile, } if distPath != "" { @@ -92,7 +94,7 @@ func (f *IpfsFetcher) Fetch(ctx context.Context, filePath string) ([]byte, error // Initialize and start IPFS node on first call to Fetch, since the fetcher // may be created by not used. f.openOnce.Do(func() { - bootstrap, peers := readIpfsConfig(f.repoRoot) + bootstrap, peers := readIpfsConfig(f.repoRoot, f.userConfigFile) f.ipfsTmpDir, f.openErr = initTempNode(ctx, bootstrap, peers) if f.openErr != nil { return @@ -288,12 +290,12 @@ func parsePath(fetchPath string) (ipath.Path, error) { return ipfsPath, ipfsPath.IsValid() } -func readIpfsConfig(repoRoot *string) (bootstrap []string, peers []peer.AddrInfo) { +func readIpfsConfig(repoRoot *string, userConfigFile string) (bootstrap []string, peers []peer.AddrInfo) { if repoRoot == nil { return } - cfgPath, err := config.Filename(*repoRoot) + cfgPath, err := config.Filename(*repoRoot, userConfigFile) if err != nil { fmt.Fprintln(os.Stderr, err) return diff --git a/repo/fsrepo/migrations/ipfsfetcher/ipfsfetcher_test.go b/repo/fsrepo/migrations/ipfsfetcher/ipfsfetcher_test.go index e300371a679..4e882b7ad83 100644 --- a/repo/fsrepo/migrations/ipfsfetcher/ipfsfetcher_test.go +++ b/repo/fsrepo/migrations/ipfsfetcher/ipfsfetcher_test.go @@ -26,7 +26,7 @@ func TestIpfsFetcher(t *testing.T) { ctx, cancel := context.WithCancel(context.Background()) defer cancel() - fetcher := NewIpfsFetcher("", 0, nil) + fetcher := NewIpfsFetcher("", 0, nil, "") defer fetcher.Close() out, err := fetcher.Fetch(ctx, "go-ipfs/versions") @@ -62,7 +62,7 @@ func TestInitIpfsFetcher(t *testing.T) { ctx, cancel := context.WithCancel(context.Background()) defer cancel() - f := NewIpfsFetcher("", 0, nil) + f := NewIpfsFetcher("", 0, nil, "") defer f.Close() // Init ipfs repo @@ -132,7 +132,7 @@ func TestReadIpfsConfig(t *testing.T) { ` noSuchDir := "no_such_dir-5953aa51-1145-4efd-afd1-a069075fcf76" - bootstrap, peers := readIpfsConfig(&noSuchDir) + bootstrap, peers := readIpfsConfig(&noSuchDir, "") if bootstrap != nil { t.Error("expected nil bootstrap") } @@ -142,12 +142,12 @@ func TestReadIpfsConfig(t *testing.T) { tmpDir := makeConfig(t, testConfig) - bootstrap, peers = readIpfsConfig(nil) + bootstrap, peers = readIpfsConfig(nil, "") if bootstrap != nil || peers != nil { t.Fatal("expected nil ipfs config items") } - bootstrap, peers = readIpfsConfig(&tmpDir) + bootstrap, peers = readIpfsConfig(&tmpDir, "") if len(bootstrap) != 2 { t.Fatal("wrong number of bootstrap addresses") } @@ -189,7 +189,7 @@ func TestBadBootstrappingIpfsConfig(t *testing.T) { tmpDir := makeConfig(t, configBadBootstrap) - bootstrap, peers := readIpfsConfig(&tmpDir) + bootstrap, peers := readIpfsConfig(&tmpDir, "") if bootstrap != nil { t.Fatal("expected nil bootstrap") } @@ -219,7 +219,7 @@ func TestBadPeersIpfsConfig(t *testing.T) { tmpDir := makeConfig(t, configBadPeers) - bootstrap, peers := readIpfsConfig(&tmpDir) + bootstrap, peers := readIpfsConfig(&tmpDir, "") if peers != nil { t.Fatal("expected nil peers") } diff --git a/repo/fsrepo/migrations/migrations.go b/repo/fsrepo/migrations/migrations.go index 726870ea004..02738483e29 100644 --- a/repo/fsrepo/migrations/migrations.go +++ b/repo/fsrepo/migrations/migrations.go @@ -115,12 +115,12 @@ func ExeName(name string) string { // ReadMigrationConfig reads the Migration section of the IPFS config, avoiding // reading anything other than the Migration section. That way, we're free to // make arbitrary changes to all _other_ sections in migrations. -func ReadMigrationConfig(repoRoot string) (*config.Migration, error) { +func ReadMigrationConfig(repoRoot string, userConfigFile string) (*config.Migration, error) { var cfg struct { Migration config.Migration } - cfgPath, err := config.Filename(repoRoot) + cfgPath, err := config.Filename(repoRoot, userConfigFile) if err != nil { return nil, err } diff --git a/repo/fsrepo/migrations/migrations_test.go b/repo/fsrepo/migrations/migrations_test.go index 2472d4706aa..4fb75774793 100644 --- a/repo/fsrepo/migrations/migrations_test.go +++ b/repo/fsrepo/migrations/migrations_test.go @@ -221,7 +221,7 @@ var testConfig = ` func TestReadMigrationConfigDefaults(t *testing.T) { tmpDir := makeConfig(t, "{}") - cfg, err := ReadMigrationConfig(tmpDir) + cfg, err := ReadMigrationConfig(tmpDir, "") if err != nil { t.Fatal(err) } @@ -243,7 +243,7 @@ func TestReadMigrationConfigDefaults(t *testing.T) { func TestReadMigrationConfigErrors(t *testing.T) { tmpDir := makeConfig(t, `{"Migration": {"Keep": "badvalue"}}`) - _, err := ReadMigrationConfig(tmpDir) + _, err := ReadMigrationConfig(tmpDir, "") if err == nil { t.Fatal("expected error") } @@ -252,13 +252,13 @@ func TestReadMigrationConfigErrors(t *testing.T) { } os.RemoveAll(tmpDir) - _, err = ReadMigrationConfig(tmpDir) + _, err = ReadMigrationConfig(tmpDir, "") if err == nil { t.Fatal("expected error") } tmpDir = makeConfig(t, `}{`) - _, err = ReadMigrationConfig(tmpDir) + _, err = ReadMigrationConfig(tmpDir, "") if err == nil { t.Fatal("expected error") } @@ -267,7 +267,7 @@ func TestReadMigrationConfigErrors(t *testing.T) { func TestReadMigrationConfig(t *testing.T) { tmpDir := makeConfig(t, testConfig) - cfg, err := ReadMigrationConfig(tmpDir) + cfg, err := ReadMigrationConfig(tmpDir, "") if err != nil { t.Fatal(err) } From 447462b80100c29822058503a9c72b900e5265cb Mon Sep 17 00:00:00 2001 From: Lucas Molas Date: Thu, 24 Mar 2022 21:43:03 -0300 Subject: [PATCH 363/414] use --repo-dir in sharness/t0020-init.sh --- test/sharness/t0020-init.sh | 106 ++++++++++++++++++------------------ 1 file changed, 53 insertions(+), 53 deletions(-) diff --git a/test/sharness/t0020-init.sh b/test/sharness/t0020-init.sh index 55ae34eadb9..c1eb209a84c 100755 --- a/test/sharness/t0020-init.sh +++ b/test/sharness/t0020-init.sh @@ -8,23 +8,23 @@ test_description="Test init command" . lib/test-lib.sh -# test that ipfs fails to init if IPFS_PATH isn't writeable +# test that ipfs fails to init with BAD_IPFS_DIR that isn't writeable test_expect_success "create dir and change perms succeeds" ' - export IPFS_PATH="$(pwd)/.badipfs" && - mkdir "$IPFS_PATH" && - chmod 000 "$IPFS_PATH" + export BAD_IPFS_DIR="$(pwd)/.badipfs" && + mkdir "$BAD_IPFS_DIR" && + chmod 000 "$BAD_IPFS_DIR" ' test_expect_success "ipfs init fails" ' - test_must_fail ipfs init 2> init_fail_out + test_must_fail ipfs init --repo-dir "$BAD_IPFS_DIR" 2> init_fail_out ' # Under Windows/Cygwin the error message is different, # so we use the STD_ERR_MSG prereq. if test_have_prereq STD_ERR_MSG; then - init_err_msg="Error: error loading plugins: open $IPFS_PATH/config: permission denied" + init_err_msg="Error: error loading plugins: open $BAD_IPFS_DIR/config: permission denied" else - init_err_msg="Error: error loading plugins: open $IPFS_PATH/config: The system cannot find the path specified." + init_err_msg="Error: error loading plugins: open $BAD_IPFS_DIR/config: The system cannot find the path specified." fi test_expect_success "ipfs init output looks good" ' @@ -33,19 +33,19 @@ test_expect_success "ipfs init output looks good" ' ' test_expect_success "cleanup dir with bad perms" ' - chmod 775 "$IPFS_PATH" && - rmdir "$IPFS_PATH" + chmod 775 "$BAD_IPFS_DIR" && + rmdir "$BAD_IPFS_DIR" ' # test no repo error message # this applies to `ipfs add sth`, `ipfs refs ` test_expect_success "ipfs cat fails" ' - export IPFS_PATH="$(pwd)/.ipfs" && - test_must_fail ipfs cat Qmaa4Rw81a3a1VEx4LxB7HADUAXvZFhCoRdBzsMZyZmqHD 2> cat_fail_out + export IPFS_DIR="$(pwd)/.ipfs" && + test_must_fail ipfs cat --repo-dir "$IPFS_DIR" Qmaa4Rw81a3a1VEx4LxB7HADUAXvZFhCoRdBzsMZyZmqHD 2> cat_fail_out ' test_expect_success "ipfs cat no repo message looks good" ' - echo "Error: no IPFS repo found in $IPFS_PATH." > cat_fail_exp && + echo "Error: no IPFS repo found in $IPFS_DIR." > cat_fail_exp && echo "please run: '"'"'ipfs init'"'"'" >> cat_fail_exp && test_path_cmp cat_fail_exp cat_fail_out ' @@ -56,39 +56,39 @@ test_ipfs_init_flags() { # test that init succeeds test_expect_success "ipfs init succeeds" ' - export IPFS_PATH="$(pwd)/.ipfs" && - echo "IPFS_PATH: \"$IPFS_PATH\"" && + export IPFS_DIR="$(pwd)/.ipfs" && + echo "IPFS_DIR: \"$IPFS_DIR\"" && RSA_BITS="2048" && case $TEST_ALG in "rsa") - ipfs init --algorithm=rsa --bits="$RSA_BITS" >actual_init || test_fsh cat actual_init + ipfs init --repo-dir "$IPFS_DIR" --algorithm=rsa --bits="$RSA_BITS" >actual_init || test_fsh cat actual_init ;; "ed25519") - ipfs init --algorithm=ed25519 >actual_init || test_fsh cat actual_init + ipfs init --repo-dir "$IPFS_DIR" --algorithm=ed25519 >actual_init || test_fsh cat actual_init ;; *) - ipfs init --algorithm=rsa --bits="$RSA_BITS" >actual_init || test_fsh cat actual_init + ipfs init --repo-dir "$IPFS_DIR" --algorithm=rsa --bits="$RSA_BITS" >actual_init || test_fsh cat actual_init ;; esac ' test_expect_success ".ipfs/ has been created" ' - test -d ".ipfs" && - test -f ".ipfs/config" && - test -d ".ipfs/datastore" && - test -d ".ipfs/blocks" && + test -d "$IPFS_DIR" && + test -f "$IPFS_DIR/config" && + test -d "$IPFS_DIR/datastore" && + test -d "$IPFS_DIR/blocks" && test ! -f ._check_writeable || - test_fsh ls -al .ipfs + test_fsh ls -al $IPFS_DIR ' test_expect_success "ipfs config succeeds" ' echo /ipfs >expected_config && - ipfs config Mounts.IPFS >actual_config && + ipfs config --repo-dir "$IPFS_DIR" Mounts.IPFS >actual_config && test_cmp expected_config actual_config ' test_expect_success "ipfs peer id looks good" ' - PEERID=$(ipfs config Identity.PeerID) && + PEERID=$(ipfs config --repo-dir "$IPFS_DIR" Identity.PeerID) && test_check_peerid "$PEERID" ' @@ -97,13 +97,13 @@ test_ipfs_init_flags() { echo "generating $RSA_BITS-bit RSA keypair...done" >rsa_expected && echo "peer identity: $PEERID" >>rsa_expected && - echo "initializing IPFS node at $IPFS_PATH" >>rsa_expected && + echo "initializing IPFS node at $IPFS_DIR" >>rsa_expected && echo "to get started, enter:" >>rsa_expected && printf "\\n\\t$STARTFILE\\n\\n" >>rsa_expected && echo "generating ED25519 keypair...done" >ed25519_expected && echo "peer identity: $PEERID" >>ed25519_expected && - echo "initializing IPFS node at $IPFS_PATH" >>ed25519_expected && + echo "initializing IPFS node at $IPFS_DIR" >>ed25519_expected && echo "to get started, enter:" >>ed25519_expected && printf "\\n\\t$STARTFILE\\n\\n" >>ed25519_expected && @@ -125,26 +125,26 @@ test_ipfs_init_flags() { ' test_expect_success "clean up ipfs dir" ' - rm -rf "$IPFS_PATH" + rm -rf "$IPFS_DIR" ' test_expect_success "'ipfs init --empty-repo' succeeds" ' RSA_BITS="2048" && case $TEST_ALG in rsa) - ipfs init --algorithm=rsa --bits="$RSA_BITS" --empty-repo >actual_init + ipfs init --repo-dir "$IPFS_DIR" --algorithm=rsa --bits="$RSA_BITS" --empty-repo >actual_init ;; ed25519) - ipfs init --algorithm=ed25519 --empty-repo >actual_init + ipfs init --repo-dir "$IPFS_DIR" --algorithm=ed25519 --empty-repo >actual_init ;; *) - ipfs init --empty-repo >actual_init + ipfs init --repo-dir "$IPFS_DIR" --empty-repo >actual_init ;; esac ' test_expect_success "ipfs peer id looks good" ' - PEERID=$(ipfs config Identity.PeerID) && + PEERID=$(ipfs config --repo-dir "$IPFS_DIR" Identity.PeerID) && test_check_peerid "$PEERID" ' @@ -152,11 +152,11 @@ test_ipfs_init_flags() { echo "generating $RSA_BITS-bit RSA keypair...done" >rsa_expected && echo "peer identity: $PEERID" >>rsa_expected && - echo "initializing IPFS node at $IPFS_PATH" >>rsa_expected && + echo "initializing IPFS node at $IPFS_DIR" >>rsa_expected && echo "generating ED25519 keypair...done" >ed25519_expected && echo "peer identity: $PEERID" >>ed25519_expected && - echo "initializing IPFS node at $IPFS_PATH" >>ed25519_expected && + echo "initializing IPFS node at $IPFS_DIR" >>ed25519_expected && case $TEST_ALG in rsa) @@ -180,7 +180,7 @@ test_ipfs_init_flags() { ' test_expect_success "clean up ipfs dir" ' - rm -rf "$IPFS_PATH" + rm -rf "$IPFS_DIR" ' } test_ipfs_init_flags 'ed25519' @@ -190,70 +190,70 @@ test_ipfs_init_flags '' # test init profiles test_expect_success "'ipfs init --profile' with invalid profile fails" ' RSA_BITS="2048" && - test_must_fail ipfs init --profile=nonexistent_profile 2> invalid_profile_out + test_must_fail ipfs init --repo-dir "$IPFS_DIR" --profile=nonexistent_profile 2> invalid_profile_out EXPECT="Error: invalid configuration profile: nonexistent_profile" && grep "$EXPECT" invalid_profile_out ' test_expect_success "'ipfs init --profile' succeeds" ' RSA_BITS="2048" && - ipfs init --profile=server + ipfs init --repo-dir "$IPFS_DIR" --profile=server ' test_expect_success "'ipfs config Swarm.AddrFilters' looks good" ' - ipfs config Swarm.AddrFilters > actual_config && + ipfs config --repo-dir "$IPFS_DIR" Swarm.AddrFilters > actual_config && test $(cat actual_config | wc -l) = 18 ' test_expect_success "clean up ipfs dir" ' - rm -rf "$IPFS_PATH" + rm -rf "$IPFS_DIR" ' test_expect_success "'ipfs init --profile=test' succeeds" ' RSA_BITS="2048" && - ipfs init --profile=test + ipfs init --repo-dir "$IPFS_DIR" --profile=test ' test_expect_success "'ipfs config Bootstrap' looks good" ' - ipfs config Bootstrap > actual_config && + ipfs config --repo-dir "$IPFS_DIR" Bootstrap > actual_config && test $(cat actual_config) = "[]" ' test_expect_success "'ipfs config Addresses.API' looks good" ' - ipfs config Addresses.API > actual_config && + ipfs config --repo-dir "$IPFS_DIR" Addresses.API > actual_config && test $(cat actual_config) = "/ip4/127.0.0.1/tcp/0" ' test_expect_success "ipfs init from existing config succeeds" ' - export ORIG_PATH=$IPFS_PATH - export IPFS_PATH=$(pwd)/.ipfs-clone + export ORIG_PATH=$IPFS_DIR + export IPFS_DIR=$(pwd)/.ipfs-clone - ipfs init "$ORIG_PATH/config" && - ipfs config Addresses.API > actual_config && + ipfs init --repo-dir "$IPFS_DIR" "$ORIG_PATH/config" && + ipfs config --repo-dir "$IPFS_DIR" Addresses.API > actual_config && test $(cat actual_config) = "/ip4/127.0.0.1/tcp/0" ' -test_expect_success "clean up ipfs clone dir and reset IPFS_PATH" ' - rm -rf "$IPFS_PATH" && - export IPFS_PATH=$ORIG_PATH +test_expect_success "clean up ipfs clone dir and reset IPFS_DIR" ' + rm -rf "$IPFS_DIR" && + export IPFS_DIR=$ORIG_PATH ' test_expect_success "clean up ipfs dir" ' - rm -rf "$IPFS_PATH" + rm -rf "$IPFS_DIR" ' test_expect_success "'ipfs init --profile=lowpower' succeeds" ' RSA_BITS="2048" && - ipfs init --profile=lowpower + ipfs init --repo-dir "$IPFS_DIR" --profile=lowpower ' test_expect_success "'ipfs config Discovery.Routing' looks good" ' - ipfs config Routing.Type > actual_config && + ipfs config --repo-dir "$IPFS_DIR" Routing.Type > actual_config && test $(cat actual_config) = "dhtclient" ' test_expect_success "clean up ipfs dir" ' - rm -rf "$IPFS_PATH" + rm -rf "$IPFS_DIR" ' test_init_ipfs @@ -261,7 +261,7 @@ test_init_ipfs test_launch_ipfs_daemon test_expect_success "ipfs init should not run while daemon is running" ' - test_must_fail ipfs init 2> daemon_running_err && + test_must_fail ipfs init --repo-dir "$IPFS_DIR" 2> daemon_running_err && EXPECT="Error: ipfs daemon is running. please stop it to run this command" && grep "$EXPECT" daemon_running_err ' From e172ad23c2ada28eb48e34014e3ff3ce110e109d Mon Sep 17 00:00:00 2001 From: Lucas Molas Date: Thu, 24 Mar 2022 22:03:34 -0300 Subject: [PATCH 364/414] --config-file test in sharness/t0021-config.sh --- test/sharness/t0021-config.sh | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/test/sharness/t0021-config.sh b/test/sharness/t0021-config.sh index ee0e81988dd..5264908c73f 100755 --- a/test/sharness/t0021-config.sh +++ b/test/sharness/t0021-config.sh @@ -110,6 +110,13 @@ test_config_cmd() { grep "\"beep3\": false," actual ' + test_expect_success "'ipfs config show --config-file' works" ' + mv "$IPFS_PATH/config" "$IPFS_PATH/config-moved" && + ipfs config --config-file "$IPFS_PATH/config-moved" show >moved && + test_cmp moved actual && + mv "$IPFS_PATH/config-moved" "$IPFS_PATH/config" + ' + test_expect_success "setup for config replace test" ' cp "$IPFS_PATH/config" newconfig.json && sed -i"~" -e /PrivKey/d -e s/10GB/11GB/ newconfig.json && From 967bd69320abbe2a076c4ca66fec906398ad72e5 Mon Sep 17 00:00:00 2001 From: Gus Eggert Date: Mon, 25 Apr 2022 11:06:22 -0400 Subject: [PATCH 365/414] feat(tracing): use OpenTelemetry env vars where possible (#8875) This removes some of the env vars added in f855bfe6e, so that go-ipfs is as consistent with standard OpenTelemetry env vars as possible. --- go.mod | 24 +++-- go.sum | 154 +++++++++++++++++++-------- test/sharness/t0310-tracing.sh | 4 +- tracing/doc.go | 33 ++++-- tracing/file_exporter.go | 45 ++++++++ tracing/tracing.go | 183 ++++++++++++++++++--------------- 6 files changed, 289 insertions(+), 154 deletions(-) create mode 100644 tracing/file_exporter.go diff --git a/go.mod b/go.mod index 1b22e73de15..f642a07122e 100644 --- a/go.mod +++ b/go.mod @@ -100,27 +100,29 @@ require ( github.com/multiformats/go-multihash v0.1.0 github.com/opentracing/opentracing-go v1.2.0 github.com/pkg/errors v0.9.1 - github.com/prometheus/client_golang v1.11.0 - github.com/stretchr/testify v1.7.0 + github.com/prometheus/client_golang v1.12.1 + github.com/prometheus/common v0.33.0 // indirect + github.com/stretchr/testify v1.7.1 github.com/syndtr/goleveldb v1.0.0 github.com/wI2L/jsondiff v0.2.0 github.com/whyrusleeping/go-sysinfo v0.0.0-20190219211824-4a357d4b90b1 github.com/whyrusleeping/multiaddr-filter v0.0.0-20160516205228-e903e4adabd7 go.opencensus.io v0.23.0 - go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.27.0 - go.opentelemetry.io/otel v1.2.0 - go.opentelemetry.io/otel/exporters/jaeger v1.2.0 - go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.2.0 - go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp v1.2.0 - go.opentelemetry.io/otel/exporters/stdout/stdouttrace v1.2.0 - go.opentelemetry.io/otel/sdk v1.2.0 - go.opentelemetry.io/otel/trace v1.2.0 + go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.31.0 + go.opentelemetry.io/otel v1.6.3 + go.opentelemetry.io/otel/exporters/jaeger v1.6.3 + go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.6.3 + go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp v1.6.3 + go.opentelemetry.io/otel/exporters/stdout/stdouttrace v1.6.3 + go.opentelemetry.io/otel/exporters/zipkin v1.6.3 + go.opentelemetry.io/otel/sdk v1.6.3 + go.opentelemetry.io/otel/trace v1.6.3 go.uber.org/dig v1.14.0 go.uber.org/fx v1.16.0 go.uber.org/zap v1.21.0 golang.org/x/crypto v0.0.0-20210921155107-089bfa567519 golang.org/x/sync v0.0.0-20210220032951-036812b2e83c - golang.org/x/sys v0.0.0-20211025112917-711f33c9992c + golang.org/x/sys v0.0.0-20220408201424-a24fb2fb8a0f ) require ( diff --git a/go.sum b/go.sum index f185dd54a5e..f044baf4b2d 100644 --- a/go.sum +++ b/go.sum @@ -55,7 +55,9 @@ github.com/Kubuxu/go-os-helper v0.0.1/go.mod h1:N8B+I7vPCT80IcP58r50u4+gEEcsZETF github.com/OneOfOne/xxhash v1.2.2 h1:KMrpdQIwFcEqXDklaen+P1axHaj9BSKzvpUUfnHldSE= github.com/OneOfOne/xxhash v1.2.2/go.mod h1:HSdplMjZKSmBqAxg5vPj2TmRDmfkzw+cTzAElWljhcU= github.com/Shopify/sarama v1.19.0/go.mod h1:FVkBWblsNy7DGZRfXLU0O9RCGt5g3g3yEuWXgklEdEo= +github.com/Shopify/sarama v1.30.0/go.mod h1:zujlQQx1kzHsh4jfV1USnptCQrHAEZ2Hk8fTKCulPVs= github.com/Shopify/toxiproxy v2.1.4+incompatible/go.mod h1:OXgGpZ6Cli1/URJOF1DMxUHB2q5Ap20/P/eIdh4G0pI= +github.com/Shopify/toxiproxy/v2 v2.1.6-0.20210914104332-15ea381dcdae/go.mod h1:/cvHQkZ1fst0EmZnA5dFtiQdWCNCFYzb+uE2vqVgvx0= github.com/Stebalien/go-bitfield v0.0.1 h1:X3kbSSPUaJK60wV2hjOPZwmpljr6VGCqdq4cBLhbQBo= github.com/Stebalien/go-bitfield v0.0.1/go.mod h1:GNjFpasyUVkHMsfEOk8EFLJ9syQ6SI+XWrX9Wf2XH0s= github.com/VividCortex/gohistogram v1.0.0/go.mod h1:Pf5mBqqDxYaXu3hDrrU+w6nw50o/4+TcAqDqk/vUH7g= @@ -119,15 +121,16 @@ github.com/buger/jsonparser v0.0.0-20181115193947-bf1c66bbce23/go.mod h1:bbYlZJ7 github.com/casbin/casbin/v2 v2.1.2/go.mod h1:YcPU1XXisHhLzuxH9coDNf2FbKpjGlbCg3n9yuLkIJQ= github.com/cenkalti/backoff v2.2.1+incompatible h1:tNowT99t7UNflLxfYYSlKYsBpXdEet03Pg2g16Swow4= github.com/cenkalti/backoff v2.2.1+incompatible/go.mod h1:90ReRw6GdpyfrHakVjL/QHaoyV4aDUVVkXQJJJ3NXXM= -github.com/cenkalti/backoff/v4 v4.1.1 h1:G2HAfAmvm/GcKan2oOQpBXOd2tT2G57ZnZGWa1PxPBQ= -github.com/cenkalti/backoff/v4 v4.1.1/go.mod h1:scbssz8iZGpm3xbr14ovlUdkxfGXNInqkPWOWmG2CLw= +github.com/cenkalti/backoff/v4 v4.1.2 h1:6Yo7N8UP2K6LWZnW94DLVSSrbobcWdVzAYOisuDPIFo= +github.com/cenkalti/backoff/v4 v4.1.2/go.mod h1:scbssz8iZGpm3xbr14ovlUdkxfGXNInqkPWOWmG2CLw= github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU= github.com/ceramicnetwork/go-dag-jose v0.1.0 h1:yJ/HVlfKpnD3LdYP03AHyTvbm3BpPiz2oZiOeReJRdU= github.com/ceramicnetwork/go-dag-jose v0.1.0/go.mod h1:qYA1nYt0X8u4XoMAVoOV3upUVKtrxy/I670Dg5F0wjI= github.com/cespare/xxhash v1.1.0 h1:a6HrQnmkObjyL+Gs60czilIUGqrzKutQD6XZog3p+ko= github.com/cespare/xxhash v1.1.0/go.mod h1:XrSqR1VqqWfGrhpAt58auRo0WTKS1nRRg3ghfAqPWnc= -github.com/cespare/xxhash/v2 v2.1.1 h1:6MnRN8NT7+YBpUIWxHtefFZOKTAPgGjpQSxqLNn0+qY= github.com/cespare/xxhash/v2 v2.1.1/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= +github.com/cespare/xxhash/v2 v2.1.2 h1:YRXhKfTDauu4ajMg1TPgFO5jnlC2HCbmLXMcTG5cbYE= +github.com/cespare/xxhash/v2 v2.1.2/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= github.com/cheekybits/genny v1.0.0 h1:uGGa4nei+j20rOSeDeP5Of12XVm7TGUd4dJA9RDitfE= github.com/cheekybits/genny v1.0.0/go.mod h1:+tQajlRqAUrPI7DOSpB0XAqZYtQakVtB7wXkRAgjxjQ= github.com/cheggaaa/pb v1.0.29 h1:FckUN5ngEk2LpvuG0fw1GEFx6LtyY2pWI/Z2QgCnEYo= @@ -199,6 +202,7 @@ github.com/dustin/go-humanize v0.0.0-20171111073723-bb3d318650d4/go.mod h1:Htrtb github.com/dustin/go-humanize v1.0.0 h1:VSnTsYCnlFHaM2/igO1h6X3HA71jcobQuxemgkq4zYo= github.com/dustin/go-humanize v1.0.0/go.mod h1:HtrtbFcZ19U5GC7JDqmcUSB87Iq5E25KnS6fMYU6eOk= github.com/eapache/go-resiliency v1.1.0/go.mod h1:kFI+JgMyC7bLPUVY133qvEBtVayf5mFgVsvEsIPBvNs= +github.com/eapache/go-resiliency v1.2.0/go.mod h1:kFI+JgMyC7bLPUVY133qvEBtVayf5mFgVsvEsIPBvNs= github.com/eapache/go-xerial-snappy v0.0.0-20180814174437-776d5712da21/go.mod h1:+020luEh2TKB4/GOp8oxxtq0Daoen/Cii55CzbTV6DU= github.com/eapache/queue v1.1.0/go.mod h1:6eCeP0CKFpHLu8blIFXhExK/dRa7WDZfr6jVFPTqq+I= github.com/edsrzf/mmap-go v1.0.0/go.mod h1:YO35OhQPt3KJa3ryjFM5Bs14WD66h8eGKpfaBNrHW5M= @@ -225,6 +229,7 @@ github.com/flynn/go-shlex v0.0.0-20150515145356-3f9db97f8568/go.mod h1:xEzjJPgXI github.com/flynn/noise v0.0.0-20180327030543-2492fe189ae6/go.mod h1:1i71OnUq3iUe1ma7Lr6yG6/rjvM3emb6yoL7xLFzcVQ= github.com/flynn/noise v1.0.0 h1:DlTHqmzmvcEiKj+4RYo/imoswx/4r6iBlCMfVtrMXpQ= github.com/flynn/noise v1.0.0/go.mod h1:xbMo+0i6+IGbYdJhF31t2eR1BIU0CYc12+BNAKwUTag= +github.com/fortytw2/leaktest v1.3.0/go.mod h1:jDsjWgpAGjm2CA7WthBh/CdZYEPF31XHquHwclZch5g= github.com/francoispqt/gojay v1.2.13 h1:d2m3sFjloqoIUQU3TsHBgj6qg/BVGlTBeHDUmyJnXKk= github.com/francoispqt/gojay v1.2.13/go.mod h1:ehT5mTG4ua4581f1++1WLG0vPdaA9HaiDsoyrBGkyDY= github.com/franela/goblin v0.0.0-20200105215937-c9ffbefa60db/go.mod h1:7dvUGVsVBjqR7JHJk0brhHOZYGmfBYOrK0ZhYMEtBr4= @@ -249,15 +254,21 @@ github.com/go-gl/glfw/v3.3/glfw v0.0.0-20200222043503-6f7a984d4dc4/go.mod h1:tQ2 github.com/go-kit/kit v0.8.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as= github.com/go-kit/kit v0.9.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as= github.com/go-kit/kit v0.10.0/go.mod h1:xUsJbQ/Fp4kEt7AFgCuvyX4a71u8h9jB8tj/ORgOZ7o= -github.com/go-kit/log v0.1.0 h1:DGJh0Sm43HbOeYDNnVZFl8BvcYVvjD5bqYJvp0REbwQ= github.com/go-kit/log v0.1.0/go.mod h1:zbhenjAZHb184qTLMA9ZjW7ThYL0H2mk7Q6pNt4vbaY= +github.com/go-kit/log v0.2.0 h1:7i2K3eKTos3Vc0enKCfnVcgHh2olr/MyfboYq7cAcFw= +github.com/go-kit/log v0.2.0/go.mod h1:NwTd00d/i8cPZ3xOwwiv2PO5MOcx78fFErGNcVmBjv0= github.com/go-logfmt/logfmt v0.3.0/go.mod h1:Qt1PoO58o5twSAckw1HlFXLmHsOX5/0LbT9GBnD5lWE= github.com/go-logfmt/logfmt v0.4.0/go.mod h1:3RMwSq7FuexP4Kalkev3ejPJsZTpXXBr9+V4qmtdjCk= -github.com/go-logfmt/logfmt v0.5.0 h1:TrB8swr/68K7m9CcGut2g3UOihhbcbiMAYiuTXdEih4= github.com/go-logfmt/logfmt v0.5.0/go.mod h1:wCYkCAKZfumFQihp8CzCvQ3paCTfi41vtzG1KdI/P7A= +github.com/go-logfmt/logfmt v0.5.1 h1:otpy5pqBCBZ1ng9RQ0dPu4PN7ba75Y/aA+UpowDyNVA= +github.com/go-logfmt/logfmt v0.5.1/go.mod h1:WYhtIu8zTZfxdn5+rREduYbwxfcBr/Vr6KEVveWlfTs= github.com/go-logr/logr v0.4.0/go.mod h1:z6/tIYblkpsD+a4lm/fGIIU9mZ+XfAiaFtq7xTgseGU= +github.com/go-logr/logr v1.2.2/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A= +github.com/go-logr/logr v1.2.3 h1:2DntVwHkVopvECVRSlL5PSo9eG+cAkDCuckLubN+rq0= +github.com/go-logr/logr v1.2.3/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A= +github.com/go-logr/stdr v1.2.2 h1:hSWxHoqTgW2S2qGc0LTAI563KZ5YKYRhT3MFKZMbjag= +github.com/go-logr/stdr v1.2.2/go.mod h1:mMo/vtBO5dYbehREoey6XUKy/eSumjCCveDpRre4VKE= github.com/go-sql-driver/mysql v1.4.0/go.mod h1:zAC/RDZ24gD3HViQzih4MyKcchzm+sOG5ZlKdlhCg5w= -github.com/go-stack/stack v1.8.0 h1:5SgMzNM5HxrEjV0ww2lTmX6E2Izsfxas4+YHWRs3Lsk= github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY= github.com/go-task/slim-sprig v0.0.0-20210107165309-348f09dbbbc0 h1:p104kn46Q8WdvHunIJ9dAyjPVtrBPhSr3KT2yUst43I= github.com/go-task/slim-sprig v0.0.0-20210107165309-348f09dbbbc0/go.mod h1:fyg7847qk6SyHyPtNmDHnmrv/HOrqktSC+C9fM+CJOE= @@ -273,6 +284,8 @@ github.com/gogo/protobuf v1.3.1/go.mod h1:SlYgWuQ5SjCEi6WLHjHCa1yvBfUnHcTbrrZtXP github.com/gogo/protobuf v1.3.2 h1:Ov1cvc58UF3b5XjBnZv7+opcTcQFZebYjWzi34vdm4Q= github.com/gogo/protobuf v1.3.2/go.mod h1:P1XiOD3dCwIKUDQYPy72D8LYyHL2YPYrpS2s69NZV8Q= github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q= +github.com/golang/glog v1.0.0 h1:nfP3RFugxnNRyKgeWd4oI1nYvXpxrx8ck8ZrcizshdQ= +github.com/golang/glog v1.0.0/go.mod h1:EWib/APOK0SL3dFbYqvxE3UYd8E6s1ouQ7iEp/0LWV4= github.com/golang/groupcache v0.0.0-20160516000752-02826c3e7903/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= github.com/golang/groupcache v0.0.0-20190702054246-869f871628b6/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= github.com/golang/groupcache v0.0.0-20191027212112-611e8accdfc9/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= @@ -308,8 +321,9 @@ github.com/golang/protobuf v1.4.3/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw github.com/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaSAoJOfIk= github.com/golang/protobuf v1.5.2 h1:ROPKBNFfQgOUMifHyP+KYbvpjbdoFNs+aK7DXlji0Tw= github.com/golang/protobuf v1.5.2/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY= -github.com/golang/snappy v0.0.0-20180518054509-2e65f85255db h1:woRePGFeVFfLKN/pOkfl+p/TAqKOfFu+7KPlMVpok/w= github.com/golang/snappy v0.0.0-20180518054509-2e65f85255db/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q= +github.com/golang/snappy v0.0.4 h1:yAGX7huGHXlcLOEtBnF4w7FQwA26wojNCwOYAEhLjQM= +github.com/golang/snappy v0.0.4/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q= github.com/google/btree v0.0.0-20180813153112-4030bb1f1f0c/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ= github.com/google/btree v1.0.0/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ= github.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5aqRK0M= @@ -358,6 +372,9 @@ github.com/gopherjs/gopherjs v0.0.0-20190430165422-3e4dfb77656c/go.mod h1:wJfORR github.com/gorilla/context v1.1.1/go.mod h1:kBGZzfjB9CEq2AlWe17Uuf7NDRt0dE0s8S51q0aT7Yg= github.com/gorilla/mux v1.6.2/go.mod h1:1lud6UwP+6orDFRuTfBEV8e9/aOM/c4fVVCaMa2zaAs= github.com/gorilla/mux v1.7.3/go.mod h1:1lud6UwP+6orDFRuTfBEV8e9/aOM/c4fVVCaMa2zaAs= +github.com/gorilla/mux v1.8.0/go.mod h1:DVbg23sWSpFRCP0SfiEN6jmj59UnW/n46BH5rLB71So= +github.com/gorilla/securecookie v1.1.1/go.mod h1:ra0sb63/xPlUeL+yeDciTfxMRAA+MP+HVt/4epWDjd4= +github.com/gorilla/sessions v1.2.1/go.mod h1:dk2InVEVJ0sfLlnXv9EAgkf6ecYs/i80K/zI+bUmuGM= github.com/gorilla/websocket v0.0.0-20170926233335-4201258b820c/go.mod h1:E7qHFY5m1UJ88s3WnNqhKjPHQ0heANvMoAMk2YaljkQ= github.com/gorilla/websocket v1.4.0/go.mod h1:E7qHFY5m1UJ88s3WnNqhKjPHQ0heANvMoAMk2YaljkQ= github.com/gorilla/websocket v1.4.1/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE= @@ -370,6 +387,8 @@ github.com/grpc-ecosystem/grpc-gateway v1.5.0/go.mod h1:RSKVYQBd5MCa4OVpNdGskqpg github.com/grpc-ecosystem/grpc-gateway v1.9.5/go.mod h1:vNeuVxBJEsws4ogUvrchl83t/GYV9WGTSLVdBhOQFDY= github.com/grpc-ecosystem/grpc-gateway v1.16.0 h1:gmcG1KaJ57LophUzW0Hy8NmPhnMZb4M0+kPpLofRdBo= github.com/grpc-ecosystem/grpc-gateway v1.16.0/go.mod h1:BDjrQk3hbvj6Nolgz8mAMFbcEtjT1g+wF4CSlocrBnw= +github.com/grpc-ecosystem/grpc-gateway/v2 v2.7.0 h1:BZHcxBETFHIdVyhyEfOvn/RdU/QGdLI4y34qQGjGWO0= +github.com/grpc-ecosystem/grpc-gateway/v2 v2.7.0/go.mod h1:hgWBS7lorOAVIJEQMi4ZsPv9hVvWI6+ch50m39Pf2Ks= github.com/gxed/hashland/keccakpg v0.0.1/go.mod h1:kRzw3HkwxFU1mpmPP8v1WyQzwdGfmKFJ6tItnhQ67kU= github.com/gxed/hashland/murmur3 v0.0.1/go.mod h1:KjXop02n4/ckmZSnY2+HKcLud/tcmvhST0bie/0lS48= github.com/hannahhoward/cbor-gen-for v0.0.0-20200817222906-ea96cece81f1/go.mod h1:jvfsLIxk0fY/2BKSQ1xf2406AKA5dwMmKKv0ADcOfN8= @@ -391,6 +410,7 @@ github.com/hashicorp/go-sockaddr v1.0.0/go.mod h1:7Xibr9yA9JjQq1JpNB2Vw7kxv8xerX github.com/hashicorp/go-syslog v1.0.0/go.mod h1:qPfqrKkXGihmCqbJM2mZgkZGvKG1dFdvsLplgctolz4= github.com/hashicorp/go-uuid v1.0.0/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro= github.com/hashicorp/go-uuid v1.0.1/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro= +github.com/hashicorp/go-uuid v1.0.2/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro= github.com/hashicorp/go-version v1.2.0/go.mod h1:fltr4n8CU8Ke44wwGCBoEymUuxUHl09ZGVZPK5anwXA= github.com/hashicorp/go.net v0.0.1/go.mod h1:hjKkEWcCURg++eb33jQU7oqQcI9XDCnUzHA0oac0k90= github.com/hashicorp/golang-lru v0.5.0/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8= @@ -643,6 +663,12 @@ github.com/jbenet/goprocess v0.0.0-20160826012719-b497e2f366b8/go.mod h1:Ly/wlsj github.com/jbenet/goprocess v0.1.3/go.mod h1:5yspPrukOVuOLORacaBi858NqyClJPQxYZlqdZVfqY4= github.com/jbenet/goprocess v0.1.4 h1:DRGOFReOMqqDNXwW70QkacFW0YN9QnwLV0Vqk+3oU0o= github.com/jbenet/goprocess v0.1.4/go.mod h1:5yspPrukOVuOLORacaBi858NqyClJPQxYZlqdZVfqY4= +github.com/jcmturner/aescts/v2 v2.0.0/go.mod h1:AiaICIRyfYg35RUkr8yESTqvSy7csK90qZ5xfvvsoNs= +github.com/jcmturner/dnsutils/v2 v2.0.0/go.mod h1:b0TnjGOvI/n42bZa+hmXL+kFJZsFT7G4t3HTlQ184QM= +github.com/jcmturner/gofork v1.0.0/go.mod h1:MK8+TM0La+2rjBD4jE12Kj1pCCxK7d2LK/UM3ncEo0o= +github.com/jcmturner/goidentity/v6 v6.0.1/go.mod h1:X1YW3bgtvwAXju7V3LCIMpY0Gbxyjn/mY9zx4tFonSg= +github.com/jcmturner/gokrb5/v8 v8.4.2/go.mod h1:sb+Xq/fTY5yktf/VxLsE3wlfPqQjp0aWNYyvBVK62bc= +github.com/jcmturner/rpc/v2 v2.0.3/go.mod h1:VUJYCIDm3PVOEHw8sgt091/20OJjskO/YJki3ELg/Hc= github.com/jellevandenhooff/dkim v0.0.0-20150330215556-f50fe3d243e1/go.mod h1:E0B/fFc00Y+Rasa88328GlI/XbtyysCtTHZS8h7IrBU= github.com/jessevdk/go-flags v0.0.0-20141203071132-1679536dcc89/go.mod h1:4FA24M0QyGHXBuZZK/XkWh8h0e1EYbRYJSGM75WSRxI= github.com/jessevdk/go-flags v1.4.0/go.mod h1:4FA24M0QyGHXBuZZK/XkWh8h0e1EYbRYJSGM75WSRxI= @@ -655,6 +681,7 @@ github.com/json-iterator/go v1.1.7/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/u github.com/json-iterator/go v1.1.8/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4= github.com/json-iterator/go v1.1.10/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4= github.com/json-iterator/go v1.1.11/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4= +github.com/json-iterator/go v1.1.12/go.mod h1:e30LSqwooZae/UwlEbR2852Gd8hjQvJoHmT4TnhNGBo= github.com/jstemmer/go-junit-report v0.0.0-20190106144839-af01ea7f8024/go.mod h1:6v2b51hI/fHJwM22ozAgKL4VKDeJcHhJFhtBdhmNjmU= github.com/jstemmer/go-junit-report v0.9.1/go.mod h1:Brl9GWCQeLvo8nXZwPNNblvFj/XSXhF0NWZEnDohbsk= github.com/jtolds/gls v4.2.1+incompatible/go.mod h1:QJZ7F/aHp+rZTRtaJ1ow/lLfFfVYBRgL+9YlvaHOwJU= @@ -1141,6 +1168,7 @@ github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJ github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= github.com/modern-go/reflect2 v0.0.0-20180701023420-4b7aa43c6742/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0= github.com/modern-go/reflect2 v1.0.1/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0= +github.com/modern-go/reflect2 v1.0.2/go.mod h1:yWuevngMOJpCy52FWWMvUC8ws7m/LJsjYzDa0/r8luk= github.com/mr-tron/base58 v1.1.0/go.mod h1:xcD2VGqlgYjBdcBLw+TuYLr8afG+Hj8g2eTVqeSzSU8= github.com/mr-tron/base58 v1.1.1/go.mod h1:xcD2VGqlgYjBdcBLw+TuYLr8afG+Hj8g2eTVqeSzSU8= github.com/mr-tron/base58 v1.1.2/go.mod h1:BinMc/sQntlIE1frQmRFPUoPA1Zkr8VRgBdjWI2mNwc= @@ -1239,16 +1267,18 @@ github.com/onsi/ginkgo v1.12.0/go.mod h1:oUhWkIvk5aDxtKvDDuw8gItl8pKl42LzjC9KZE0 github.com/onsi/ginkgo v1.12.1/go.mod h1:zj2OWP4+oCPe1qIXoGWkgMRwljMUYCdkwsT2108oapk= github.com/onsi/ginkgo v1.14.0/go.mod h1:iSB4RoI2tjJc9BBv4NKIKWKya62Rps+oPG/Lv9klQyY= github.com/onsi/ginkgo v1.16.2/go.mod h1:CObGmKUOKaSC0RjmoAK7tKyn4Azo5P2IWuoMnvwxz1E= -github.com/onsi/ginkgo v1.16.4 h1:29JGrr5oVBm5ulCWet69zQkzWipVXIol6ygQUe/EzNc= github.com/onsi/ginkgo v1.16.4/go.mod h1:dX+/inL/fNMqNlz0e9LfyB9TswhZpCVdJM/Z6Vvnwo0= +github.com/onsi/ginkgo v1.16.5 h1:8xi0RTUf59SOSfEtZMvwTvXYMzG4gV23XVHOZiXNtnE= +github.com/onsi/ginkgo v1.16.5/go.mod h1:+E8gABHa3K6zRBolWtd+ROzc/U5bkGt0FwiG042wbpU= github.com/onsi/gomega v1.4.1/go.mod h1:C1qb7wdrVGGVU+Z6iS04AVkA3Q65CEZX59MT0QO5uiA= github.com/onsi/gomega v1.4.3/go.mod h1:ex+gbHU/CVuBBDIJjb2X0qEXbFg53c61hWP/1CpauHY= github.com/onsi/gomega v1.5.0/go.mod h1:ex+gbHU/CVuBBDIJjb2X0qEXbFg53c61hWP/1CpauHY= github.com/onsi/gomega v1.7.1/go.mod h1:XdKZgCCFLUoM/7CFJVPcG8C1xQ1AJ0vpAezJrB7JYyY= github.com/onsi/gomega v1.9.0/go.mod h1:Ho0h+IUsWyvy1OpqCwxlQ/21gkhVunqlU8fDGcoTdcA= github.com/onsi/gomega v1.10.1/go.mod h1:iN09h71vgCQne3DLsj+A5owkum+a2tYe+TOCB1ybHNo= -github.com/onsi/gomega v1.13.0 h1:7lLHu94wT9Ij0o6EWWclhu0aOh32VxhkwEJvzuWPeak= github.com/onsi/gomega v1.13.0/go.mod h1:lRk9szgn8TxENtWd0Tp4c3wjlRfMTMH27I+3Je41yGY= +github.com/onsi/gomega v1.16.0 h1:6gjqkI8iiRHMvdccRJM8rVKjCWk6ZIm6FTm3ddIe4/c= +github.com/onsi/gomega v1.16.0/go.mod h1:HnhC7FXeEQY45zxNK3PPoIUhzk/80Xly9PcubAlGdZY= github.com/op/go-logging v0.0.0-20160315200505-970db520ece7/go.mod h1:HzydrMdWErDVzsI23lYNej1Htcns9BCg93Dk0bBINWk= github.com/opencontainers/runtime-spec v1.0.2 h1:UfAcuLBJB9Coz72x1hgl8O5RVzTdNiaglX6v2DM6FI0= github.com/opencontainers/runtime-spec v1.0.2/go.mod h1:jwyrGlmzljRJv/Fgzds9SsS/C5hL+LL3ko9hs6T5lQ0= @@ -1263,6 +1293,8 @@ github.com/openzipkin/zipkin-go v0.1.1/go.mod h1:NtoC/o8u3JlF1lSlyPNswIbeQH9bJTm github.com/openzipkin/zipkin-go v0.1.6/go.mod h1:QgAqvLzwWbR/WpD4A3cGpPtJrZXNIiJc5AZX7/PBEpw= github.com/openzipkin/zipkin-go v0.2.1/go.mod h1:NaW6tEwdmWMaCDZzg8sh+IBNOxHMPnhQw8ySjnjRyN4= github.com/openzipkin/zipkin-go v0.2.2/go.mod h1:NaW6tEwdmWMaCDZzg8sh+IBNOxHMPnhQw8ySjnjRyN4= +github.com/openzipkin/zipkin-go v0.4.0 h1:CtfRrOVZtbDj8rt1WXjklw0kqqJQwICrCKmlfUuBUUw= +github.com/openzipkin/zipkin-go v0.4.0/go.mod h1:4c3sLeE8xjNqehmF5RpAFLPLJxXscc0R4l6Zg0P1tTQ= github.com/pact-foundation/pact-go v1.0.4/go.mod h1:uExwJY4kCzNPcHRj+hCR/HBbOOIwwtUjcrb0b5/5kLM= github.com/pascaldekloe/goe v0.0.0-20180627143212-57f6aae5913c/go.mod h1:lzWF7FIEvWOWxwDKqyGYQf6ZUaNfKdP144TG7ZOy1lc= github.com/pbnjay/memory v0.0.0-20210728143218-7b4eea64cf58 h1:onHthvaw9LFnH4t2DcNVpwGmV9E1BkGknEliJkfwQj0= @@ -1274,6 +1306,7 @@ github.com/petar/GoLLRB v0.0.0-20210522233825-ae3b015fd3e9 h1:1/WtZae0yGtPq+TI6+ github.com/petar/GoLLRB v0.0.0-20210522233825-ae3b015fd3e9/go.mod h1:x3N5drFsm2uilKKuuYo6LdyD8vZAW55sH/9w+pbo1sw= github.com/pierrec/lz4 v1.0.2-0.20190131084431-473cd7ce01a1/go.mod h1:3/3N9NVKO0jef7pBehbT1qWhCMrIgbYNnFAZCqQ5LRc= github.com/pierrec/lz4 v2.0.5+incompatible/go.mod h1:pdkljMzZIN41W+lC3N2tnIh5sFi+IEE17M5jbnwPHcY= +github.com/pierrec/lz4 v2.6.1+incompatible/go.mod h1:pdkljMzZIN41W+lC3N2tnIh5sFi+IEE17M5jbnwPHcY= github.com/pkg/errors v0.8.0/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4= @@ -1296,8 +1329,9 @@ github.com/prometheus/client_golang v1.3.0/go.mod h1:hJaj2vgQTGQmVCsAACORcieXFeD github.com/prometheus/client_golang v1.7.1/go.mod h1:PY5Wy2awLA44sXw4AOSfFBetzPP4j5+D6mVACh+pe2M= github.com/prometheus/client_golang v1.9.0/go.mod h1:FqZLKOZnGdFAhOK4nqGHa7D66IdsO+O441Eve7ptJDU= github.com/prometheus/client_golang v1.10.0/go.mod h1:WJM3cc3yu7XKBKa/I8WeZm+V3eltZnBwfENSU7mdogU= -github.com/prometheus/client_golang v1.11.0 h1:HNkLOAEQMIDv/K+04rukrLx6ch7msSRwf3/SASFAGtQ= github.com/prometheus/client_golang v1.11.0/go.mod h1:Z6t4BnS23TR94PD6BsDNk8yVqroYurpAkEiz0P2BEV0= +github.com/prometheus/client_golang v1.12.1 h1:ZiaPsmm9uiBeaSMRznKsCDNtPCS0T3JVDGF+06gjBzk= +github.com/prometheus/client_golang v1.12.1/go.mod h1:3Z9XVyYiZYEO+YQWt3RD2R3jrbd179Rt297l4aS6nDY= github.com/prometheus/client_model v0.0.0-20180712105110-5c3871d89910/go.mod h1:MbSGuTsp3dbXC40dX6PRTWyKYBIrTGTE9sqQNg2J8bo= github.com/prometheus/client_model v0.0.0-20190115171406-56726106282f/go.mod h1:MbSGuTsp3dbXC40dX6PRTWyKYBIrTGTE9sqQNg2J8bo= github.com/prometheus/client_model v0.0.0-20190129233127-fd36f4220a90/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= @@ -1315,8 +1349,10 @@ github.com/prometheus/common v0.15.0/go.mod h1:U+gB1OBLb1lF3O42bTCL+FK18tX9Oar16 github.com/prometheus/common v0.18.0/go.mod h1:U+gB1OBLb1lF3O42bTCL+FK18tX9Oar16Clt/msog/s= github.com/prometheus/common v0.26.0/go.mod h1:M7rCNAaPfAosfx8veZJCuw84e35h3Cfd9VFqTh1DIvc= github.com/prometheus/common v0.28.0/go.mod h1:vu+V0TpY+O6vW9J44gczi3Ap/oXXR10b+M/gUGO4Hls= -github.com/prometheus/common v0.30.0 h1:JEkYlQnpzrzQFxi6gnukFPdQ+ac82oRhzMcIduJu/Ug= github.com/prometheus/common v0.30.0/go.mod h1:vu+V0TpY+O6vW9J44gczi3Ap/oXXR10b+M/gUGO4Hls= +github.com/prometheus/common v0.32.1/go.mod h1:vu+V0TpY+O6vW9J44gczi3Ap/oXXR10b+M/gUGO4Hls= +github.com/prometheus/common v0.33.0 h1:rHgav/0a6+uYgGdNt3jwz8FNSesO/Hsang3O0T9A5SE= +github.com/prometheus/common v0.33.0/go.mod h1:gB3sOl7P0TvJabZpLY5uQMpUqRCPPCyRLCZYc7JZTNE= github.com/prometheus/procfs v0.0.0-20180725123919-05ee40e3a273/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk= github.com/prometheus/procfs v0.0.0-20181005140218-185b4288413d/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk= github.com/prometheus/procfs v0.0.0-20181204211112-1dc9a6cbc91a/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk= @@ -1330,11 +1366,13 @@ github.com/prometheus/procfs v0.7.3 h1:4jVXhlkAyzOScmCkXBTOLRLTz8EeU+eyjrwB/EPq0 github.com/prometheus/procfs v0.7.3/go.mod h1:cz+aTbrPOrUb4q7XlbU9ygM+/jj0fzG6c1xBZuNvfVA= github.com/prometheus/statsd_exporter v0.21.0 h1:hA05Q5RFeIjgwKIYEdFd59xu5Wwaznf33yKI+pyX6T8= github.com/prometheus/statsd_exporter v0.21.0/go.mod h1:rbT83sZq2V+p73lHhPZfMc3MLCHmSHelCh9hSGYNLTQ= +github.com/rabbitmq/amqp091-go v1.1.0/go.mod h1:ogQDLSOACsLPsIq0NpbtiifNZi2YOz0VTJ0kHRghqbM= github.com/raulk/clock v1.1.0 h1:dpb29+UKMbLqiU/jqIJptgLR1nn23HLgMY0sTCDza5Y= github.com/raulk/clock v1.1.0/go.mod h1:3MpVxdZ/ODBQDxbN+kzshf5OSZwPjtMDx6BBXBmOeY0= github.com/raulk/go-watchdog v1.2.0 h1:konN75pw2BMmZ+AfuAm5rtFsWcJpKF3m02rKituuXNo= github.com/raulk/go-watchdog v1.2.0/go.mod h1:lzSbAl5sh4rtI8tYHU01BWIDzgzqaQLj6RcA1i4mlqI= github.com/rcrowley/go-metrics v0.0.0-20181016184325-3113b8401b8a/go.mod h1:bCqnVzQkZxMG4s8nGwiZ5l3QUCyqpo9Y+/ZMZ9VjZe4= +github.com/rcrowley/go-metrics v0.0.0-20201227073835-cf1acfcdf475/go.mod h1:bCqnVzQkZxMG4s8nGwiZ5l3QUCyqpo9Y+/ZMZ9VjZe4= github.com/rogpeppe/fastuuid v0.0.0-20150106093220-6724a57986af/go.mod h1:XWv6SoW27p1b0cqNHllgS5HIMJraePCO15w5zCzIWYg= github.com/rogpeppe/fastuuid v1.2.0/go.mod h1:jVj6XXZzXRy/MSR5jhDC/2q6DgLz+nrA6LYCDYWNEvQ= github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4= @@ -1417,8 +1455,9 @@ github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UV github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4= github.com/stretchr/testify v1.5.1/go.mod h1:5W2xD1RspED5o8YsWQXVCued0rvSQ+mT+I5cxcmMvtA= github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= -github.com/stretchr/testify v1.7.0 h1:nwc3DEeHmmLAfoZucVR881uASk0Mfjw8xYJ99tb5CcY= github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= +github.com/stretchr/testify v1.7.1 h1:5TQK59W5E3v0r2duFAb7P95B6hEeOyEnHRa8MjYSMTY= +github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= github.com/syndtr/goleveldb v1.0.0 h1:fBdIW9lB4Iz0n9khmH8w27SJ3QEJ7+IgjPEwGSZiFdE= github.com/syndtr/goleveldb v1.0.0/go.mod h1:ZVVdQEZoIme9iO1Ch2Jdy24qqXrMMOU6lpPAyBWyWuQ= github.com/tarm/serial v0.0.0-20180830185346-98f6abe2eb07/go.mod h1:kDXzergiv9cbyO7IOYJZWg1U88JhDg3PB6klq9Hg2pA= @@ -1438,6 +1477,7 @@ github.com/urfave/cli v1.20.0/go.mod h1:70zkFmudgCuE/ngEzBv17Jvp/497gISqfk5gWijb github.com/urfave/cli v1.22.1/go.mod h1:Gos4lmkARVdJ6EkW0WaNv/tZAAMe9V7XWyB60NtXRu0= github.com/urfave/cli v1.22.2/go.mod h1:Gos4lmkARVdJ6EkW0WaNv/tZAAMe9V7XWyB60NtXRu0= github.com/urfave/cli/v2 v2.0.0/go.mod h1:SE9GqnLQmjVa0iPEY0f1w3ygNIYcIJ0OKPMoW2caLfQ= +github.com/urfave/cli/v2 v2.3.0/go.mod h1:LJmUH05zAU44vOAcrfzZQKsZbVcdbOG8rtL3/XcUArI= github.com/viant/assertly v0.4.8/go.mod h1:aGifi++jvCrUaklKEKT0BU95igDNaqkvz+49uaYMPRU= github.com/viant/toolbox v0.24.0/go.mod h1:OxMCG57V0PXuIP2HNQrtJf2CjqdmbrOx5EkMILuUhzM= github.com/wI2L/jsondiff v0.2.0 h1:dE00WemBa1uCjrzQUUTE/17I6m5qAaN0EMFOg2Ynr/k= @@ -1476,6 +1516,9 @@ github.com/whyrusleeping/multiaddr-filter v0.0.0-20160516205228-e903e4adabd7/go. github.com/whyrusleeping/timecache v0.0.0-20160911033111-cfcb2f1abfee h1:lYbXeSvJi5zk5GLKVuid9TVjS9a0OmLIDKTfoZBL6Ow= github.com/whyrusleeping/timecache v0.0.0-20160911033111-cfcb2f1abfee/go.mod h1:m2aV4LZI4Aez7dP5PMyVKEHhUyEJ/RjmPEDOpDvudHg= github.com/x-cray/logrus-prefixed-formatter v0.5.2/go.mod h1:2duySbKsL6M18s5GU7VPsoEPHyzalCE06qoARUCeBBE= +github.com/xdg-go/pbkdf2 v1.0.0/go.mod h1:jrpuAogTd400dnrH08LKmI/xc1MbPOebTwRqcT5RDeI= +github.com/xdg-go/scram v1.0.2/go.mod h1:1WAq6h33pAW+iRreB34OORO2Nf7qel3VV3fjBj+hCSs= +github.com/xdg-go/stringprep v1.0.2/go.mod h1:8F9zXuvzgwmyT5DUm4GUfZGDdT3W+LCvS6+da4O5kxM= github.com/xiang90/probing v0.0.0-20190116061207-43a291ad63a2/go.mod h1:UETIi67q53MR2AWcXfiuqkDkRtnGDLqkBTpCHuJHxtU= github.com/xordataexchange/crypt v0.0.3-0.20170626215501-b2862e3d0a77/go.mod h1:aYKd//L2LvnjZzWKhF00oedf4jCCReLcmhLdhm1A27Q= github.com/yuin/goldmark v1.1.25/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= @@ -1496,36 +1539,42 @@ go.opencensus.io v0.22.3/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw= go.opencensus.io v0.22.4/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw= go.opencensus.io v0.23.0 h1:gqCw0LfLxScz8irSi8exQc7fyQ0fKQU/qnC/X8+V/1M= go.opencensus.io v0.23.0/go.mod h1:XItmlyltB5F7CS4xOC1DcqMoFqwtC6OG2xF7mCv7P7E= -go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.27.0 h1:0BgiNWjN7rUWO9HdjF4L12r8OW86QkVQcYmCjnayJLo= -go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.27.0/go.mod h1:bdvm3YpMxWAgEfQhtTBaVR8ceXPRuRBSQrvOBnIlHxc= +go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.31.0 h1:woM+Mb4d0A+Dxa3rYPenSN5ZeS9qHUvE8rlObiLRXTY= +go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.31.0/go.mod h1:PFmBsWbldL1kiWZk9+0LBZz2brhByaGsvp6pRICMlPE= go.opentelemetry.io/otel v0.20.0/go.mod h1:Y3ugLH2oa81t5QO+Lty+zXf8zC9L26ax4Nzoxm/dooo= -go.opentelemetry.io/otel v1.2.0 h1:YOQDvxO1FayUcT9MIhJhgMyNO1WqoduiyvQHzGN0kUQ= -go.opentelemetry.io/otel v1.2.0/go.mod h1:aT17Fk0Z1Nor9e0uisf98LrntPGMnk4frBO9+dkf69I= -go.opentelemetry.io/otel/exporters/jaeger v1.2.0 h1:C/5Egj3MJBXRJi22cSl07suqPqtZLnLFmH//OxETUEc= -go.opentelemetry.io/otel/exporters/jaeger v1.2.0/go.mod h1:KJLFbEMKTNPIfOxcg/WikIozEoKcPgJRz3Ce1vLlM8E= -go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.2.0 h1:xzbcGykysUh776gzD1LUPsNNHKWN0kQWDnJhn1ddUuk= -go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.2.0/go.mod h1:14T5gr+Y6s2AgHPqBMgnGwp04csUjQmYXFWPeiBoq5s= -go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.2.0 h1:VsgsSCDwOSuO8eMVh63Cd4nACMqgjpmAeJSIvVNneD0= -go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.2.0/go.mod h1:9mLBBnPRf3sf+ASVH2p9xREXVBvwib02FxcKnavtExg= -go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp v1.2.0 h1:j/jXNzS6Dy0DFgO/oyCvin4H7vTQBg2Vdi6idIzWhCI= -go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp v1.2.0/go.mod h1:k5GnE4m4Jyy2DNh6UAzG6Nml51nuqQyszV7O1ksQAnE= -go.opentelemetry.io/otel/exporters/stdout/stdouttrace v1.2.0 h1:OiYdrCq1Ctwnovp6EofSPwlp5aGy4LgKNbkg7PtEUw8= -go.opentelemetry.io/otel/exporters/stdout/stdouttrace v1.2.0/go.mod h1:DUFCmFkXr0VtAHl5Zq2JRx24G6ze5CAq8YfdD36RdX8= -go.opentelemetry.io/otel/internal/metric v0.25.0 h1:w/7RXe16WdPylaIXDgcYM6t/q0K5lXgSdZOEbIEyliE= -go.opentelemetry.io/otel/internal/metric v0.25.0/go.mod h1:Nhuw26QSX7d6n4duoqAFi5KOQR4AuzyMcl5eXOgwxtc= +go.opentelemetry.io/otel v1.6.0/go.mod h1:bfJD2DZVw0LBxghOTlgnlI0CV3hLDu9XF/QKOUXMTQQ= +go.opentelemetry.io/otel v1.6.1/go.mod h1:blzUabWHkX6LJewxvadmzafgh/wnvBSDBdOuwkAtrWQ= +go.opentelemetry.io/otel v1.6.3 h1:FLOfo8f9JzFVFVyU+MSRJc2HdEAXQgm7pIv2uFKRSZE= +go.opentelemetry.io/otel v1.6.3/go.mod h1:7BgNga5fNlF/iZjG06hM3yofffp0ofKCDwSXx1GC4dI= +go.opentelemetry.io/otel/exporters/jaeger v1.6.3 h1:7tvBU1Ydbzq080efuepYYqC1Pv3/vOFBgCSrxLb24d0= +go.opentelemetry.io/otel/exporters/jaeger v1.6.3/go.mod h1:YgX3eZWbJzgrNyNHCK0otGreAMBTIAcObtZS2VRi6sU= +go.opentelemetry.io/otel/exporters/otlp/internal/retry v1.6.3 h1:nAmg1WgsUXoXf46dJG9eS/AzOcvkCTK4xJSUYpWyHYg= +go.opentelemetry.io/otel/exporters/otlp/internal/retry v1.6.3/go.mod h1:NEu79Xo32iVb+0gVNV8PMd7GoWqnyDXRlj04yFjqz40= +go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.6.3 h1:4/UjHWMVVc5VwX/KAtqJOHErKigMCH8NexChMuanb/o= +go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.6.3/go.mod h1:UJmXdiVVBaZ63umRUTwJuCMAV//GCMvDiQwn703/GoY= +go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.6.3 h1:leYDq5psbM3K4QNcZ2juCj30LjUnvxjuYQj1mkGjXFM= +go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.6.3/go.mod h1:ycItY/esVj8c0dKgYTOztTERXtPzcfDU/0o8EdwCjoA= +go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp v1.6.3 h1:ufVuVt/g16GZ/yDOyp+AcCGebGX8u4z7kDRuwEX0DkA= +go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp v1.6.3/go.mod h1:S18p8VK4KRHHyAg5rH3iUnJUcRvIUg9xwIWtq1MWibM= +go.opentelemetry.io/otel/exporters/stdout/stdouttrace v1.6.3 h1:uSApZ0WGBOrEMNp0rtX1jtpYBh5CvktueAEHTWfLOtk= +go.opentelemetry.io/otel/exporters/stdout/stdouttrace v1.6.3/go.mod h1:LhMjYbVawqjXUIRbAT2CFuWtuQVxTPL8WEtxB/Iyg5Y= +go.opentelemetry.io/otel/exporters/zipkin v1.6.3 h1:5BzTuSYCahVIsRlxZjJO23WUsJjq/q70TnmNZz5Klk8= +go.opentelemetry.io/otel/exporters/zipkin v1.6.3/go.mod h1:JRfrU4shvi54xFL5KA9ftJv7El3FMMpkz3V2S8aZ/q0= go.opentelemetry.io/otel/metric v0.20.0/go.mod h1:598I5tYlH1vzBjn+BTuhzTCSb/9debfNp6R3s7Pr1eU= -go.opentelemetry.io/otel/metric v0.25.0 h1:7cXOnCADUsR3+EOqxPaSKwhEuNu0gz/56dRN1hpIdKw= -go.opentelemetry.io/otel/metric v0.25.0/go.mod h1:E884FSpQfnJOMMUaq+05IWlJ4rjZpk2s/F1Ju+TEEm8= +go.opentelemetry.io/otel/metric v0.28.0 h1:o5YNh+jxACMODoAo1bI7OES0RUW4jAMae0Vgs2etWAQ= +go.opentelemetry.io/otel/metric v0.28.0/go.mod h1:TrzsfQAmQaB1PDcdhBauLMk7nyyg9hm+GoQq/ekE9Iw= go.opentelemetry.io/otel/oteltest v0.20.0/go.mod h1:L7bgKf9ZB7qCwT9Up7i9/pn0PWIa9FqQ2IQ8LoxiGnw= go.opentelemetry.io/otel/sdk v0.20.0/go.mod h1:g/IcepuwNsoiX5Byy2nNV0ySUF1em498m7hBWC279Yc= -go.opentelemetry.io/otel/sdk v1.2.0 h1:wKN260u4DesJYhyjxDa7LRFkuhH7ncEVKU37LWcyNIo= -go.opentelemetry.io/otel/sdk v1.2.0/go.mod h1:jNN8QtpvbsKhgaC6V5lHiejMoKD+V8uadoSafgHPx1U= +go.opentelemetry.io/otel/sdk v1.6.3 h1:prSHYdwCQOX5DrsEzxowH3nLhoAzEBdZhvrR79scfLs= +go.opentelemetry.io/otel/sdk v1.6.3/go.mod h1:A4iWF7HTXa+GWL/AaqESz28VuSBIcZ+0CV+IzJ5NMiQ= go.opentelemetry.io/otel/trace v0.20.0/go.mod h1:6GjCW8zgDjwGHGa6GkyeB8+/5vjT16gUEi0Nf1iBdgw= -go.opentelemetry.io/otel/trace v1.2.0 h1:Ys3iqbqZhcf28hHzrm5WAquMkDHNZTUkw7KHbuNjej0= -go.opentelemetry.io/otel/trace v1.2.0/go.mod h1:N5FLswTubnxKxOJHM7XZC074qpeEdLy3CgAVsdMucK0= +go.opentelemetry.io/otel/trace v1.6.0/go.mod h1:qs7BrU5cZ8dXQHBGxHMOxwME/27YH2qEp4/+tZLLwJE= +go.opentelemetry.io/otel/trace v1.6.1/go.mod h1:RkFRM1m0puWIq10oxImnGEduNBzxiN7TXluRBtE+5j0= +go.opentelemetry.io/otel/trace v1.6.3 h1:IqN4L+5b0mPNjdXIiZ90Ni4Bl5BRkDQywePLWemd9bc= +go.opentelemetry.io/otel/trace v1.6.3/go.mod h1:GNJQusJlUgZl9/TQBPKU/Y/ty+0iVB5fjhKeJGZPGFs= go.opentelemetry.io/proto/otlp v0.7.0/go.mod h1:PqfVotwruBrMGOCsRd/89rSnXhoiJIqeYNgFYFoEGnI= -go.opentelemetry.io/proto/otlp v0.10.0 h1:n7brgtEbDvXEgGyKKo8SobKT1e9FewlDtXzkVP5djoE= -go.opentelemetry.io/proto/otlp v0.10.0/go.mod h1:zG20xCK0szZ1xdokeSOwEcmlXu+x9kkdRe6N1DhKcfU= +go.opentelemetry.io/proto/otlp v0.15.0 h1:h0bKrvdrT/9sBwEJ6iWUqT/N/xPcS66bL4u3isneJ6w= +go.opentelemetry.io/proto/otlp v0.15.0/go.mod h1:H7XAot3MsfNsj7EXtrA2q5xSNQ10UqI405h3+duxN4U= go.uber.org/atomic v1.3.2/go.mod h1:gD2HeocX3+yG+ygLZcrzQJaqmWj9AIm7n08wl/qW/PE= go.uber.org/atomic v1.4.0/go.mod h1:gD2HeocX3+yG+ygLZcrzQJaqmWj9AIm7n08wl/qW/PE= go.uber.org/atomic v1.5.0/go.mod h1:sABNBOSYdrvTF6hTgEIbc7YasKWGhgEQZyfxyTvoXHQ= @@ -1541,8 +1590,9 @@ go.uber.org/fx v1.16.0/go.mod h1:OMoT5BnXcOaiexlpjtpE4vcAmzyDKyRs9TRYXCzamx8= go.uber.org/goleak v1.0.0/go.mod h1:8a7PlsEVH3e/a/GLqe5IIrQx6GzcnRmZEufDUTk4A7A= go.uber.org/goleak v1.1.10/go.mod h1:8a7PlsEVH3e/a/GLqe5IIrQx6GzcnRmZEufDUTk4A7A= go.uber.org/goleak v1.1.11-0.20210813005559-691160354723/go.mod h1:cwTWslyiVhfpKIDGSZEM2HlOvcqm+tG4zioyIeLoqMQ= -go.uber.org/goleak v1.1.11 h1:wy28qYRKZgnJTxGxvye5/wgWr1EKjmUDGYox5mGlRlI= go.uber.org/goleak v1.1.11/go.mod h1:cwTWslyiVhfpKIDGSZEM2HlOvcqm+tG4zioyIeLoqMQ= +go.uber.org/goleak v1.1.12 h1:gZAh5/EyT/HQwlpkCy6wTpqfH9H8Lz8zbm3dZh+OyzA= +go.uber.org/goleak v1.1.12/go.mod h1:cwTWslyiVhfpKIDGSZEM2HlOvcqm+tG4zioyIeLoqMQ= go.uber.org/multierr v1.1.0/go.mod h1:wR5kodmAFQ0UK8QlbwjlSNy0Z68gJhDJUG5sjR94q/0= go.uber.org/multierr v1.3.0/go.mod h1:VgVr7evmIr6uPjLBxg28wmKNXyqE9akIJ5XnfpiKl+4= go.uber.org/multierr v1.5.0/go.mod h1:FeouvMocqHpRaaGuG9EjoKcStLC43Zu/fmqdUMPcKYU= @@ -1590,12 +1640,14 @@ golang.org/x/crypto v0.0.0-20200510223506-06a226fb4e37/go.mod h1:LzIPMQfyMNhhGPh golang.org/x/crypto v0.0.0-20200602180216-279210d13fed/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= golang.org/x/crypto v0.0.0-20200820211705-5c72a883971a/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= +golang.org/x/crypto v0.0.0-20201112155050-0c6587e931a9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= golang.org/x/crypto v0.0.0-20210220033148-5ea612d1eb83/go.mod h1:jdWPYTVW3xRLrWPugEBEK3UY2ZEsg3UU495nc5E+M+I= golang.org/x/crypto v0.0.0-20210322153248-0c34fe9e7dc2/go.mod h1:T9bdIzuCu7OtxOm1hfPfRQxPLYneinmdGuTeoZ9dtd4= golang.org/x/crypto v0.0.0-20210506145944-38f3c27a63bf/go.mod h1:P+XmwS30IXTQdn5tA2iutPOUgjI07+tq3H3K9MVA1s8= golang.org/x/crypto v0.0.0-20210513164829-c07d793c2f9a/go.mod h1:P+XmwS30IXTQdn5tA2iutPOUgjI07+tq3H3K9MVA1s8= golang.org/x/crypto v0.0.0-20210711020723-a769d52b0f97/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= golang.org/x/crypto v0.0.0-20210813211128-0a44fdfbc16e/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= +golang.org/x/crypto v0.0.0-20210920023735-84f357641f63/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= golang.org/x/crypto v0.0.0-20210921155107-089bfa567519 h1:7I4JAnoQBe7ZtJcBaYHi5UtiO8tQHbUSXxL+pnGRANg= golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= @@ -1691,8 +1743,11 @@ golang.org/x/net v0.0.0-20210423184538-5f58ad60dda6/go.mod h1:OJAsFXCWl8Ukc7SiCT golang.org/x/net v0.0.0-20210428140749-89ef3d95e781/go.mod h1:OJAsFXCWl8Ukc7SiCT/9KSuxbyM7479/AVlXFRxuMCk= golang.org/x/net v0.0.0-20210505024714-0287a6fb4125/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= golang.org/x/net v0.0.0-20210525063256-abc453219eb5/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= -golang.org/x/net v0.0.0-20210813160813-60bc85c4be6d h1:LO7XpTYMwTqxjLcGWPijK3vRXg1aWdlNOVOHRq45d7c= golang.org/x/net v0.0.0-20210813160813-60bc85c4be6d/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= +golang.org/x/net v0.0.0-20210917221730-978cfadd31cf/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= +golang.org/x/net v0.0.0-20220127200216-cd36cc0744dd/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk= +golang.org/x/net v0.0.0-20220225172249-27dd8689420f h1:oA4XRj0qtSt8Yo1Zms0CUlsT3KG69V2UGQWPBxujDmc= +golang.org/x/net v0.0.0-20220225172249-27dd8689420f/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk= golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= golang.org/x/oauth2 v0.0.0-20181017192945-9dcd33a902f4/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= golang.org/x/oauth2 v0.0.0-20181203162652-d668ce993890/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= @@ -1700,8 +1755,10 @@ golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4Iltr golang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= golang.org/x/oauth2 v0.0.0-20191202225959-858c2ad4c8b6/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= golang.org/x/oauth2 v0.0.0-20200107190931-bf48bf16ab8d/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= -golang.org/x/oauth2 v0.0.0-20210514164344-f6687ab2804c h1:pkQiBZBvdos9qq4wBAHqlzuZHEXo07pqV06ef90u1WI= golang.org/x/oauth2 v0.0.0-20210514164344-f6687ab2804c/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= +golang.org/x/oauth2 v0.0.0-20211104180415-d3ed0bb246c8/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= +golang.org/x/oauth2 v0.0.0-20220223155221-ee480838109b h1:clP8eMhB30EHdc0bd2Twtq6kgU7yl5ub2cQLSdrv1Dg= +golang.org/x/oauth2 v0.0.0-20220223155221-ee480838109b/go.mod h1:DAh4E804XQdzx2j+YRIaUnCqCV2RuMz24cGBJ5QYIrc= golang.org/x/perf v0.0.0-20180704124530-6e6d33e29852/go.mod h1:JLpeXjPJfIyPr5TlbXLkXWLhP8nz10XfvxElABhCtcw= golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= @@ -1800,16 +1857,20 @@ golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBc golang.org/x/sys v0.0.0-20210630005230-0f9fa26af87c/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20210816183151-1e6c022a8912/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20210903071746-97244b99971b/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20211025112917-711f33c9992c h1:i4MLwL3EbCgobekQtkVW94UBSPLMadfEGtKq+CAFsEU= -golang.org/x/sys v0.0.0-20211025112917-711f33c9992c/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20211216021012-1d35b9e2eb4e/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220114195835-da31bd327af9/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220408201424-a24fb2fb8a0f h1:8w7RhxzTVgUzw/AH/9mUV5q0vMgy40SQRursCcfmkCw= +golang.org/x/sys v0.0.0-20220408201424-a24fb2fb8a0f/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/term v0.0.0-20201117132131-f5c789dd3221/go.mod h1:Nr5EML6q2oocZ2LXRh80K7BxOlk5/8JxuGnuhpl+muw= -golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1 h1:v+OssWQX+hTHEmOBgwxdZxK4zHq3yOs8F9J7mk0PY8E= golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= +golang.org/x/term v0.0.0-20210927222741-03fcf44c2211 h1:JGgROgKl9N8DuW20oFS5gxc+lE67/N3FcwmBPMe7ArY= +golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8= golang.org/x/text v0.0.0-20170915032832-14c0d48ead0c/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.1-0.20180807135948-17ff2d5776d2/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk= golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= +golang.org/x/text v0.3.5/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/text v0.3.7 h1:olpwvP2KacW1ZWvsR7uQhoyTYvKAupfQrRGBFM352Gk= golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ= @@ -1945,8 +2006,9 @@ google.golang.org/genproto v0.0.0-20200526211855-cb27e3aa2013/go.mod h1:NbSheEEY google.golang.org/genproto v0.0.0-20200618031413-b414f8b61790/go.mod h1:jDfRM7FcilCzHH/e9qn6dsT145K34l5v+OpcnNgKAAA= google.golang.org/genproto v0.0.0-20200729003335-053ba62fc06f/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= google.golang.org/genproto v0.0.0-20200804131852-c06518451d9c/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= -google.golang.org/genproto v0.0.0-20200825200019-8632dd797987 h1:PDIOdWxZ8eRizhKa1AAvY53xsvLB1cWorMjslvY3VA8= google.golang.org/genproto v0.0.0-20200825200019-8632dd797987/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= +google.golang.org/genproto v0.0.0-20211118181313-81c1377c94b1 h1:b9mVrqYfq3P4bCdaLg1qtBnPzUYgglsIdjZkL/fQVOE= +google.golang.org/genproto v0.0.0-20211118181313-81c1377c94b1/go.mod h1:5CzLGKJ67TSI2B9POpiiyGha0AjJvZIUgRMt1dSmuhc= google.golang.org/grpc v1.14.0/go.mod h1:yo6s7OP7yaDglbqo1J04qKzAhqBH6lvTonzMVmEdcZw= google.golang.org/grpc v1.16.0/go.mod h1:0JHn/cJsOMiMfNA9+DeHDlAU7KAAB5GDlYFpa9MZMio= google.golang.org/grpc v1.17.0/go.mod h1:6QZJwpn2B+Zp71q/5VxRsJ6NXXVCE5NRUHRo+f3cWCs= @@ -1973,8 +2035,9 @@ google.golang.org/grpc v1.33.2/go.mod h1:JMHMWHQWaTccqQQlmk3MJZS+GWXOdAesneDmEnv google.golang.org/grpc v1.36.0/go.mod h1:qjiiYl8FncCW8feJPdyg3v6XW24KsRHe+dy9BAGRRjU= google.golang.org/grpc v1.40.0/go.mod h1:ogyxbiOoUXAkP+4+xa6PZSE9DZgIHtSpzjDTB9KAK34= google.golang.org/grpc v1.41.0/go.mod h1:U3l9uK9J0sini8mHphKoXyaqDA/8VyGnDee1zzIUK6k= -google.golang.org/grpc v1.42.0 h1:XT2/MFpuPFsEX2fWh3YQtHkZ+WYZFQRfaUgLZYj/p6A= google.golang.org/grpc v1.42.0/go.mod h1:k+4IHHFw41K8+bbowsex27ge2rCb65oeWqe4jJ590SU= +google.golang.org/grpc v1.45.0 h1:NEpgUqV3Z+ZjkqMsxMg11IaDrXY4RY6CQukSGK0uI1M= +google.golang.org/grpc v1.45.0/go.mod h1:lN7owxKUQEqMfSyQikvvk5tf/6zMPsrK+ONuO11+0rQ= google.golang.org/protobuf v0.0.0-20200109180630-ec00e32a8dfd/go.mod h1:DFci5gLYBciE7Vtevhsrf46CRTquxDuWsQurQQe4oz8= google.golang.org/protobuf v0.0.0-20200221191635-4d8936d0db64/go.mod h1:kwYJMbMJ01Woi6D6+Kah6886xMZcty6N08ah7+eCXa0= google.golang.org/protobuf v0.0.0-20200228230310-ab0ca4ff8a60/go.mod h1:cfTl7dwQJ+fmap5saPgwCLgHXTUD7jkjRqWcaiX5VyM= @@ -1987,8 +2050,9 @@ google.golang.org/protobuf v1.24.0/go.mod h1:r/3tXBNzIEhYS9I1OUVjXDlt8tc493IdKGj google.golang.org/protobuf v1.25.0/go.mod h1:9JNX74DMeImyA3h4bdi1ymwjUzf21/xIlbajtzgsN7c= google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw= google.golang.org/protobuf v1.26.0/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc= -google.golang.org/protobuf v1.27.1 h1:SnqbnDw1V7RiZcXPx5MEeqPv2s79L9i7BJUlG/+RurQ= google.golang.org/protobuf v1.27.1/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc= +google.golang.org/protobuf v1.28.0 h1:w43yiav+6bVFTBQFZX0r7ipe9JQ1QsbMgHwbBziscLw= +google.golang.org/protobuf v1.28.0/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I= gopkg.in/alecthomas/kingpin.v2 v2.2.6/go.mod h1:FMv+mEhP44yOT+4EoQTLFTRgOQ1FBLkstjWtayDeSgw= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= diff --git a/test/sharness/t0310-tracing.sh b/test/sharness/t0310-tracing.sh index bbc7cb1e1b6..42846c9d076 100755 --- a/test/sharness/t0310-tracing.sh +++ b/test/sharness/t0310-tracing.sh @@ -10,8 +10,8 @@ test_description="Test tracing" test_init_ipfs -export IPFS_TRACING=1 -export IPFS_TRACING_OTLP_GRPC=1 +export OTEL_TRACES_EXPORTER=otlp +export OTEL_EXPORTER_OTLP_PROTOCOL=grpc export OTEL_EXPORTER_OTLP_ENDPOINT=http://localhost:4317 cat < collector-config.yaml diff --git a/tracing/doc.go b/tracing/doc.go index d8ba6d9e9b9..a7b43f0ce2a 100644 --- a/tracing/doc.go +++ b/tracing/doc.go @@ -4,18 +4,15 @@ // NOTE: Tracing is currently experimental. Span names may change unexpectedly, spans may be removed, // and backwards-incompatible changes may be made to tracing configuration, options, and defaults. // -// go-ipfs uses OpenTelemetry as its tracing API, and when possible, standard OpenTelemetry environment -// variables can be used to configure it. Multiple exporters can also be installed simultaneously, -// including one that writes traces to a JSON file on disk. +// Tracing is configured through environment variables, as consistent with the OpenTelemetry spec as possible: // -// In general, tracing is configured through environment variables. The IPFS-specific environment variables are: +// https://github.com/open-telemetry/opentelemetry-specification/blob/main/specification/sdk-environment-variables.md // -// - IPFS_TRACING: enable tracing in go-ipfs -// - IPFS_TRACING_JAEGER: enable the Jaeger exporter -// - IPFS_TRACING_RATIO: the ratio of traces to export, defaults to 1 (export everything) -// - IPFS_TRACING_FILE: write traces to the given filename -// - IPFS_TRACING_OTLP_HTTP: enable the OTLP HTTP exporter -// - IPFS_TRACING_OTLP_GRPC: enable the OTLP gRPC exporter +// - OTEL_TRACES_EXPORTER: a comma-separated list of exporters +// - otlp +// - jaeger +// - zipkin +// - file // // Different exporters have their own set of environment variables, depending on the exporter. These are typically // standard environment variables. Some common ones: @@ -30,12 +27,25 @@ // // OTLP HTTP/gRPC: // +// - OTEL_EXPORTER_OTLP_PROTOCOL +// - one of [grpc, http/protobuf] +// - default: grpc // - OTEL_EXPORTER_OTLP_ENDPOINT // - OTEL_EXPORTER_OTLP_CERTIFICATE // - OTEL_EXPORTER_OTLP_HEADERS // - OTEL_EXPORTER_OTLP_COMPRESSION // - OTEL_EXPORTER_OTLP_TIMEOUT // +// Zipkin: +// +// - OTEL_EXPORTER_ZIPKIN_ENDPOINT +// +// File: +// +// - OTEL_EXPORTER_FILE_PATH +// - file path to write JSON traces +// - default: `$PWD/traces.json` +// // For example, if you run a local IPFS daemon, you can use the jaegertracing/all-in-one Docker image to run // a full Jaeger stack and configure go-ipfs to publish traces to it: // @@ -47,10 +57,11 @@ // -p 5778:5778 \ // -p 16686:16686 \ // -p 14268:14268 \ +// -p 14269:14269 \ // -p 14250:14250 \ // -p 9411:9411 \ // jaegertracing/all-in-one -// IPFS_TRACING=1 IPFS_TRACING_JAEGER=1 ipfs daemon +// OTEL_TRACES_EXPORTER=jaeger ipfs daemon // // In this example the Jaeger UI is available at http://localhost:16686. // diff --git a/tracing/file_exporter.go b/tracing/file_exporter.go new file mode 100644 index 00000000000..32ca20ee274 --- /dev/null +++ b/tracing/file_exporter.go @@ -0,0 +1,45 @@ +package tracing + +import ( + "context" + "fmt" + "os" + + "go.opentelemetry.io/otel/exporters/stdout/stdouttrace" + "go.opentelemetry.io/otel/sdk/trace" +) + +// fileExporter wraps a file-writing exporter and closes the file when the exporter is shutdown. +type fileExporter struct { + file *os.File + writerExporter *stdouttrace.Exporter +} + +func newFileExporter(file string) (*fileExporter, error) { + f, err := os.OpenFile(file, os.O_RDWR|os.O_CREATE|os.O_APPEND, 0666) + if err != nil { + return nil, fmt.Errorf("opening '%s' for OpenTelemetry file exporter: %w", file, err) + } + stdoutExporter, err := stdouttrace.New(stdouttrace.WithWriter(f)) + if err != nil { + return nil, err + } + return &fileExporter{ + writerExporter: stdoutExporter, + file: f, + }, nil +} + +func (e *fileExporter) ExportSpans(ctx context.Context, spans []trace.ReadOnlySpan) error { + return e.writerExporter.ExportSpans(ctx, spans) +} + +func (e *fileExporter) Shutdown(ctx context.Context) error { + if err := e.writerExporter.Shutdown(ctx); err != nil { + return err + } + if err := e.file.Close(); err != nil { + return fmt.Errorf("closing trace file: %w", err) + } + return nil +} diff --git a/tracing/tracing.go b/tracing/tracing.go index 6cc8f6ad98c..99b340236f5 100644 --- a/tracing/tracing.go +++ b/tracing/tracing.go @@ -4,105 +4,128 @@ import ( "context" "fmt" "os" - "strconv" + "path" + "strings" version "github.com/ipfs/go-ipfs" "go.opentelemetry.io/otel" "go.opentelemetry.io/otel/exporters/jaeger" "go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc" "go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp" - "go.opentelemetry.io/otel/exporters/stdout/stdouttrace" + "go.opentelemetry.io/otel/exporters/zipkin" "go.opentelemetry.io/otel/sdk/resource" "go.opentelemetry.io/otel/sdk/trace" semconv "go.opentelemetry.io/otel/semconv/v1.7.0" traceapi "go.opentelemetry.io/otel/trace" ) -var exporterBuilders = map[string]func(context.Context, string) (trace.SpanExporter, error){ - "IPFS_TRACING_JAEGER": func(ctx context.Context, s string) (trace.SpanExporter, error) { - return jaeger.New(jaeger.WithCollectorEndpoint()) - }, - "IPFS_TRACING_FILE": func(ctx context.Context, s string) (trace.SpanExporter, error) { - return newFileExporter(s) - }, - "IPFS_TRACING_OTLP_HTTP": func(ctx context.Context, s string) (trace.SpanExporter, error) { - return otlptracehttp.New(ctx) - }, - "IPFS_TRACING_OTLP_GRPC": func(ctx context.Context, s string) (trace.SpanExporter, error) { - return otlptracegrpc.New(ctx) - }, -} - -// fileExporter wraps a file-writing exporter and closes the file when the exporter is shutdown. -type fileExporter struct { - file *os.File - writerExporter *stdouttrace.Exporter -} - -var _ trace.SpanExporter = &fileExporter{} - -func newFileExporter(file string) (*fileExporter, error) { - f, err := os.OpenFile(file, os.O_RDWR|os.O_CREATE|os.O_APPEND, 0666) - if err != nil { - return nil, fmt.Errorf("opening %s: %w", file, err) - } - stdoutExporter, err := stdouttrace.New(stdouttrace.WithWriter(f)) - if err != nil { - return nil, err - } - return &fileExporter{ - writerExporter: stdoutExporter, - file: f, - }, nil +// shutdownTracerProvider adds a shutdown method for tracer providers. +// +// Note that this doesn't directly use the provided TracerProvider interface +// to avoid build breaking go-ipfs if new methods are added to it. +type shutdownTracerProvider interface { + Tracer(instrumentationName string, opts ...traceapi.TracerOption) traceapi.Tracer + Shutdown(ctx context.Context) error } -func (e *fileExporter) ExportSpans(ctx context.Context, spans []trace.ReadOnlySpan) error { - return e.writerExporter.ExportSpans(ctx, spans) -} +// noopShutdownTracerProvider adds a no-op Shutdown method to a TracerProvider. +type noopShutdownTracerProvider struct{ traceapi.TracerProvider } + +func (n *noopShutdownTracerProvider) Shutdown(ctx context.Context) error { return nil } + +func buildExporters(ctx context.Context) ([]trace.SpanExporter, error) { + // These env vars are standardized but not yet supported by opentelemetry-go. + // Once supported, we can remove most of this code. + // + // Specs: + // https://github.com/open-telemetry/opentelemetry-specification/blob/main/specification/sdk-environment-variables.md#exporter-selection + // https://github.com/open-telemetry/opentelemetry-specification/blob/main/specification/protocol/exporter.md + var exporters []trace.SpanExporter + for _, exporterStr := range strings.Split(os.Getenv("OTEL_TRACES_EXPORTER"), ",") { + switch exporterStr { + case "otlp": + protocol := "http/protobuf" + if v := os.Getenv("OTEL_EXPORTER_OTLP_PROTOCOL"); v != "" { + protocol = v + } + if v := os.Getenv("OTEL_EXPORTER_OTLP_TRACES_PROTOCOL"); v != "" { + protocol = v + } -func (e *fileExporter) Shutdown(ctx context.Context) error { - if err := e.writerExporter.Shutdown(ctx); err != nil { - return err - } - if err := e.file.Close(); err != nil { - return fmt.Errorf("closing trace file: %w", err) + switch protocol { + case "http/protobuf": + exporter, err := otlptracehttp.New(ctx) + if err != nil { + return nil, fmt.Errorf("building OTLP HTTP exporter: %w", err) + } + exporters = append(exporters, exporter) + case "grpc": + exporter, err := otlptracegrpc.New(ctx) + if err != nil { + return nil, fmt.Errorf("building OTLP gRPC exporter: %w", err) + } + exporters = append(exporters, exporter) + default: + return nil, fmt.Errorf("unknown or unsupported OTLP exporter '%s'", exporterStr) + } + case "jaeger": + exporter, err := jaeger.New(jaeger.WithCollectorEndpoint()) + if err != nil { + return nil, fmt.Errorf("building Jaeger exporter: %w", err) + } + exporters = append(exporters, exporter) + case "zipkin": + exporter, err := zipkin.New("") + if err != nil { + return nil, fmt.Errorf("building Zipkin exporter: %w", err) + } + exporters = append(exporters, exporter) + case "file": + // This is not part of the spec, but provided for convenience + // so that you don't have to setup a collector, + // and because we don't support the stdout exporter. + filePath := os.Getenv("OTEL_EXPORTER_FILE_PATH") + if filePath == "" { + cwd, err := os.Getwd() + if err != nil { + return nil, fmt.Errorf("finding working directory for the OpenTelemetry file exporter: %w", err) + } + filePath = path.Join(cwd, "traces.json") + } + exporter, err := newFileExporter(filePath) + if err != nil { + return nil, err + } + exporters = append(exporters, exporter) + case "none": + continue + case "": + continue + case "stdout": + // stdout is already used for certain kinds of logging, so we don't support this + fallthrough + default: + return nil, fmt.Errorf("unknown or unsupported exporter '%s'", exporterStr) + } } - return nil -} - -// noopShutdownTracerProvider wraps a TracerProvider with a no-op Shutdown method. -type noopShutdownTracerProvider struct { - tp traceapi.TracerProvider -} - -func (n *noopShutdownTracerProvider) Shutdown(ctx context.Context) error { - return nil -} -func (n *noopShutdownTracerProvider) Tracer(instrumentationName string, opts ...traceapi.TracerOption) traceapi.Tracer { - return n.tp.Tracer(instrumentationName, opts...) -} - -type ShutdownTracerProvider interface { - traceapi.TracerProvider - Shutdown(ctx context.Context) error + return exporters, nil } // NewTracerProvider creates and configures a TracerProvider. -func NewTracerProvider(ctx context.Context) (ShutdownTracerProvider, error) { - if os.Getenv("IPFS_TRACING") == "" { - return &noopShutdownTracerProvider{tp: traceapi.NewNoopTracerProvider()}, nil +func NewTracerProvider(ctx context.Context) (shutdownTracerProvider, error) { + exporters, err := buildExporters(ctx) + if err != nil { + return nil, err + } + if len(exporters) == 0 { + return &noopShutdownTracerProvider{TracerProvider: traceapi.NewNoopTracerProvider()}, nil } options := []trace.TracerProviderOption{} - traceRatio := 1.0 - if envRatio := os.Getenv("IPFS_TRACING_RATIO"); envRatio != "" { - r, err := strconv.ParseFloat(envRatio, 64) - if err == nil { - traceRatio = r - } + for _, exporter := range exporters { + options = append(options, trace.WithBatcher(exporter)) } - options = append(options, trace.WithSampler(trace.ParentBased(trace.TraceIDRatioBased(traceRatio)))) r, err := resource.Merge( resource.Default(), @@ -117,16 +140,6 @@ func NewTracerProvider(ctx context.Context) (ShutdownTracerProvider, error) { } options = append(options, trace.WithResource(r)) - for envVar, builder := range exporterBuilders { - if val := os.Getenv(envVar); val != "" { - exporter, err := builder(ctx, val) - if err != nil { - return nil, err - } - options = append(options, trace.WithBatcher(exporter)) - } - } - return trace.NewTracerProvider(options...), nil } From d4879a464b4afe3cef552b83873e0a70d7847d48 Mon Sep 17 00:00:00 2001 From: Gus Eggert Date: Wed, 27 Apr 2022 13:38:05 +0200 Subject: [PATCH 366/414] fix: build after Go 1.17 and Prometheus upgrades (#8916) * fix: go mod tidy * fix: update expected prometheus metrics Go 1.17 includes some new runtime metrics that are automatically published by the Prometheus client, so this adds them to the expected metric list so that the tests pass and we don't accidentally drop them in the future. --- go.mod | 38 ++++----- .../t0116-prometheus-data/prometheus_metrics | 79 +++++++++++++++++++ 2 files changed, 99 insertions(+), 18 deletions(-) diff --git a/go.mod b/go.mod index f642a07122e..ca15cc62fdb 100644 --- a/go.mod +++ b/go.mod @@ -135,8 +135,8 @@ require ( github.com/beorn7/perks v1.0.1 // indirect github.com/btcsuite/btcd v0.22.0-beta // indirect github.com/cenkalti/backoff v2.2.1+incompatible // indirect - github.com/cenkalti/backoff/v4 v4.1.1 // indirect - github.com/cespare/xxhash/v2 v2.1.1 // indirect + github.com/cenkalti/backoff/v4 v4.1.2 // indirect + github.com/cespare/xxhash/v2 v2.1.2 // indirect github.com/cheekybits/genny v1.0.0 // indirect github.com/containerd/cgroups v0.0.0-20201119153540-4cbc285b3327 // indirect github.com/crackcomm/go-gitignore v0.0.0-20170627025303-887ab5e44cc3 // indirect @@ -150,18 +150,20 @@ require ( github.com/felixge/httpsnoop v1.0.2 // indirect github.com/flynn/noise v1.0.0 // indirect github.com/francoispqt/gojay v1.2.13 // indirect - github.com/go-kit/log v0.1.0 // indirect - github.com/go-logfmt/logfmt v0.5.0 // indirect + github.com/go-kit/log v0.2.0 // indirect + github.com/go-logfmt/logfmt v0.5.1 // indirect + github.com/go-logr/logr v1.2.3 // indirect + github.com/go-logr/stdr v1.2.2 // indirect github.com/go-task/slim-sprig v0.0.0-20210107165309-348f09dbbbc0 // indirect github.com/godbus/dbus/v5 v5.0.4 // indirect github.com/gogo/protobuf v1.3.2 // indirect github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da // indirect github.com/golang/protobuf v1.5.2 // indirect - github.com/golang/snappy v0.0.0-20180518054509-2e65f85255db // indirect + github.com/golang/snappy v0.0.4 // indirect github.com/google/gopacket v1.1.19 // indirect github.com/google/uuid v1.3.0 // indirect github.com/gorilla/websocket v1.4.2 // indirect - github.com/grpc-ecosystem/grpc-gateway v1.16.0 // indirect + github.com/grpc-ecosystem/grpc-gateway/v2 v2.7.0 // indirect github.com/hannahhoward/go-pubsub v0.0.0-20200423002714-8d62886cc36e // indirect github.com/hashicorp/errwrap v1.0.0 // indirect github.com/hashicorp/golang-lru v0.5.4 // indirect @@ -220,13 +222,13 @@ require ( github.com/multiformats/go-multistream v0.2.2 // indirect github.com/multiformats/go-varint v0.0.6 // indirect github.com/nxadm/tail v1.4.8 // indirect - github.com/onsi/ginkgo v1.16.4 // indirect + github.com/onsi/ginkgo v1.16.5 // indirect github.com/opencontainers/runtime-spec v1.0.2 // indirect + github.com/openzipkin/zipkin-go v0.4.0 // indirect github.com/pbnjay/memory v0.0.0-20210728143218-7b4eea64cf58 // indirect github.com/pmezard/go-difflib v1.0.0 // indirect github.com/polydawn/refmt v0.0.0-20201211092308-30ac6d18308e // indirect github.com/prometheus/client_model v0.2.0 // indirect - github.com/prometheus/common v0.30.0 // indirect github.com/prometheus/procfs v0.7.3 // indirect github.com/prometheus/statsd_exporter v0.21.0 // indirect github.com/raulk/clock v1.1.0 // indirect @@ -244,25 +246,25 @@ require ( github.com/whyrusleeping/go-keyspace v0.0.0-20160322163242-5b898ac5add1 // indirect github.com/whyrusleeping/mdns v0.0.0-20190826153040-b9b60ed33aa9 // indirect github.com/whyrusleeping/timecache v0.0.0-20160911033111-cfcb2f1abfee // indirect - go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.2.0 // indirect - go.opentelemetry.io/otel/internal/metric v0.25.0 // indirect - go.opentelemetry.io/otel/metric v0.25.0 // indirect - go.opentelemetry.io/proto/otlp v0.10.0 // indirect + go.opentelemetry.io/otel/exporters/otlp/internal/retry v1.6.3 // indirect + go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.6.3 // indirect + go.opentelemetry.io/otel/metric v0.28.0 // indirect + go.opentelemetry.io/proto/otlp v0.15.0 // indirect go.uber.org/atomic v1.9.0 // indirect go.uber.org/multierr v1.7.0 // indirect go4.org v0.0.0-20200411211856-f5505b9728dd // indirect golang.org/x/exp v0.0.0-20210615023648-acb5c1269671 // indirect golang.org/x/mod v0.4.2 // indirect - golang.org/x/net v0.0.0-20210813160813-60bc85c4be6d // indirect - golang.org/x/oauth2 v0.0.0-20210514164344-f6687ab2804c // indirect - golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1 // indirect + golang.org/x/net v0.0.0-20220225172249-27dd8689420f // indirect + golang.org/x/oauth2 v0.0.0-20220223155221-ee480838109b // indirect + golang.org/x/term v0.0.0-20210927222741-03fcf44c2211 // indirect golang.org/x/text v0.3.7 // indirect golang.org/x/tools v0.1.5 // indirect golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1 // indirect google.golang.org/appengine v1.6.6 // indirect - google.golang.org/genproto v0.0.0-20200825200019-8632dd797987 // indirect - google.golang.org/grpc v1.42.0 // indirect - google.golang.org/protobuf v1.27.1 // indirect + google.golang.org/genproto v0.0.0-20211118181313-81c1377c94b1 // indirect + google.golang.org/grpc v1.45.0 // indirect + google.golang.org/protobuf v1.28.0 // indirect gopkg.in/square/go-jose.v2 v2.5.1 // indirect gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7 // indirect gopkg.in/yaml.v2 v2.4.0 // indirect diff --git a/test/sharness/t0116-prometheus-data/prometheus_metrics b/test/sharness/t0116-prometheus-data/prometheus_metrics index af41dc8a88d..dd358e82f4f 100644 --- a/test/sharness/t0116-prometheus-data/prometheus_metrics +++ b/test/sharness/t0116-prometheus-data/prometheus_metrics @@ -159,6 +159,9 @@ flatfs_datastore_sync_latency_seconds_bucket flatfs_datastore_sync_latency_seconds_count flatfs_datastore_sync_latency_seconds_sum flatfs_datastore_sync_total +go_gc_cycles_automatic_gc_cycles_total +go_gc_cycles_forced_gc_cycles_total +go_gc_cycles_total_gc_cycles_total go_gc_duration_seconds go_gc_duration_seconds go_gc_duration_seconds @@ -166,8 +169,70 @@ go_gc_duration_seconds go_gc_duration_seconds go_gc_duration_seconds_count go_gc_duration_seconds_sum +go_gc_heap_allocs_by_size_bytes_total_bucket +go_gc_heap_allocs_by_size_bytes_total_bucket +go_gc_heap_allocs_by_size_bytes_total_bucket +go_gc_heap_allocs_by_size_bytes_total_bucket +go_gc_heap_allocs_by_size_bytes_total_bucket +go_gc_heap_allocs_by_size_bytes_total_bucket +go_gc_heap_allocs_by_size_bytes_total_bucket +go_gc_heap_allocs_by_size_bytes_total_bucket +go_gc_heap_allocs_by_size_bytes_total_bucket +go_gc_heap_allocs_by_size_bytes_total_bucket +go_gc_heap_allocs_by_size_bytes_total_bucket +go_gc_heap_allocs_by_size_bytes_total_bucket +go_gc_heap_allocs_by_size_bytes_total_count +go_gc_heap_allocs_by_size_bytes_total_sum +go_gc_heap_allocs_bytes_total +go_gc_heap_allocs_objects_total +go_gc_heap_frees_by_size_bytes_total_bucket +go_gc_heap_frees_by_size_bytes_total_bucket +go_gc_heap_frees_by_size_bytes_total_bucket +go_gc_heap_frees_by_size_bytes_total_bucket +go_gc_heap_frees_by_size_bytes_total_bucket +go_gc_heap_frees_by_size_bytes_total_bucket +go_gc_heap_frees_by_size_bytes_total_bucket +go_gc_heap_frees_by_size_bytes_total_bucket +go_gc_heap_frees_by_size_bytes_total_bucket +go_gc_heap_frees_by_size_bytes_total_bucket +go_gc_heap_frees_by_size_bytes_total_bucket +go_gc_heap_frees_by_size_bytes_total_bucket +go_gc_heap_frees_by_size_bytes_total_count +go_gc_heap_frees_by_size_bytes_total_sum +go_gc_heap_frees_bytes_total +go_gc_heap_frees_objects_total +go_gc_heap_goal_bytes +go_gc_heap_objects_objects +go_gc_heap_tiny_allocs_objects_total +go_gc_pauses_seconds_total_bucket +go_gc_pauses_seconds_total_bucket +go_gc_pauses_seconds_total_bucket +go_gc_pauses_seconds_total_bucket +go_gc_pauses_seconds_total_bucket +go_gc_pauses_seconds_total_bucket +go_gc_pauses_seconds_total_bucket +go_gc_pauses_seconds_total_bucket +go_gc_pauses_seconds_total_bucket +go_gc_pauses_seconds_total_bucket +go_gc_pauses_seconds_total_bucket +go_gc_pauses_seconds_total_count +go_gc_pauses_seconds_total_sum go_goroutines go_info +go_memory_classes_heap_free_bytes +go_memory_classes_heap_objects_bytes +go_memory_classes_heap_released_bytes +go_memory_classes_heap_stacks_bytes +go_memory_classes_heap_unused_bytes +go_memory_classes_metadata_mcache_free_bytes +go_memory_classes_metadata_mcache_inuse_bytes +go_memory_classes_metadata_mspan_free_bytes +go_memory_classes_metadata_mspan_inuse_bytes +go_memory_classes_metadata_other_bytes +go_memory_classes_os_stacks_bytes +go_memory_classes_other_bytes +go_memory_classes_profiling_buckets_bytes +go_memory_classes_total_bytes go_memstats_alloc_bytes go_memstats_alloc_bytes_total go_memstats_buck_hash_sys_bytes @@ -192,6 +257,20 @@ go_memstats_other_sys_bytes go_memstats_stack_inuse_bytes go_memstats_stack_sys_bytes go_memstats_sys_bytes +go_sched_goroutines_goroutines +go_sched_latencies_seconds_bucket +go_sched_latencies_seconds_bucket +go_sched_latencies_seconds_bucket +go_sched_latencies_seconds_bucket +go_sched_latencies_seconds_bucket +go_sched_latencies_seconds_bucket +go_sched_latencies_seconds_bucket +go_sched_latencies_seconds_bucket +go_sched_latencies_seconds_bucket +go_sched_latencies_seconds_bucket +go_sched_latencies_seconds_bucket +go_sched_latencies_seconds_count +go_sched_latencies_seconds_sum go_threads ipfs_bitswap_active_block_tasks ipfs_bitswap_active_tasks From 74aff245d259546b65f214b413bc30172fd74a7d Mon Sep 17 00:00:00 2001 From: Gus Eggert Date: Thu, 28 Apr 2022 15:27:16 +0200 Subject: [PATCH 367/414] feat: persist limits to Swarm.ResourceMgr.Limits (#8901) * feat: persist limit changes to config This changes the "ipfs swarm limit" command so that when limit changes are applied via the command line, they are persisted to the repo config, so that they remain in effect when the daemon restarts. Any existing limit.json can be dropped into the IPFS config easily using something like: cat ~/.ipfs/config | jq ".Swarm.ResourceMgr.Limits = $(cat limit.json)" | sponge ~/.ipfs/config This also upgrades to Resource Manager v0.3.0, which exports the config schema so that we don't have to maintain our own copy of it. Co-authored-by: Marcin Rataj --- config/swarm.go | 46 +-------- core/commands/swarm.go | 8 +- core/node/libp2p/rcmgr.go | 106 +++++++++++++-------- go.mod | 2 +- go.sum | 3 +- test/sharness/t0139-swarm-rcmgr.sh | 147 +++++++++++++++++++++++------ 6 files changed, 198 insertions(+), 114 deletions(-) diff --git a/config/swarm.go b/config/swarm.go index be420298497..83f42a29543 100644 --- a/config/swarm.go +++ b/config/swarm.go @@ -1,5 +1,7 @@ package config +import rcmgr "github.com/libp2p/go-libp2p-resource-manager" + type SwarmConfig struct { // AddrFilters specifies a set libp2p addresses that we should never // dial or receive connections from. @@ -137,10 +139,8 @@ type ConnMgr struct { // type ResourceMgr struct { // Enables the Network Resource Manager feature - Enabled Flag `json:",omitempty"` - - /* TODO: decide if and how we want to expose limits in our config - Limits *ResourceMgrScopeConfig `json:",omitempty"` */ + Enabled Flag `json:",omitempty"` + Limits *rcmgr.BasicLimiterConfig `json:",omitempty"` } const ( @@ -150,41 +150,3 @@ const ( ResourceMgrProtocolScopePrefix = "proto:" ResourceMgrPeerScopePrefix = "peer:" ) - -/* TODO: decide if and how we want to expose limits in our config -type ResourceMgrLimitsConfig struct { - System *ResourceMgrScopeConfig `json:",omitempty"` - Transient *ResourceMgrScopeConfig `json:",omitempty"` - - ServiceDefault *ResourceMgrScopeConfig `json:",omitempty"` - ServicePeerDefault *ResourceMgrScopeConfig `json:",omitempty"` - Service map[string]ResourceMgrScopeConfig `json:",omitempty"` - ServicePeer map[string]ResourceMgrScopeConfig `json:",omitempty"` - - ProtocolDefault *ResourceMgrScopeConfig `json:",omitempty"` - ProtocolPeerDefault *ResourceMgrScopeConfig `json:",omitempty"` - Protocol map[string]ResourceMgrScopeConfig `json:",omitempty"` - ProtocolPeer map[string]ResourceMgrScopeConfig `json:",omitempty"` - - PeerDefault *ResourceMgrScopeConfig `json:",omitempty"` - Peer map[string]ResourceMgrScopeConfig `json:",omitempty"` - - Conn *ResourceMgrScopeConfig `json:",omitempty"` - Stream *ResourceMgrScopeConfig `json:",omitempty"` -} -*/ - -// libp2p Network Resource Manager config for a scope -type ResourceMgrScopeConfig struct { - Dynamic bool `json:",omitempty"` - // set if Dynamic is false - Memory int64 `json:",omitempty"` - // set if Dynamic is true - MemoryFraction float64 `json:",omitempty"` - MinMemory int64 `json:",omitempty"` - MaxMemory int64 `json:",omitempty"` - - Streams, StreamsInbound, StreamsOutbound int - Conns, ConnsInbound, ConnsOutbound int - FD int -} diff --git a/core/commands/swarm.go b/core/commands/swarm.go index 61f40e456aa..d6a3e8d696d 100644 --- a/core/commands/swarm.go +++ b/core/commands/swarm.go @@ -23,6 +23,7 @@ import ( cmds "github.com/ipfs/go-ipfs-cmds" inet "github.com/libp2p/go-libp2p-core/network" "github.com/libp2p/go-libp2p-core/peer" + rcmgr "github.com/libp2p/go-libp2p-resource-manager" ma "github.com/multiformats/go-multiaddr" madns "github.com/multiformats/go-multiaddr-dns" mamask "github.com/whyrusleeping/multiaddr-filter" @@ -380,8 +381,7 @@ It is possible to use this command to inspect and tweak limits at runtime: $ vi limit.json $ ipfs swarm limit system limit.json -Changes made via command line are discarded on node shutdown. -For permanent limits set Swarm.ResourceMgr.Limits in the $IPFS_PATH/config file. +Changes made via command line are persisted in the Swarm.ResourceMgr.Limits field of the $IPFS_PATH/config file. `}, Arguments: []cmds.Argument{ cmds.StringArg("scope", true, false, "scope of the limit"), @@ -401,7 +401,7 @@ For permanent limits set Swarm.ResourceMgr.Limits in the $IPFS_PATH/config file. // set scope limit to new values (when limit.json is passed as a second arg) if req.Files != nil { - var newLimit config.ResourceMgrScopeConfig + var newLimit rcmgr.BasicLimitConfig it := req.Files.Entries() if it.Next() { file := files.FileFromEntry(it) @@ -411,7 +411,7 @@ For permanent limits set Swarm.ResourceMgr.Limits in the $IPFS_PATH/config file. if err := json.NewDecoder(file).Decode(&newLimit); err != nil { return errors.New("failed to decode JSON as ResourceMgrScopeConfig") } - return libp2p.NetSetLimit(node.ResourceManager, scope, newLimit) + return libp2p.NetSetLimit(node.ResourceManager, node.Repo, scope, newLimit) } if err := it.Err(); err != nil { return fmt.Errorf("error opening limit JSON file: %w", err) diff --git a/core/node/libp2p/rcmgr.go b/core/node/libp2p/rcmgr.go index 511e3185242..938f5eb43f9 100644 --- a/core/node/libp2p/rcmgr.go +++ b/core/node/libp2p/rcmgr.go @@ -2,7 +2,6 @@ package libp2p import ( "context" - "errors" "fmt" "os" "path/filepath" @@ -27,7 +26,6 @@ var NoResourceMgrError = fmt.Errorf("missing ResourceMgr: make sure the daemon i func ResourceManager(cfg config.SwarmConfig) func(fx.Lifecycle, repo.Repo) (network.ResourceManager, Libp2pOpts, error) { return func(lc fx.Lifecycle, repo repo.Repo) (network.ResourceManager, Libp2pOpts, error) { - var limiter *rcmgr.BasicLimiter var manager network.ResourceManager var opts Libp2pOpts @@ -47,25 +45,18 @@ func ResourceManager(cfg config.SwarmConfig) func(fx.Lifecycle, repo.Repo) (netw repoPath, err := config.PathRoot() if err != nil { - return nil, opts, fmt.Errorf("error opening IPFS_PATH: %w", err) + return nil, opts, fmt.Errorf("opening IPFS_PATH: %w", err) } - // Create limiter: - // - parse $IPFS_PATH/limits.json if exists - // - use defaultLimits from rcmgr_defaults.go defaultLimits := adjustedDefaultLimits(cfg) - limitFilePath := filepath.Join(repoPath, NetLimitDefaultFilename) - limitFile, err := os.Open(limitFilePath) - switch { - case err == nil: - defer limitFile.Close() - limiter, err = rcmgr.NewLimiterFromJSON(limitFile, defaultLimits) - if err != nil { - return nil, opts, fmt.Errorf("error parsing libp2p limit file: %w", err) - } - case errors.Is(err, os.ErrNotExist): - limiter = rcmgr.NewStaticLimiter(defaultLimits) - default: + + var limits rcmgr.BasicLimiterConfig + if cfg.ResourceMgr.Limits != nil { + limits = *cfg.ResourceMgr.Limits + } + + limiter, err := rcmgr.NewLimiter(limits, defaultLimits) + if err != nil { return nil, opts, err } @@ -80,9 +71,8 @@ func ResourceManager(cfg config.SwarmConfig) func(fx.Lifecycle, repo.Repo) (netw manager, err = rcmgr.NewResourceManager(limiter, ropts...) if err != nil { - return nil, opts, fmt.Errorf("error creating libp2p resource manager: %w", err) + return nil, opts, fmt.Errorf("creating libp2p resource manager: %w", err) } - } else { log.Debug("libp2p resource manager is disabled") manager = network.NullResourceManager @@ -196,14 +186,13 @@ func NetStat(mgr network.ResourceManager, scope string) (NetStatOut, error) { } } -func NetLimit(mgr network.ResourceManager, scope string) (config.ResourceMgrScopeConfig, error) { - var result config.ResourceMgrScopeConfig +func NetLimit(mgr network.ResourceManager, scope string) (rcmgr.BasicLimitConfig, error) { + var result rcmgr.BasicLimitConfig getLimit := func(s network.ResourceScope) error { limiter, ok := s.(rcmgr.ResourceScopeLimiter) if !ok { // NullResourceManager return NoResourceMgrError } - limit := limiter.Limit() switch l := limit.(type) { case *rcmgr.StaticLimit: @@ -280,7 +269,8 @@ func NetLimit(mgr network.ResourceManager, scope string) (config.ResourceMgrScop } } -func NetSetLimit(mgr network.ResourceManager, scope string, limit config.ResourceMgrScopeConfig) error { +// NetSetLimit sets new ResourceManager limits for the given scope. The limits take effect immediately, and are also persisted to the repo config. +func NetSetLimit(mgr network.ResourceManager, repo repo.Repo, scope string, limit rcmgr.BasicLimitConfig) error { setLimit := func(s network.ResourceScope) error { limiter, ok := s.(rcmgr.ResourceScopeLimiter) if !ok { // NullResourceManager @@ -324,45 +314,87 @@ func NetSetLimit(mgr network.ResourceManager, scope string, limit config.Resourc return nil } + cfg, err := repo.Config() + if err != nil { + return fmt.Errorf("reading config to set limit: %w", err) + } + + if cfg.Swarm.ResourceMgr.Limits == nil { + cfg.Swarm.ResourceMgr.Limits = &rcmgr.BasicLimiterConfig{} + } + configLimits := cfg.Swarm.ResourceMgr.Limits + + var setConfigFunc func() switch { case scope == config.ResourceMgrSystemScope: - err := mgr.ViewSystem(func(s network.ResourceScope) error { + err = mgr.ViewSystem(func(s network.ResourceScope) error { return setLimit(s) }) - return err + setConfigFunc = func() { configLimits.System = &limit } case scope == config.ResourceMgrTransientScope: - err := mgr.ViewTransient(func(s network.ResourceScope) error { + err = mgr.ViewTransient(func(s network.ResourceScope) error { return setLimit(s) }) - return err + setConfigFunc = func() { configLimits.Transient = &limit } case strings.HasPrefix(scope, config.ResourceMgrServiceScopePrefix): - svc := scope[4:] - err := mgr.ViewService(svc, func(s network.ServiceScope) error { + svc := strings.TrimPrefix(scope, config.ResourceMgrServiceScopePrefix) + err = mgr.ViewService(svc, func(s network.ServiceScope) error { return setLimit(s) }) - return err + setConfigFunc = func() { + if configLimits.Service == nil { + configLimits.Service = map[string]rcmgr.BasicLimitConfig{} + } + configLimits.Service[svc] = limit + } case strings.HasPrefix(scope, config.ResourceMgrProtocolScopePrefix): - proto := scope[6:] - err := mgr.ViewProtocol(protocol.ID(proto), func(s network.ProtocolScope) error { + proto := strings.TrimPrefix(scope, config.ResourceMgrProtocolScopePrefix) + err = mgr.ViewProtocol(protocol.ID(proto), func(s network.ProtocolScope) error { return setLimit(s) }) - return err + setConfigFunc = func() { + if configLimits.Protocol == nil { + configLimits.Protocol = map[string]rcmgr.BasicLimitConfig{} + } + configLimits.Protocol[proto] = limit + } case strings.HasPrefix(scope, config.ResourceMgrPeerScopePrefix): - p := scope[5:] - pid, err := peer.Decode(p) + p := strings.TrimPrefix(scope, config.ResourceMgrPeerScopePrefix) + var pid peer.ID + pid, err = peer.Decode(p) if err != nil { return fmt.Errorf("invalid peer ID: %q: %w", p, err) } err = mgr.ViewPeer(pid, func(s network.PeerScope) error { return setLimit(s) }) - return err + setConfigFunc = func() { + if configLimits.Peer == nil { + configLimits.Peer = map[string]rcmgr.BasicLimitConfig{} + } + configLimits.Peer[p] = limit + } default: return fmt.Errorf("invalid scope %q", scope) } + + if err != nil { + return fmt.Errorf("setting new limits on resource manager: %w", err) + } + + if cfg.Swarm.ResourceMgr.Limits == nil { + cfg.Swarm.ResourceMgr.Limits = &rcmgr.BasicLimiterConfig{} + } + setConfigFunc() + + if err := repo.SetConfig(cfg); err != nil { + return fmt.Errorf("writing new limits to repo config: %w", err) + } + + return nil } diff --git a/go.mod b/go.mod index ca15cc62fdb..e3c48f90367 100644 --- a/go.mod +++ b/go.mod @@ -82,7 +82,7 @@ require ( github.com/libp2p/go-libp2p-pubsub-router v0.5.0 github.com/libp2p/go-libp2p-quic-transport v0.16.1 github.com/libp2p/go-libp2p-record v0.1.3 - github.com/libp2p/go-libp2p-resource-manager v0.1.5 + github.com/libp2p/go-libp2p-resource-manager v0.3.0 github.com/libp2p/go-libp2p-routing-helpers v0.2.3 github.com/libp2p/go-libp2p-swarm v0.10.2 github.com/libp2p/go-libp2p-testing v0.8.0 diff --git a/go.sum b/go.sum index f044baf4b2d..b39877c20f1 100644 --- a/go.sum +++ b/go.sum @@ -910,8 +910,9 @@ github.com/libp2p/go-libp2p-record v0.1.0/go.mod h1:ujNc8iuE5dlKWVy6wuL6dd58t0n7 github.com/libp2p/go-libp2p-record v0.1.2/go.mod h1:pal0eNcT5nqZaTV7UGhqeGqxFgGdsU/9W//C8dqjQDk= github.com/libp2p/go-libp2p-record v0.1.3 h1:R27hoScIhQf/A8XJZ8lYpnqh9LatJ5YbHs28kCIfql0= github.com/libp2p/go-libp2p-record v0.1.3/go.mod h1:yNUff/adKIfPnYQXgp6FQmNu3gLJ6EMg7+/vv2+9pY4= -github.com/libp2p/go-libp2p-resource-manager v0.1.5 h1:7J6t9KLFS0MxXDTfqA6rwfVCZl/yLQnXW5LpZjHAANI= github.com/libp2p/go-libp2p-resource-manager v0.1.5/go.mod h1:wJPNjeE4XQlxeidwqVY5G6DLOKqFK33u2n8blpl0I6Y= +github.com/libp2p/go-libp2p-resource-manager v0.3.0 h1:2+cYxUNi33tcydsVLt6K5Fv2E3OTiVeafltecAj15E0= +github.com/libp2p/go-libp2p-resource-manager v0.3.0/go.mod h1:K+eCkiapf+ey/LADO4TaMpMTP9/Qde/uLlrnRqV4PLQ= github.com/libp2p/go-libp2p-routing v0.0.1/go.mod h1:N51q3yTr4Zdr7V8Jt2JIktVU+3xBBylx1MZeVA6t1Ys= github.com/libp2p/go-libp2p-routing-helpers v0.2.3 h1:xY61alxJ6PurSi+MXbywZpelvuU4U4p/gPTxjqCqTzY= github.com/libp2p/go-libp2p-routing-helpers v0.2.3/go.mod h1:795bh+9YeoFl99rMASoiVgHdi5bjack0N1+AFAdbvBw= diff --git a/test/sharness/t0139-swarm-rcmgr.sh b/test/sharness/t0139-swarm-rcmgr.sh index 39bbf1d5204..659f508b166 100755 --- a/test/sharness/t0139-swarm-rcmgr.sh +++ b/test/sharness/t0139-swarm-rcmgr.sh @@ -9,58 +9,147 @@ test_init_ipfs # swarm limit|stats should fail in offline mode test_expect_success 'disconnected: swarm limit requires running daemon' ' - test_expect_code 1 ipfs swarm limit system 2> actual && - test_should_contain "missing ResourceMgr" actual + test_expect_code 1 ipfs swarm limit system 2> actual && + test_should_contain "missing ResourceMgr" actual ' test_expect_success 'disconnected: swarm stats requires running daemon' ' - test_expect_code 1 ipfs swarm stats all 2> actual && - test_should_contain "missing ResourceMgr" actual + test_expect_code 1 ipfs swarm stats all 2> actual && + test_should_contain "missing ResourceMgr" actual ' # swarm limit|stats should fail in online mode by default -# because Resource Manager is opt-in for now +# because Resource Manager is opt-in test_launch_ipfs_daemon test_expect_success 'ResourceMgr disabled by default: swarm limit requires Swarm.ResourceMgr.Enabled' ' - test_expect_code 1 ipfs swarm limit system 2> actual && - test_should_contain "missing ResourceMgr" actual + test_expect_code 1 ipfs swarm limit system 2> actual && + test_should_contain "missing ResourceMgr" actual ' test_expect_success 'ResourceMgr disabled by default: swarm stats requires Swarm.ResourceMgr.Enabled' ' - test_expect_code 1 ipfs swarm stats all 2> actual && - test_should_contain "missing ResourceMgr" actual + test_expect_code 1 ipfs swarm stats all 2> actual && + test_should_contain "missing ResourceMgr" actual ' -# swarm limit|stat should work when Swarm.ResourceMgr.Enabled test_kill_ipfs_daemon -test_expect_success "test_config_set succeeds" " - ipfs config --json Swarm.ResourceMgr.Enabled true + +test_expect_success "setting an invalid limit should result in a failure" " + test_expect_code 1 ipfs config --json Swarm.ResourceMgr.Limits.System.Conns 'asdf' 2> actual && + test_should_contain 'failed to unmarshal' actual +" + +# swarm limit|stat should work when Swarm.ResourceMgr.Enabled +test_expect_success "test enabling resource manager" " + ipfs config --json Swarm.ResourceMgr.Enabled true && + ipfs config --json Swarm.ResourceMgr && + jq -e '.Swarm.ResourceMgr.Enabled == true' < \"$IPFS_PATH/config\" " + test_launch_ipfs_daemon +test_expect_success "test setting system conns limit" " + ipfs config --json Swarm.ResourceMgr.Enabled true && + ipfs config --json Swarm.ResourceMgr.Limits.System.Conns 99999 +" + # every scope has the same fields, so we only inspect System test_expect_success 'ResourceMgr enabled: swarm limit' ' - ipfs swarm limit system --enc=json | tee json && - jq -e .Conns < json && - jq -e .ConnsInbound < json && - jq -e .ConnsOutbound < json && - jq -e .FD < json && - jq -e .Memory < json && - jq -e .Streams < json && - jq -e .StreamsInbound < json && - jq -e .StreamsOutbound < json + ipfs swarm limit system --enc=json | tee json && + jq -e .Conns < json && + jq -e .ConnsInbound < json && + jq -e .ConnsOutbound < json && + jq -e .FD < json && + jq -e .Memory < json && + jq -e .Streams < json && + jq -e .StreamsInbound < json && + jq -e .StreamsOutbound < json ' # every scope has the same fields, so we only inspect System test_expect_success 'ResourceMgr enabled: swarm stats' ' - ipfs swarm stats all --enc=json | tee json && - jq -e .System.Memory < json && - jq -e .System.NumConnsInbound < json && - jq -e .System.NumConnsOutbound < json && - jq -e .System.NumFD < json && - jq -e .System.NumStreamsInbound < json && - jq -e .System.NumStreamsOutbound < json && - jq -e .Transient.Memory < json + ipfs swarm stats all --enc=json | tee json && + jq -e .System.Memory < json && + jq -e .System.NumConnsInbound < json && + jq -e .System.NumConnsOutbound < json && + jq -e .System.NumFD < json && + jq -e .System.NumStreamsInbound < json && + jq -e .System.NumStreamsOutbound < json && + jq -e .Transient.Memory < json ' +# shut down the daemon, set a limit in the config, and verify that it's applied test_kill_ipfs_daemon + +test_expect_success "set system conn limit" " + ipfs config --json Swarm.ResourceMgr.Limits.System.Conns 99999 +" + +test_launch_ipfs_daemon + +test_expect_success 'ResourceMgr enabled: swarm limit' ' + ipfs swarm limit system --enc=json | tee json && + jq -e ".Conns == 99999" < json +' + +test_expect_success 'Set system memory limit while the daemon is running' ' + ipfs swarm limit system | jq ".Memory = 99998" > system.json && + ipfs swarm limit system system.json +' + +test_expect_success 'The new system limits were written to the config' ' + jq -e ".Swarm.ResourceMgr.Limits.System.Memory == 99998" < "$IPFS_PATH/config" +' + +test_expect_success 'The new system limits are in the swarm limit output' ' + ipfs swarm limit system --enc=json | jq -e ".Memory == 99998" +' + +# now test all the other scopes +test_expect_success 'Set limit on transient scope' ' + ipfs swarm limit transient | jq ".Memory = 88888" > transient.json && + ipfs swarm limit transient transient.json && + jq -e ".Swarm.ResourceMgr.Limits.Transient.Memory == 88888" < "$IPFS_PATH/config" && + ipfs swarm limit transient --enc=json | tee limits && + jq -e ".Memory == 88888" < limits +' + +test_expect_success 'Set limit on service scope' ' + ipfs swarm limit svc:foo | jq ".Memory = 77777" > service-foo.json && + ipfs swarm limit svc:foo service-foo.json --enc=json && + jq -e ".Swarm.ResourceMgr.Limits.Service.foo.Memory == 77777" < "$IPFS_PATH/config" && + ipfs swarm limit svc:foo --enc=json | tee limits && + jq -e ".Memory == 77777" < limits +' + +test_expect_success 'Set limit on protocol scope' ' + ipfs swarm limit proto:foo | jq ".Memory = 66666" > proto-foo.json && + ipfs swarm limit proto:foo proto-foo.json --enc=json && + jq -e ".Swarm.ResourceMgr.Limits.Protocol.foo.Memory == 66666" < "$IPFS_PATH/config" && + ipfs swarm limit proto:foo --enc=json | tee limits && + jq -e ".Memory == 66666" < limits +' + +# any valid peer id +PEER_ID=QmNnooDu7bfjPFoTZYxMNLWUQJyrVwtbZg5gBMjTezGAJN + +test_expect_success 'Set limit on peer scope' ' + ipfs swarm limit peer:$PEER_ID | jq ".Memory = 66666" > peer-$PEER_ID.json && + ipfs swarm limit peer:$PEER_ID peer-$PEER_ID.json --enc=json && + jq -e ".Swarm.ResourceMgr.Limits.Peer.${PEER_ID}.Memory == 66666" < "$IPFS_PATH/config" && + ipfs swarm limit peer:$PEER_ID --enc=json | tee limits && + jq -e ".Memory == 66666" < limits +' + +test_expect_success 'Get limit for peer scope with an invalid peer ID' ' + test_expect_code 1 ipfs swarm limit peer:foo 2> actual && + test_should_contain "invalid peer ID" actual +' + +test_expect_success 'Set limit for peer scope with an invalid peer ID' ' + echo "{\"Memory\": 99}" > invalid-peer-id.json && + test_expect_code 1 ipfs swarm limit peer:foo invalid-peer-id.json 2> actual && + test_should_contain "invalid peer ID" actual +' + +test_kill_ipfs_daemon + test_done From 6815293aacb30531a59e9f0b87f44d1cb631083b Mon Sep 17 00:00:00 2001 From: Marcin Rataj Date: Thu, 28 Apr 2022 15:57:43 +0200 Subject: [PATCH 368/414] chore: mark 'log tail' experimental (#8912) Ensuring people are aware the RPC API/CMD may change Context: https://github.com/ipfs/go-ipfs/pull/8765#issuecomment-1109884874 --- core/commands/log.go | 1 + 1 file changed, 1 insertion(+) diff --git a/core/commands/log.go b/core/commands/log.go index 78ff8a6b50f..96366d4c4ee 100644 --- a/core/commands/log.go +++ b/core/commands/log.go @@ -105,6 +105,7 @@ subsystems of a running daemon. } var logTailCmd = &cmds.Command{ + Status: cmds.Experimental, Helptext: cmds.HelpText{ Tagline: "Read the event log.", ShortDescription: ` From ae15fcd195e80d6e1bf3c8f902d3a9eba1e6270a Mon Sep 17 00:00:00 2001 From: Marcin Rataj Date: Sat, 16 Apr 2022 01:10:07 +0200 Subject: [PATCH 369/414] chore&fix: panic/error handling while enumerating pins switch to version from https://github.com/ipfs/go-pinning-service-http-client/pull/18 to see if CI E2E tests pass --- go.mod | 2 +- go.sum | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/go.mod b/go.mod index e3c48f90367..d44a42e5766 100644 --- a/go.mod +++ b/go.mod @@ -53,7 +53,7 @@ require ( github.com/ipfs/go-mfs v0.2.1 github.com/ipfs/go-namesys v0.4.0 github.com/ipfs/go-path v0.2.2 - github.com/ipfs/go-pinning-service-http-client v0.1.0 + github.com/ipfs/go-pinning-service-http-client v0.1.1 github.com/ipfs/go-unixfs v0.3.1 github.com/ipfs/go-unixfsnode v1.1.3 github.com/ipfs/go-verifcid v0.0.1 diff --git a/go.sum b/go.sum index b39877c20f1..10abe815d1d 100644 --- a/go.sum +++ b/go.sum @@ -614,8 +614,8 @@ github.com/ipfs/go-peertaskqueue v0.1.1/go.mod h1:Jmk3IyCcfl1W3jTW3YpghSwSEC6IJ3 github.com/ipfs/go-peertaskqueue v0.2.0/go.mod h1:5/eNrBEbtSKWCG+kQK8K8fGNixoYUnr+P7jivavs9lY= github.com/ipfs/go-peertaskqueue v0.7.0 h1:VyO6G4sbzX80K58N60cCaHsSsypbUNs1GjO5seGNsQ0= github.com/ipfs/go-peertaskqueue v0.7.0/go.mod h1:M/akTIE/z1jGNXMU7kFB4TeSEFvj68ow0Rrb04donIU= -github.com/ipfs/go-pinning-service-http-client v0.1.0 h1:Au0P4NglL5JfzhNSZHlZ1qra+IcJyO3RWMd9EYCwqSY= -github.com/ipfs/go-pinning-service-http-client v0.1.0/go.mod h1:tcCKmlkWWH9JUUkKs8CrOZBanacNc1dmKLfjlyXAMu4= +github.com/ipfs/go-pinning-service-http-client v0.1.1 h1:Bar+Vi60A0zI8GSSrumVqnbFg6qkUgZSQTX9sV5jWrA= +github.com/ipfs/go-pinning-service-http-client v0.1.1/go.mod h1:i6tC2nWOnJbZZUQPgxOlrg4CX8bhQZMh4II09FxvD58= github.com/ipfs/go-unixfs v0.2.4/go.mod h1:SUdisfUjNoSDzzhGVxvCL9QO/nKdwXdr+gbMUdqcbYw= github.com/ipfs/go-unixfs v0.3.1 h1:LrfED0OGfG98ZEegO4/xiprx2O+yS+krCMQSp7zLVv8= github.com/ipfs/go-unixfs v0.3.1/go.mod h1:h4qfQYzghiIc8ZNFKiLMFWOTzrWIAtzYQ59W/pCFf1o= From 4e2028d19c1d81cf9726875154d3749cdae7cfd2 Mon Sep 17 00:00:00 2001 From: Lucas Molas Date: Tue, 5 Apr 2022 14:00:24 -0300 Subject: [PATCH 370/414] fix(cmds): add: reject files with different import dir --- go.mod | 2 +- go.sum | 4 ++-- test/sharness/t0040-add-and-cat.sh | 8 ++------ 3 files changed, 5 insertions(+), 9 deletions(-) diff --git a/go.mod b/go.mod index d44a42e5766..6e0a1aba142 100644 --- a/go.mod +++ b/go.mod @@ -31,7 +31,7 @@ require ( github.com/ipfs/go-graphsync v0.11.0 github.com/ipfs/go-ipfs-blockstore v1.2.0 github.com/ipfs/go-ipfs-chunker v0.0.5 - github.com/ipfs/go-ipfs-cmds v0.8.0 + github.com/ipfs/go-ipfs-cmds v0.8.1 github.com/ipfs/go-ipfs-exchange-interface v0.1.0 github.com/ipfs/go-ipfs-exchange-offline v0.2.0 github.com/ipfs/go-ipfs-files v0.0.9 diff --git a/go.sum b/go.sum index 10abe815d1d..4a73e07eb89 100644 --- a/go.sum +++ b/go.sum @@ -518,8 +518,8 @@ github.com/ipfs/go-ipfs-blocksutil v0.0.1/go.mod h1:Yq4M86uIOmxmGPUHv/uI7uKqZNtL github.com/ipfs/go-ipfs-chunker v0.0.1/go.mod h1:tWewYK0we3+rMbOh7pPFGDyypCtvGcBFymgY4rSDLAw= github.com/ipfs/go-ipfs-chunker v0.0.5 h1:ojCf7HV/m+uS2vhUGWcogIIxiO5ubl5O57Q7NapWLY8= github.com/ipfs/go-ipfs-chunker v0.0.5/go.mod h1:jhgdF8vxRHycr00k13FM8Y0E+6BoalYeobXmUyTreP8= -github.com/ipfs/go-ipfs-cmds v0.8.0 h1:M7apkPxhGe7I3rcKuQ8xRJLIPdaEqaZhJz0uPZEE8EU= -github.com/ipfs/go-ipfs-cmds v0.8.0/go.mod h1:y0bflH6m4g6ary4HniYt98UqbrVnRxmRarzeMdLIUn0= +github.com/ipfs/go-ipfs-cmds v0.8.1 h1:El661DBWqdqwgz7B9xwKyUpigwqk6BBBHb5B8DfJP00= +github.com/ipfs/go-ipfs-cmds v0.8.1/go.mod h1:y0bflH6m4g6ary4HniYt98UqbrVnRxmRarzeMdLIUn0= github.com/ipfs/go-ipfs-delay v0.0.0-20181109222059-70721b86a9a8/go.mod h1:8SP1YXK1M1kXuc4KJZINY3TQQ03J2rwBG9QfXmbRPrw= github.com/ipfs/go-ipfs-delay v0.0.1 h1:r/UXYyRcddO6thwOnhiznIAiSvxMECGgtv35Xs1IeRQ= github.com/ipfs/go-ipfs-delay v0.0.1/go.mod h1:8SP1YXK1M1kXuc4KJZINY3TQQ03J2rwBG9QfXmbRPrw= diff --git a/test/sharness/t0040-add-and-cat.sh b/test/sharness/t0040-add-and-cat.sh index 36a6e224050..833d6043e2e 100755 --- a/test/sharness/t0040-add-and-cat.sh +++ b/test/sharness/t0040-add-and-cat.sh @@ -346,12 +346,8 @@ test_add_cat_file() { test_cmp expected actual ' - test_expect_success "ipfs add with multiple files of same name succeeds" ' - mkdir -p mountdir/same-file/ && - cp mountdir/hello.txt mountdir/same-file/hello.txt && - ipfs add mountdir/hello.txt mountdir/same-file/hello.txt >actual && - rm mountdir/same-file/hello.txt && - rmdir mountdir/same-file + test_expect_success "ipfs add with multiple files of same name and import dir succeeds" ' + ipfs add mountdir/hello.txt mountdir/hello.txt >actual ' test_expect_success "ipfs add with multiple files of same name output looks good" ' From 232ccb4e55e2fb8b54ebf7f52ec0e0a5b6000f44 Mon Sep 17 00:00:00 2001 From: Marten Seemann Date: Thu, 28 Apr 2022 17:13:15 +0200 Subject: [PATCH 371/414] feat: relay v2 discovery (go-libp2p v0.19.0) (#8868) * update go-libp2p to v0.19.0 * chore: go-namesys v0.5.0 * refactor(config): cleanup relay handling * docs(config): document updated defaults * fix(tests): panic during sharness * fix: t0160-resolve.sh See https://github.com/ipfs/go-namesys/pull/32 * fix: t0182-circuit-relay.sh * test: transport encryption Old tests were no longer working because go-libp2p 0.19 removed the undocumented 'ls' pseudoprotocol. This replaces these tests with handshake attempt (name is echoed back on OK or 'na' is returned when protocol is not available) for tls and noise variants + adds explicit test that safeguards us against enabling plaintext by default by a mistake. * fix: ./t0182-circuit-relay.sh test is flaky, for now we just restart the testbed when we get NO_RESERVATION error * refactor: AutoRelayFeeder with exp. backoff It starts at feeding peers ever 15s, then backs off each time until it is done once an hour Should be acceptable until we have smarter mechanism in go-lib2p 0.20 * feat(AutoRelay): prioritize Peering.Peers This ensures we feed trusted Peering.Peers in addition to any peers discovered over DHT. * docs(CHANGELOG): document breaking changes Co-authored-by: Marcin Rataj Co-authored-by: Gus Eggert --- CHANGELOG.md | 5 +- core/node/groups.go | 50 +++---- core/node/libp2p/relay.go | 42 +++--- core/node/libp2p/routing.go | 90 ++++++++++++- docs/config.md | 43 ++---- go.mod | 72 +++++----- go.sum | 123 +++++++++++------- test/sharness/.gitignore | 1 + test/sharness/t0060-daemon.sh | 23 +++- .../sharness/t0060-data/{mss-ls => mss-noise} | 2 +- test/sharness/t0060-data/mss-plaintext | 2 + test/sharness/t0060-data/mss-tls | 2 + test/sharness/t0061-daemon-opts.sh | 5 +- test/sharness/t0160-resolve.sh | 2 +- test/sharness/t0182-circuit-relay.sh | 19 ++- test/sharness/t0280-plugin-dag-jose.sh | 0 16 files changed, 310 insertions(+), 171 deletions(-) rename test/sharness/t0060-data/{mss-ls => mss-noise} (71%) create mode 100644 test/sharness/t0060-data/mss-plaintext create mode 100644 test/sharness/t0060-data/mss-tls mode change 100644 => 100755 test/sharness/t0280-plugin-dag-jose.sh diff --git a/CHANGELOG.md b/CHANGELOG.md index b12fce5723a..80155f91fac 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -15,7 +15,10 @@ - `ipfs cid codecs` command - it now lists codecs from https://github.com/multiformats/go-multicodec - `ipfs cid codecs --supported` can be passed to only show codecs supported in various go-ipfs commands - +- `Swarm` configuration + - Daemon will refuse to start if long-deprecated RelayV1 config key `Swarm.EnableAutoRelay` or `Swarm.DisableRelay` is set to `true` + - When `Swarm.Transports.Network.Relay` is disabled, `Swarm.RelayService` and `Swarm.RelayClient` are also disabled (unless user explicitly enabled them). + - If user enabled them manually, then we error on start and inform they require `Swarm.Transports.Network.Relay` ## v0.12.2 and v0.11.1 2022-04-08 diff --git a/core/node/groups.go b/core/node/groups.go index 7f4cd8b97a2..007d2a76eb2 100644 --- a/core/node/groups.go +++ b/core/node/groups.go @@ -8,7 +8,7 @@ import ( blockstore "github.com/ipfs/go-ipfs-blockstore" util "github.com/ipfs/go-ipfs-util" - config "github.com/ipfs/go-ipfs/config" + "github.com/ipfs/go-ipfs/config" "github.com/ipfs/go-log" "github.com/libp2p/go-libp2p-core/peer" pubsub "github.com/libp2p/go-libp2p-pubsub" @@ -111,52 +111,57 @@ func LibP2P(bcfg *BuildCfg, cfg *config.Config) fx.Option { autonat = fx.Provide(libp2p.AutoNATService(cfg.AutoNAT.Throttle)) } - // If `cfg.Swarm.DisableRelay` is set and `Network.RelayTransport` isn't, use the former. - enableRelayTransport := cfg.Swarm.Transports.Network.Relay.WithDefault(!cfg.Swarm.DisableRelay) // nolint + enableRelayTransport := cfg.Swarm.Transports.Network.Relay.WithDefault(true) // nolint + enableRelayService := cfg.Swarm.RelayService.Enabled.WithDefault(enableRelayTransport) + enableRelayClient := cfg.Swarm.RelayClient.Enabled.WithDefault(enableRelayTransport) - // Warn about a deprecated option. + // Log error when relay subsystem could not be initialized due to missing dependency + if !enableRelayTransport { + if enableRelayService { + logger.Fatal("Failed to enable `Swarm.RelayService`, it requires `Swarm.Transports.Network.Relay` to be true.") + } + if enableRelayClient { + logger.Fatal("Failed to enable `Swarm.RelayClient`, it requires `Swarm.Transports.Network.Relay` to be true.") + } + } + + // Force users to migrate old config. // nolint if cfg.Swarm.DisableRelay { - logger.Error("The 'Swarm.DisableRelay' config field is deprecated.") - if enableRelayTransport { - logger.Error("'Swarm.DisableRelay' has been overridden by 'Swarm.Transports.Network.Relay'") - } else { - logger.Error("Use the 'Swarm.Transports.Network.Relay' config field instead") - } + logger.Fatal("The 'Swarm.DisableRelay' config field was removed." + + "Use the 'Swarm.Transports.Network.Relay' instead.") } // nolint if cfg.Swarm.EnableAutoRelay { - logger.Error("The 'Swarm.EnableAutoRelay' config field is deprecated.") - if cfg.Swarm.RelayClient.Enabled == config.Default { - logger.Error("Use the 'Swarm.AutoRelay.Enabled' config field instead") - } else { - logger.Error("'Swarm.EnableAutoRelay' has been overridden by 'Swarm.AutoRelay.Enabled'") - } + logger.Fatal("The 'Swarm.EnableAutoRelay' config field was removed." + + "Use the 'Swarm.RelayClient.Enabled' instead.") } // nolint if cfg.Swarm.EnableRelayHop { - logger.Fatal("The `Swarm.EnableRelayHop` config field is ignored.\n" + + logger.Fatal("The `Swarm.EnableRelayHop` config field was removed.\n" + "Use `Swarm.RelayService` to configure the circuit v2 relay.\n" + - "If you want to continue running a circuit v1 relay, please use the standalone relay daemon: https://github.com/libp2p/go-libp2p-relay-daemon (with RelayV1.Enabled: true)") + "If you want to continue running a circuit v1 relay, please use the standalone relay daemon: https://dist.ipfs.io/#libp2p-relay-daemon (with RelayV1.Enabled: true)") } + peerChan := make(libp2p.AddrInfoChan) // Gather all the options opts := fx.Options( BaseLibP2P, + fx.Supply(peerChan), + // Services (resource management) fx.Provide(libp2p.ResourceManager(cfg.Swarm)), fx.Provide(libp2p.AddrFilters(cfg.Swarm.AddrFilters)), fx.Provide(libp2p.AddrsFactory(cfg.Addresses.Announce, cfg.Addresses.AppendAnnounce, cfg.Addresses.NoAnnounce)), fx.Provide(libp2p.SmuxTransport(cfg.Swarm.Transports)), fx.Provide(libp2p.RelayTransport(enableRelayTransport)), - fx.Provide(libp2p.RelayService(cfg.Swarm.RelayService.Enabled.WithDefault(true), cfg.Swarm.RelayService)), + fx.Provide(libp2p.RelayService(enableRelayService, cfg.Swarm.RelayService)), fx.Provide(libp2p.Transports(cfg.Swarm.Transports)), fx.Invoke(libp2p.StartListening(cfg.Addresses.Swarm)), fx.Invoke(libp2p.SetupDiscovery(cfg.Discovery.MDNS.Enabled, cfg.Discovery.MDNS.Interval)), fx.Provide(libp2p.ForceReachability(cfg.Internal.Libp2pForceReachability)), - fx.Provide(libp2p.StaticRelays(cfg.Swarm.RelayClient.StaticRelays)), - fx.Provide(libp2p.HolePunching(cfg.Swarm.EnableHolePunching, cfg.Swarm.RelayClient.Enabled.WithDefault(false))), + fx.Provide(libp2p.HolePunching(cfg.Swarm.EnableHolePunching, enableRelayClient)), fx.Provide(libp2p.Security(!bcfg.DisableEncryptedConnections, cfg.Swarm.Transports)), @@ -166,7 +171,8 @@ func LibP2P(bcfg *BuildCfg, cfg *config.Config) fx.Option { maybeProvide(libp2p.BandwidthCounter, !cfg.Swarm.DisableBandwidthMetrics), maybeProvide(libp2p.NatPortMap, !cfg.Swarm.DisableNatPortMap), - maybeProvide(libp2p.AutoRelay(len(cfg.Swarm.RelayClient.StaticRelays) == 0), cfg.Swarm.RelayClient.Enabled.WithDefault(false)), + maybeProvide(libp2p.AutoRelay(cfg.Swarm.RelayClient.StaticRelays, peerChan), enableRelayClient), + maybeInvoke(libp2p.AutoRelayFeeder(cfg.Peering), enableRelayClient), autonat, connmgr, ps, diff --git a/core/node/libp2p/relay.go b/core/node/libp2p/relay.go index d30adcfaed9..5e218dcfe82 100644 --- a/core/node/libp2p/relay.go +++ b/core/node/libp2p/relay.go @@ -1,10 +1,10 @@ package libp2p import ( - config "github.com/ipfs/go-ipfs/config" - "github.com/libp2p/go-libp2p-core/peer" - + "github.com/ipfs/go-ipfs/config" "github.com/libp2p/go-libp2p" + "github.com/libp2p/go-libp2p-core/peer" + "github.com/libp2p/go-libp2p/p2p/host/autorelay" "github.com/libp2p/go-libp2p/p2p/protocol/circuitv2/relay" ) @@ -43,30 +43,26 @@ func RelayService(enable bool, relayOpts config.RelayService) func() (opts Libp2 } } -func StaticRelays(relays []string) func() (opts Libp2pOpts, err error) { +func AutoRelay(staticRelays []string, peerChan <-chan peer.AddrInfo) func() (opts Libp2pOpts, err error) { return func() (opts Libp2pOpts, err error) { - staticRelays := make([]peer.AddrInfo, 0, len(relays)) - for _, s := range relays { - var addr *peer.AddrInfo - addr, err = peer.AddrInfoFromString(s) - if err != nil { - return - } - staticRelays = append(staticRelays, *addr) - } + var autoRelayOpts []autorelay.Option if len(staticRelays) > 0 { - opts.Opts = append(opts.Opts, libp2p.StaticRelays(staticRelays)) + static := make([]peer.AddrInfo, 0, len(staticRelays)) + for _, s := range staticRelays { + var addr *peer.AddrInfo + addr, err = peer.AddrInfoFromString(s) + if err != nil { + return + } + static = append(static, *addr) + } + autoRelayOpts = append(autoRelayOpts, autorelay.WithStaticRelays(static)) + autoRelayOpts = append(autoRelayOpts, autorelay.WithCircuitV1Support()) } - return - } -} - -func AutoRelay(addDefaultRelays bool) func() (opts Libp2pOpts, err error) { - return func() (opts Libp2pOpts, err error) { - opts.Opts = append(opts.Opts, libp2p.EnableAutoRelay()) - if addDefaultRelays { - opts.Opts = append(opts.Opts, libp2p.DefaultStaticRelays()) + if peerChan != nil { + autoRelayOpts = append(autoRelayOpts, autorelay.WithPeerSource(peerChan)) } + opts.Opts = append(opts.Opts, libp2p.EnableAutoRelay(autoRelayOpts...)) return } } diff --git a/core/node/libp2p/routing.go b/core/node/libp2p/routing.go index b249611cc49..9c7351318d1 100644 --- a/core/node/libp2p/routing.go +++ b/core/node/libp2p/routing.go @@ -2,22 +2,27 @@ package libp2p import ( "context" + "fmt" + "runtime/debug" "sort" "time" "github.com/ipfs/go-ipfs/core/node/helpers" + config "github.com/ipfs/go-ipfs/config" "github.com/ipfs/go-ipfs/repo" - host "github.com/libp2p/go-libp2p-core/host" - routing "github.com/libp2p/go-libp2p-core/routing" + "github.com/libp2p/go-libp2p-core/host" + "github.com/libp2p/go-libp2p-core/peer" + "github.com/libp2p/go-libp2p-core/routing" dht "github.com/libp2p/go-libp2p-kad-dht" ddht "github.com/libp2p/go-libp2p-kad-dht/dual" "github.com/libp2p/go-libp2p-kad-dht/fullrt" - "github.com/libp2p/go-libp2p-pubsub" + pubsub "github.com/libp2p/go-libp2p-pubsub" namesys "github.com/libp2p/go-libp2p-pubsub-router" record "github.com/libp2p/go-libp2p-record" routinghelpers "github.com/libp2p/go-libp2p-routing-helpers" + "github.com/cenkalti/backoff/v4" "go.uber.org/fx" ) @@ -55,6 +60,8 @@ type processInitialRoutingOut struct { BaseRT BaseIpfsRouting } +type AddrInfoChan chan peer.AddrInfo + func BaseRouting(experimentalDHTClient bool) interface{} { return func(mctx helpers.MetricsCtx, lc fx.Lifecycle, in processInitialRoutingIn) (out processInitialRoutingOut, err error) { var dr *ddht.DHT @@ -179,3 +186,80 @@ func PubsubRouter(mctx helpers.MetricsCtx, lc fx.Lifecycle, in p2pPSRoutingIn) ( }, }, psRouter, nil } + +func AutoRelayFeeder(cfgPeering config.Peering) func(fx.Lifecycle, host.Host, AddrInfoChan, *ddht.DHT) { + return func(lc fx.Lifecycle, h host.Host, peerChan AddrInfoChan, dht *ddht.DHT) { + ctx, cancel := context.WithCancel(context.Background()) + done := make(chan struct{}) + + defer func() { + if r := recover(); r != nil { + fmt.Println("Recovering from unexpected error in AutoRelayFeeder:", r) + debug.PrintStack() + } + }() + go func() { + defer close(done) + + // Feed peers more often right after the bootstrap, then backoff + bo := backoff.NewExponentialBackOff() + bo.InitialInterval = 15 * time.Second + bo.Multiplier = 3 + bo.MaxInterval = 1 * time.Hour + bo.MaxElapsedTime = 0 // never stop + t := backoff.NewTicker(bo) + defer t.Stop() + for { + select { + case <-t.C: + case <-ctx.Done(): + return + } + + // Always feed trusted IDs (Peering.Peers in the config) + for _, trustedPeer := range cfgPeering.Peers { + if len(trustedPeer.Addrs) == 0 { + continue + } + select { + case peerChan <- trustedPeer: + case <-ctx.Done(): + return + } + } + + // Additionally, feed closest peers discovered via DHT + if dht == nil { + /* noop due to missing dht.WAN. happens in some unit tests, + not worth fixing as we will refactor this after go-libp2p 0.20 */ + continue + } + closestPeers, err := dht.WAN.GetClosestPeers(ctx, h.ID().String()) + if err != nil { + // no-op: usually 'failed to find any peer in table' during startup + continue + } + for _, p := range closestPeers { + addrs := h.Peerstore().Addrs(p) + if len(addrs) == 0 { + continue + } + dhtPeer := peer.AddrInfo{ID: p, Addrs: addrs} + select { + case peerChan <- dhtPeer: + case <-ctx.Done(): + return + } + } + } + }() + + lc.Append(fx.Hook{ + OnStop: func(_ context.Context) error { + cancel() + <-done + return nil + }, + }) + } +} diff --git a/docs/config.md b/docs/config.md index 519a7c10546..4261244e502 100644 --- a/docs/config.md +++ b/docs/config.md @@ -107,7 +107,6 @@ config file at runtime. - [`Swarm.DisableBandwidthMetrics`](#swarmdisablebandwidthmetrics) - [`Swarm.DisableNatPortMap`](#swarmdisablenatportmap) - [`Swarm.EnableHolePunching`](#swarmenableholepunching) - - [`Swarm.EnableAutoRelay`](#swarmenableautorelay) - [`Swarm.RelayClient`](#swarmrelayclient) - [`Swarm.RelayClient.Enabled`](#swarmrelayclientenabled) - [`Swarm.RelayClient.StaticRelays`](#swarmrelayclientstaticrelays) @@ -122,7 +121,6 @@ config file at runtime. - [`Swarm.RelayService.MaxReservationsPerPeer`](#swarmrelayservicemaxreservationsperpeer) - [`Swarm.RelayService.MaxReservationsPerIP`](#swarmrelayservicemaxreservationsperip) - [`Swarm.RelayService.MaxReservationsPerASN`](#swarmrelayservicemaxreservationsperasn) - - [`Swarm.DisableRelay`](#swarmdisablerelay) - [`Swarm.EnableAutoNATService`](#swarmenableautonatservice) - [`Swarm.ConnMgr`](#swarmconnmgr) - [`Swarm.ConnMgr.Type`](#swarmconnmgrtype) @@ -1376,21 +1374,9 @@ Type: `flag` ### `Swarm.EnableAutoRelay` -Deprecated: Set `Swarm.RelayClient.Enabled` to `true`. - -Enables "automatic relay user" mode for this node. - -Your node will automatically _use_ public relays from the network if it detects -that it cannot be reached from the public internet (e.g., it's behind a -firewall) and get a `/p2p-circuit` address from a public relay. - -This is likely the feature you're looking for, but see also: -- [`Swarm.RelayService.Enabled`](#swarmrelayserviceenabled) if your node should act as a limited relay for other peers -- Docs: [Libp2p Circuit Relay](https://docs.libp2p.io/concepts/circuit-relay/) - -Default: `false` +**REMOVED** -Type: `bool` +See `Swarm.RelayClient` instead. ### `Swarm.RelayClient` @@ -1408,14 +1394,14 @@ Your node will automatically _use_ public relays from the network if it detects that it cannot be reached from the public internet (e.g., it's behind a firewall) and get a `/p2p-circuit` address from a public relay. -Default: `false` +Default: `true` -Type: `bool` +Type: `flag` #### `Swarm.RelayClient.StaticRelays` -Your node will use these statically configured relay servers instead of -discovering public relays from the network. +Your node will use these statically configured relay servers (V1 or V2) +instead of discovering public relays V2 from the network. Default: `[]` @@ -1438,7 +1424,7 @@ NOTE: This is the service/server part of the relay system. Disabling this will prevent this node from running as a relay server. Use [`Swarm.RelayClient.Enabled`](#swarmrelayclientenabled) for turning your node into a relay user. -Default: Enabled +Default: `true` Type: `flag` @@ -1536,15 +1522,9 @@ Replaced with [`Swarm.RelayService.Enabled`](#swarmrelayserviceenabled). ### `Swarm.DisableRelay` -Deprecated: Set `Swarm.Transports.Network.Relay` to `false`. - -Disables the p2p-circuit relay transport. This will prevent this node from -connecting to nodes behind relays, or accepting connections from nodes behind -relays. - -Default: `false` +**REMOVED** -Type: `bool` +Set `Swarm.Transports.Network.Relay` to `false` instead. ### `Swarm.EnableAutoNATService` @@ -1765,8 +1745,9 @@ NATs. See also: - Docs: [Libp2p Circuit Relay](https://docs.libp2p.io/concepts/circuit-relay/) -- [`Swarm.EnableAutoRelay`](#swarmenableautorelay) for getting a public - `/p2p-circuit` address when behind a firewall. +- [`Swarm.RelayClient.Enabled`](#swarmrelayclientenabled) for getting a public +- `/p2p-circuit` address when behind a firewall. + - [`Swarm.EnableHolePunching`](#swarmenableholepunching) for direct connection upgrade through relay - [`Swarm.RelayService.Enabled`](#swarmrelayserviceenabled) for becoming a limited relay for other peers diff --git a/go.mod b/go.mod index 6e0a1aba142..293ac707038 100644 --- a/go.mod +++ b/go.mod @@ -4,6 +4,7 @@ require ( bazil.org/fuse v0.0.0-20200117225306-7b5117fecadc contrib.go.opencensus.io/exporter/prometheus v0.4.0 github.com/blang/semver/v4 v4.0.0 + github.com/cenkalti/backoff/v4 v4.1.2 github.com/ceramicnetwork/go-dag-jose v0.1.0 github.com/cespare/xxhash v1.1.0 github.com/cheggaaa/pb v1.0.29 @@ -51,7 +52,7 @@ require ( github.com/ipfs/go-metrics-interface v0.0.1 github.com/ipfs/go-metrics-prometheus v0.0.2 github.com/ipfs/go-mfs v0.2.1 - github.com/ipfs/go-namesys v0.4.0 + github.com/ipfs/go-namesys v0.5.0 github.com/ipfs/go-path v0.2.2 github.com/ipfs/go-pinning-service-http-client v0.1.1 github.com/ipfs/go-unixfs v0.3.1 @@ -67,31 +68,31 @@ require ( github.com/jbenet/go-temp-err-catcher v0.1.0 github.com/jbenet/goprocess v0.1.4 github.com/libp2p/go-doh-resolver v0.4.0 - github.com/libp2p/go-libp2p v0.18.0 + github.com/libp2p/go-libp2p v0.19.0 github.com/libp2p/go-libp2p-connmgr v0.3.2-0.20220115145817-a7820a5879c7 // indirect - github.com/libp2p/go-libp2p-core v0.14.0 + github.com/libp2p/go-libp2p-core v0.15.1 github.com/libp2p/go-libp2p-discovery v0.6.0 github.com/libp2p/go-libp2p-http v0.2.1 github.com/libp2p/go-libp2p-kad-dht v0.15.0 github.com/libp2p/go-libp2p-kbucket v0.4.7 github.com/libp2p/go-libp2p-loggables v0.1.0 - github.com/libp2p/go-libp2p-mplex v0.6.0 - github.com/libp2p/go-libp2p-noise v0.3.0 + github.com/libp2p/go-libp2p-mplex v0.7.0 + github.com/libp2p/go-libp2p-noise v0.4.0 github.com/libp2p/go-libp2p-peerstore v0.6.0 github.com/libp2p/go-libp2p-pubsub v0.6.0 github.com/libp2p/go-libp2p-pubsub-router v0.5.0 - github.com/libp2p/go-libp2p-quic-transport v0.16.1 + github.com/libp2p/go-libp2p-quic-transport v0.17.0 github.com/libp2p/go-libp2p-record v0.1.3 github.com/libp2p/go-libp2p-resource-manager v0.3.0 github.com/libp2p/go-libp2p-routing-helpers v0.2.3 github.com/libp2p/go-libp2p-swarm v0.10.2 - github.com/libp2p/go-libp2p-testing v0.8.0 - github.com/libp2p/go-libp2p-tls v0.3.1 - github.com/libp2p/go-libp2p-yamux v0.8.2 + github.com/libp2p/go-libp2p-testing v0.9.2 + github.com/libp2p/go-libp2p-tls v0.4.1 + github.com/libp2p/go-libp2p-yamux v0.9.1 github.com/libp2p/go-socket-activation v0.1.0 github.com/libp2p/go-tcp-transport v0.5.1 github.com/libp2p/go-ws-transport v0.6.0 - github.com/miekg/dns v1.1.43 + github.com/miekg/dns v1.1.48 github.com/mitchellh/go-homedir v1.1.0 github.com/multiformats/go-multiaddr v0.5.0 github.com/multiformats/go-multiaddr-dns v0.3.1 @@ -120,9 +121,9 @@ require ( go.uber.org/dig v1.14.0 go.uber.org/fx v1.16.0 go.uber.org/zap v1.21.0 - golang.org/x/crypto v0.0.0-20210921155107-089bfa567519 + golang.org/x/crypto v0.0.0-20220411220226-7b82a4e95df4 golang.org/x/sync v0.0.0-20210220032951-036812b2e83c - golang.org/x/sys v0.0.0-20220408201424-a24fb2fb8a0f + golang.org/x/sys v0.0.0-20220412211240-33da011f77ad ) require ( @@ -135,10 +136,9 @@ require ( github.com/beorn7/perks v1.0.1 // indirect github.com/btcsuite/btcd v0.22.0-beta // indirect github.com/cenkalti/backoff v2.2.1+incompatible // indirect - github.com/cenkalti/backoff/v4 v4.1.2 // indirect github.com/cespare/xxhash/v2 v2.1.2 // indirect github.com/cheekybits/genny v1.0.0 // indirect - github.com/containerd/cgroups v0.0.0-20201119153540-4cbc285b3327 // indirect + github.com/containerd/cgroups v1.0.3 // indirect github.com/crackcomm/go-gitignore v0.0.0-20170627025303-887ab5e44cc3 // indirect github.com/cskr/pubsub v1.0.2 // indirect github.com/davecgh/go-spew v1.1.1 // indirect @@ -146,7 +146,7 @@ require ( github.com/dgraph-io/badger v1.6.2 // indirect github.com/dgraph-io/ristretto v0.0.2 // indirect github.com/docker/go-units v0.4.0 // indirect - github.com/elastic/gosigar v0.12.0 // indirect + github.com/elastic/gosigar v0.14.2 // indirect github.com/felixge/httpsnoop v1.0.2 // indirect github.com/flynn/noise v1.0.0 // indirect github.com/francoispqt/gojay v1.2.13 // indirect @@ -155,29 +155,29 @@ require ( github.com/go-logr/logr v1.2.3 // indirect github.com/go-logr/stdr v1.2.2 // indirect github.com/go-task/slim-sprig v0.0.0-20210107165309-348f09dbbbc0 // indirect - github.com/godbus/dbus/v5 v5.0.4 // indirect + github.com/godbus/dbus/v5 v5.1.0 // indirect github.com/gogo/protobuf v1.3.2 // indirect github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da // indirect github.com/golang/protobuf v1.5.2 // indirect github.com/golang/snappy v0.0.4 // indirect github.com/google/gopacket v1.1.19 // indirect github.com/google/uuid v1.3.0 // indirect - github.com/gorilla/websocket v1.4.2 // indirect + github.com/gorilla/websocket v1.5.0 // indirect github.com/grpc-ecosystem/grpc-gateway/v2 v2.7.0 // indirect github.com/hannahhoward/go-pubsub v0.0.0-20200423002714-8d62886cc36e // indirect github.com/hashicorp/errwrap v1.0.0 // indirect github.com/hashicorp/golang-lru v0.5.4 // indirect - github.com/huin/goupnp v1.0.2 // indirect + github.com/huin/goupnp v1.0.3 // indirect github.com/ipfs/bbloom v0.0.4 // indirect github.com/ipfs/go-bitfield v1.0.0 // indirect github.com/ipfs/go-ipfs-delay v0.0.1 // indirect github.com/ipfs/go-ipfs-ds-help v1.1.0 // indirect github.com/ipfs/go-ipfs-pq v0.0.2 // indirect - github.com/ipfs/go-log/v2 v2.5.0 // indirect + github.com/ipfs/go-log/v2 v2.5.1 // indirect github.com/ipfs/go-peertaskqueue v0.7.0 // indirect github.com/jackpal/go-nat-pmp v1.0.2 // indirect - github.com/klauspost/compress v1.13.6 // indirect - github.com/klauspost/cpuid/v2 v2.0.9 // indirect + github.com/klauspost/compress v1.15.1 // indirect + github.com/klauspost/cpuid/v2 v2.0.12 // indirect github.com/koron/go-ssdp v0.0.2 // indirect github.com/libp2p/go-buffer-pool v0.0.2 // indirect github.com/libp2p/go-cidranger v1.1.0 // indirect @@ -191,20 +191,20 @@ require ( github.com/libp2p/go-libp2p-pnet v0.2.0 // indirect github.com/libp2p/go-libp2p-transport-upgrader v0.7.1 // indirect github.com/libp2p/go-libp2p-xor v0.0.0-20210714161855-5c005aca55db // indirect - github.com/libp2p/go-mplex v0.6.0 // indirect - github.com/libp2p/go-msgio v0.1.0 // indirect + github.com/libp2p/go-mplex v0.7.0 // indirect + github.com/libp2p/go-msgio v0.2.0 // indirect github.com/libp2p/go-nat v0.1.0 // indirect github.com/libp2p/go-netroute v0.2.0 // indirect github.com/libp2p/go-openssl v0.0.7 // indirect github.com/libp2p/go-reuseport v0.1.0 // indirect github.com/libp2p/go-reuseport-transport v0.1.0 // indirect github.com/libp2p/go-stream-muxer-multistream v0.4.0 // indirect - github.com/libp2p/go-yamux/v3 v3.0.2 // indirect + github.com/libp2p/go-yamux/v3 v3.1.1 // indirect github.com/libp2p/zeroconf/v2 v2.1.1 // indirect - github.com/lucas-clemente/quic-go v0.25.0 // indirect - github.com/marten-seemann/qtls-go1-16 v0.1.4 // indirect - github.com/marten-seemann/qtls-go1-17 v0.1.0 // indirect - github.com/marten-seemann/qtls-go1-18 v0.1.0-beta.1 // indirect + github.com/lucas-clemente/quic-go v0.27.0 // indirect + github.com/marten-seemann/qtls-go1-16 v0.1.5 // indirect + github.com/marten-seemann/qtls-go1-17 v0.1.1 // indirect + github.com/marten-seemann/qtls-go1-18 v0.1.1 // indirect github.com/marten-seemann/tcp v0.0.0-20210406111302-dfbc87cc63fd // indirect github.com/mattn/go-colorable v0.1.4 // indirect github.com/mattn/go-isatty v0.0.14 // indirect @@ -216,10 +216,10 @@ require ( github.com/minio/blake2b-simd v0.0.0-20160723061019-3f5f724cb5b1 // indirect github.com/minio/sha256-simd v1.0.0 // indirect github.com/mr-tron/base58 v1.2.0 // indirect - github.com/multiformats/go-base32 v0.0.3 // indirect + github.com/multiformats/go-base32 v0.0.4 // indirect github.com/multiformats/go-base36 v0.1.0 // indirect github.com/multiformats/go-multiaddr-fmt v0.1.0 // indirect - github.com/multiformats/go-multistream v0.2.2 // indirect + github.com/multiformats/go-multistream v0.3.0 // indirect github.com/multiformats/go-varint v0.0.6 // indirect github.com/nxadm/tail v1.4.8 // indirect github.com/onsi/ginkgo v1.16.5 // indirect @@ -251,16 +251,16 @@ require ( go.opentelemetry.io/otel/metric v0.28.0 // indirect go.opentelemetry.io/proto/otlp v0.15.0 // indirect go.uber.org/atomic v1.9.0 // indirect - go.uber.org/multierr v1.7.0 // indirect + go.uber.org/multierr v1.8.0 // indirect go4.org v0.0.0-20200411211856-f5505b9728dd // indirect golang.org/x/exp v0.0.0-20210615023648-acb5c1269671 // indirect - golang.org/x/mod v0.4.2 // indirect - golang.org/x/net v0.0.0-20220225172249-27dd8689420f // indirect + golang.org/x/mod v0.6.0-dev.0.20220106191415-9b9b3d81d5e3 // indirect + golang.org/x/net v0.0.0-20220418201149-a630d4f3e7a2 // indirect golang.org/x/oauth2 v0.0.0-20220223155221-ee480838109b // indirect golang.org/x/term v0.0.0-20210927222741-03fcf44c2211 // indirect golang.org/x/text v0.3.7 // indirect - golang.org/x/tools v0.1.5 // indirect - golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1 // indirect + golang.org/x/tools v0.1.10 // indirect + golang.org/x/xerrors v0.0.0-20220411194840-2f41105eb62f // indirect google.golang.org/appengine v1.6.6 // indirect google.golang.org/genproto v0.0.0-20211118181313-81c1377c94b1 // indirect google.golang.org/grpc v1.45.0 // indirect @@ -269,7 +269,7 @@ require ( gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7 // indirect gopkg.in/yaml.v2 v2.4.0 // indirect gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b // indirect - lukechampine.com/blake3 v1.1.6 // indirect + lukechampine.com/blake3 v1.1.7 // indirect ) go 1.17 diff --git a/go.sum b/go.sum index 4a73e07eb89..6859a1fddf5 100644 --- a/go.sum +++ b/go.sum @@ -139,6 +139,7 @@ github.com/chzyer/logex v1.1.10/go.mod h1:+Ywpsq7O8HXn0nuIou7OrIPyXbp3wmkHB+jjWR github.com/chzyer/readline v0.0.0-20180603132655-2972be24d48e/go.mod h1:nSuG5e5PlCu98SY8svDHJxuZscDgtXS6KTTbou5AhLI= github.com/chzyer/test v0.0.0-20180213035817-a1ea475d72b1/go.mod h1:Q3SI9o4m/ZMnBNeIyt5eFwwo7qiLfzFZmjNmxjkiQlU= github.com/cilium/ebpf v0.2.0/go.mod h1:To2CFviqOWL/M0gIMsvSMlqe7em/l1ALkX1PyjrX2Qs= +github.com/cilium/ebpf v0.4.0/go.mod h1:4tRaxcgiL706VnOzHOdBlY8IEAIdxINsQBcU4xJJXRs= github.com/clbanning/x2j v0.0.0-20191024224557-825249438eec/go.mod h1:jMjuTZXRI4dUb/I5gc9Hdhagfvm9+RyrPryS/auMzxE= github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw= github.com/cncf/udpa/go v0.0.0-20191209042840-269d4d468f6f/go.mod h1:M8M6+tZqaGXZJjfX53e64911xZQV5JYwmTeXPW+k8Sc= @@ -150,8 +151,9 @@ github.com/cncf/xds/go v0.0.0-20210922020428-25de7278fc84/go.mod h1:eXthEFrGJvWH github.com/cncf/xds/go v0.0.0-20211011173535-cb28da3451f1/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs= github.com/cockroachdb/datadriven v0.0.0-20190809214429-80d97fb3cbaa/go.mod h1:zn76sxSg3SzpJ0PPJaLDCu+Bu0Lg3sKTORVIj19EIF8= github.com/codahale/hdrhistogram v0.0.0-20161010025455-3a0bb77429bd/go.mod h1:sE/e/2PUdi/liOCUjSTXgM1o87ZssimdTWN964YiIeI= -github.com/containerd/cgroups v0.0.0-20201119153540-4cbc285b3327 h1:7grrpcfCtbZLsjtB0DgMuzs1umsJmpzaHMZ6cO6iAWw= github.com/containerd/cgroups v0.0.0-20201119153540-4cbc285b3327/go.mod h1:ZJeTFisyysqgcCdecO57Dj79RfL0LNeGiFUqLYQRYLE= +github.com/containerd/cgroups v1.0.3 h1:ADZftAkglvCiD44c77s5YmMqaP2pzVCFZvBmAlBdAP4= +github.com/containerd/cgroups v1.0.3/go.mod h1:/ofk34relqNjSGyqPrmEULrO4Sc8LJhvJmWbUCUKqj8= github.com/coreos/etcd v3.3.10+incompatible/go.mod h1:uF7uidLiAD3TWHmW31ZFd/JWoc32PjwdhPthX9715RE= github.com/coreos/go-etcd v2.0.0+incompatible/go.mod h1:Jez6KQU2B/sWsbdaef3ED8NzMklzPG4d5KIOhIy30Tk= github.com/coreos/go-semver v0.2.0/go.mod h1:nnelYz7RCh+5ahJtPPxZlU+153eP4D4r3EedlOD2RNk= @@ -206,8 +208,9 @@ github.com/eapache/go-resiliency v1.2.0/go.mod h1:kFI+JgMyC7bLPUVY133qvEBtVayf5m github.com/eapache/go-xerial-snappy v0.0.0-20180814174437-776d5712da21/go.mod h1:+020luEh2TKB4/GOp8oxxtq0Daoen/Cii55CzbTV6DU= github.com/eapache/queue v1.1.0/go.mod h1:6eCeP0CKFpHLu8blIFXhExK/dRa7WDZfr6jVFPTqq+I= github.com/edsrzf/mmap-go v1.0.0/go.mod h1:YO35OhQPt3KJa3ryjFM5Bs14WD66h8eGKpfaBNrHW5M= -github.com/elastic/gosigar v0.12.0 h1:AsdhYCJlTudhfOYQyFNgx+fIVTfrDO0V1ST0vHgiapU= github.com/elastic/gosigar v0.12.0/go.mod h1:iXRIGg2tLnu7LBdpqzyQfGDEidKCfWcCMS0WKyPWoMs= +github.com/elastic/gosigar v0.14.2 h1:Dg80n8cr90OZ7x+bAax/QjoW/XqTI11RmA79ZwIm9/4= +github.com/elastic/gosigar v0.14.2/go.mod h1:iXRIGg2tLnu7LBdpqzyQfGDEidKCfWcCMS0WKyPWoMs= github.com/elgris/jsondiff v0.0.0-20160530203242-765b5c24c302 h1:QV0ZrfBLpFc2KDk+a4LJefDczXnonRwrYrQJY/9L4dA= github.com/elgris/jsondiff v0.0.0-20160530203242-765b5c24c302/go.mod h1:qBlWZqWeVx9BjvqBsnC/8RUlAYpIFmPvgROcw0n1scE= github.com/envoyproxy/go-control-plane v0.6.9/go.mod h1:SBwIajubJHhxtWwsL9s8ss4safvEdbitLhGGK48rN6g= @@ -273,8 +276,9 @@ github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/me github.com/go-task/slim-sprig v0.0.0-20210107165309-348f09dbbbc0 h1:p104kn46Q8WdvHunIJ9dAyjPVtrBPhSr3KT2yUst43I= github.com/go-task/slim-sprig v0.0.0-20210107165309-348f09dbbbc0/go.mod h1:fyg7847qk6SyHyPtNmDHnmrv/HOrqktSC+C9fM+CJOE= github.com/godbus/dbus/v5 v5.0.3/go.mod h1:xhWf0FNVPg57R7Z0UbKHbJfkEywrmjJnf7w5xrFpKfA= -github.com/godbus/dbus/v5 v5.0.4 h1:9349emZab16e7zQvpmsbtjc18ykshndd8y2PG3sgJbA= github.com/godbus/dbus/v5 v5.0.4/go.mod h1:xhWf0FNVPg57R7Z0UbKHbJfkEywrmjJnf7w5xrFpKfA= +github.com/godbus/dbus/v5 v5.1.0 h1:4KLkAxT3aOY8Li4FRJe/KvhoNFFxo0m6fNuFUO8QJUk= +github.com/godbus/dbus/v5 v5.1.0/go.mod h1:xhWf0FNVPg57R7Z0UbKHbJfkEywrmjJnf7w5xrFpKfA= github.com/gogo/googleapis v1.1.0/go.mod h1:gf4bu3Q80BeJ6H1S1vYPm8/ELATdvryBaNFGgqEef3s= github.com/gogo/protobuf v1.1.1/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ= github.com/gogo/protobuf v1.2.0/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ= @@ -378,8 +382,9 @@ github.com/gorilla/sessions v1.2.1/go.mod h1:dk2InVEVJ0sfLlnXv9EAgkf6ecYs/i80K/z github.com/gorilla/websocket v0.0.0-20170926233335-4201258b820c/go.mod h1:E7qHFY5m1UJ88s3WnNqhKjPHQ0heANvMoAMk2YaljkQ= github.com/gorilla/websocket v1.4.0/go.mod h1:E7qHFY5m1UJ88s3WnNqhKjPHQ0heANvMoAMk2YaljkQ= github.com/gorilla/websocket v1.4.1/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE= -github.com/gorilla/websocket v1.4.2 h1:+/TMaTYc4QFitKJxsQ7Yye35DkWvkdLcvGKqM+x0Ufc= github.com/gorilla/websocket v1.4.2/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE= +github.com/gorilla/websocket v1.5.0 h1:PPwGk2jz7EePpoHN/+ClbZu8SPxiqlu12wZP/3sWmnc= +github.com/gorilla/websocket v1.5.0/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE= github.com/gregjones/httpcache v0.0.0-20180305231024-9cad4c3443a7/go.mod h1:FecbI9+v66THATjSRHfNgh1IVFe/9kFxbXtjV0ctIMA= github.com/grpc-ecosystem/go-grpc-middleware v1.0.1-0.20190118093823-f849b5445de4/go.mod h1:FiyG127CGDf3tlThmgyCl78X/SZQqEOJBCDaAfeWzPs= github.com/grpc-ecosystem/go-grpc-prometheus v1.2.0/go.mod h1:8NvIoxWQoOIhqOTXgfV/d3M/q6VIi02HzZEHgUlZvzk= @@ -425,8 +430,9 @@ github.com/hashicorp/serf v0.8.2/go.mod h1:6hOLApaqBFA1NXqRQAsxw9QxuDEvNxSQRwA/J github.com/hpcloud/tail v1.0.0/go.mod h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpOxQnU= github.com/hudl/fargo v1.3.0/go.mod h1:y3CKSmjA+wD2gak7sUSXTAoopbhU08POFhmITJgmKTg= github.com/huin/goupnp v1.0.0/go.mod h1:n9v9KO1tAxYH82qOn+UTIFQDmx5n1Zxd/ClZDMX7Bnc= -github.com/huin/goupnp v1.0.2 h1:RfGLP+h3mvisuWEyybxNq5Eft3NWhHLPeUN72kpKZoI= github.com/huin/goupnp v1.0.2/go.mod h1:0dxJBVBHqTMjIUMkESDTNgOOx/Mw5wYIfyFmdzSamkM= +github.com/huin/goupnp v1.0.3 h1:N8No57ls+MnjlB+JPiCVSOyy/ot7MJTqlo7rn+NYSqQ= +github.com/huin/goupnp v1.0.3/go.mod h1:ZxNlw5WqJj6wSsRK5+YfflQGXYfccj5VgQsMNixHM7Y= github.com/huin/goutil v0.0.0-20170803182201-1ca381bf3150/go.mod h1:PpLOETDnJ0o3iZrZfqZzyLl6l7F3c6L1oWn7OICBi6o= github.com/ianlancetaylor/demangle v0.0.0-20181102032728-5e5cf60278f6/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc= github.com/inconshreveable/mousetrap v1.0.0/go.mod h1:PxqpIevigyE2G7u3NXJIT2ANytuPF1OarO4DADm73n8= @@ -586,8 +592,9 @@ github.com/ipfs/go-log/v2 v2.1.1/go.mod h1:2v2nsGfZsvvAJz13SyFzf9ObaqwHiHxsPLEHn github.com/ipfs/go-log/v2 v2.1.3/go.mod h1:/8d0SH3Su5Ooc31QlL1WysJhvyOTDCjcCZ9Axpmri6g= github.com/ipfs/go-log/v2 v2.3.0/go.mod h1:QqGoj30OTpnKaG/LKTGTxoP2mmQtjVMEnK72gynbe/g= github.com/ipfs/go-log/v2 v2.4.0/go.mod h1:nPZnh7Cj7lwS3LpRU5Mwr2ol1c2gXIEXuF6aywqrtmo= -github.com/ipfs/go-log/v2 v2.5.0 h1:+MhAooFd9XZNvR0i9FriKW6HB0ql7HNXUuflWtc0dd4= github.com/ipfs/go-log/v2 v2.5.0/go.mod h1:prSpmC1Gpllc9UYWxDiZDreBYw7zp4Iqp1kOLU9U5UI= +github.com/ipfs/go-log/v2 v2.5.1 h1:1XdUzF7048prq4aBjDQQ4SL5RxftpRGdXhNRwKSAlcY= +github.com/ipfs/go-log/v2 v2.5.1/go.mod h1:prSpmC1Gpllc9UYWxDiZDreBYw7zp4Iqp1kOLU9U5UI= github.com/ipfs/go-merkledag v0.0.6/go.mod h1:QYPdnlvkOg7GnQRofu9XZimC5ZW5Wi3bKys/4GQQfto= github.com/ipfs/go-merkledag v0.2.3/go.mod h1:SQiXrtSts3KGNmgOzMICy5c0POOpUNQLvB3ClKnBAlk= github.com/ipfs/go-merkledag v0.3.2/go.mod h1:fvkZNNZixVW6cKSZ/JfLlON5OlgTXNdRLz0p6QG/I2M= @@ -600,8 +607,8 @@ github.com/ipfs/go-metrics-prometheus v0.0.2 h1:9i2iljLg12S78OhC6UAiXi176xvQGiZa github.com/ipfs/go-metrics-prometheus v0.0.2/go.mod h1:ELLU99AQQNi+zX6GCGm2lAgnzdSH3u5UVlCdqSXnEks= github.com/ipfs/go-mfs v0.2.1 h1:5jz8+ukAg/z6jTkollzxGzhkl3yxm022Za9f2nL5ab8= github.com/ipfs/go-mfs v0.2.1/go.mod h1:Woj80iuw4ajDnIP6+seRaoHpPsc9hmL0pk/nDNDWP88= -github.com/ipfs/go-namesys v0.4.0 h1:Gxg4kEWxVcHuUJl60KMNs1k8AiVB3luXbz8ZJkSGacs= -github.com/ipfs/go-namesys v0.4.0/go.mod h1:jpJwzodyP8DZdWN6DShRjVZw6gaqMr4nQLBSxU5cR6E= +github.com/ipfs/go-namesys v0.5.0 h1:vZEkdqxRiSnxBBJrvYTkwHYBFgibGUSpNtg9BHRyN+o= +github.com/ipfs/go-namesys v0.5.0/go.mod h1:zZOme8KDAUYDl4f5MnWSiTRhoxcM7kLkZIyps/HV/S0= github.com/ipfs/go-path v0.0.7/go.mod h1:6KTKmeRnBXgqrTvzFrPV3CamxcgvXX/4z79tfAd2Sno= github.com/ipfs/go-path v0.0.9/go.mod h1:VpDkSBKQ9EFQOUgi54Tq/O/tGi8n1RfYNks13M3DEs8= github.com/ipfs/go-path v0.1.1/go.mod h1:vC8q4AKOtrjJz2NnllIrmr2ZbGlF5fW2OKKyhV9ggb0= @@ -696,12 +703,14 @@ github.com/kisielk/errcheck v1.5.0/go.mod h1:pFxgyoBC7bSaBwPgfKdkLd5X25qrDl4LWUI github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck= github.com/kkdai/bstream v0.0.0-20161212061736-f391b8402d23/go.mod h1:J+Gs4SYgM6CZQHDETBtE9HaSEkGmuNXF86RwHhHUvq4= github.com/klauspost/compress v1.11.7/go.mod h1:aoV0uJVorq1K+umq18yTdKaF57EivdYsUV+/s2qKfXs= -github.com/klauspost/compress v1.13.6 h1:P76CopJELS0TiO2mebmnzgWaajssP/EszplttgQxcgc= github.com/klauspost/compress v1.13.6/go.mod h1:/3/Vjq9QcHkK5uEr5lBEmyoZ1iFhe47etQ6QUkpK6sk= +github.com/klauspost/compress v1.15.1 h1:y9FcTHGyrebwfP0ZZqFiaxTaiDnUrGkJkI+f583BL1A= +github.com/klauspost/compress v1.15.1/go.mod h1:/3/Vjq9QcHkK5uEr5lBEmyoZ1iFhe47etQ6QUkpK6sk= github.com/klauspost/cpuid/v2 v2.0.4/go.mod h1:FInQzS24/EEf25PyTYn52gqo7WaD8xa0213Md/qVLRg= github.com/klauspost/cpuid/v2 v2.0.6/go.mod h1:FInQzS24/EEf25PyTYn52gqo7WaD8xa0213Md/qVLRg= -github.com/klauspost/cpuid/v2 v2.0.9 h1:lgaqFMSdTdQYdZ04uHyN2d/eKdOMyi2YLSvlQIBFYa4= github.com/klauspost/cpuid/v2 v2.0.9/go.mod h1:FInQzS24/EEf25PyTYn52gqo7WaD8xa0213Md/qVLRg= +github.com/klauspost/cpuid/v2 v2.0.12 h1:p9dKCg8i4gmOxtv35DvrYoWqYzQrvEVdjQ762Y0OqZE= +github.com/klauspost/cpuid/v2 v2.0.12/go.mod h1:g2LTdtYhdyuGPqyWyv7qRAmj1WBqxuObKfj5c0PQa7c= github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= github.com/konsorten/go-windows-terminal-sequences v1.0.3/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= github.com/koron/go-ssdp v0.0.0-20180514024734-4a0ed625a78b/go.mod h1:5Ky9EC2xfoUKUor0Hjgi2BJhCSXJfMOFlmyYrVKGQMk= @@ -755,8 +764,8 @@ github.com/libp2p/go-libp2p v0.13.0/go.mod h1:pM0beYdACRfHO1WcJlp65WXyG2A6NqYM+t github.com/libp2p/go-libp2p v0.14.3/go.mod h1:d12V4PdKbpL0T1/gsUNN8DfgMuRPDX8bS2QxCZlwRH0= github.com/libp2p/go-libp2p v0.14.4/go.mod h1:EIRU0Of4J5S8rkockZM7eJp2S0UrCyi55m2kJVru3rM= github.com/libp2p/go-libp2p v0.16.0/go.mod h1:ump42BsirwAWxKzsCiFnTtN1Yc+DuPu76fyMX364/O4= -github.com/libp2p/go-libp2p v0.18.0 h1:moKKKG875KNGsCjZxTIFB75ihHiVjFeWg5I4aR1pDLk= -github.com/libp2p/go-libp2p v0.18.0/go.mod h1:+veaZ9z1SZQhmc5PW78jvnnxZ89Mgvmh4cggO11ETmw= +github.com/libp2p/go-libp2p v0.19.0 h1:zosskMbaobL7UDCVLEe1m5CGs1TaFNFoN/M5XLiKg0U= +github.com/libp2p/go-libp2p v0.19.0/go.mod h1:Ki9jJXLO2YqrTIFxofV7Twyd3INWPT97+r8hGt7XPjI= github.com/libp2p/go-libp2p-asn-util v0.0.0-20200825225859-85005c6cf052/go.mod h1:nRMRTab+kZuk0LnKZpxhOVH/ndsdr2Nr//Zltc/vwgo= github.com/libp2p/go-libp2p-asn-util v0.1.0/go.mod h1:wu+AnM9Ii2KgO5jMmS1rz9dvzTdj8BXqsPR9HR0XB7I= github.com/libp2p/go-libp2p-asn-util v0.2.0 h1:rg3+Os8jbnO5DxkC7K/Utdi+DkY3q/d1/1q+8WeNAsw= @@ -817,8 +826,9 @@ github.com/libp2p/go-libp2p-core v0.10.0/go.mod h1:ECdxehoYosLYHgDDFa2N4yE8Y7aQR github.com/libp2p/go-libp2p-core v0.11.0/go.mod h1:ECdxehoYosLYHgDDFa2N4yE8Y7aQRAMf0sX9mf2sbGg= github.com/libp2p/go-libp2p-core v0.12.0/go.mod h1:ECdxehoYosLYHgDDFa2N4yE8Y7aQRAMf0sX9mf2sbGg= github.com/libp2p/go-libp2p-core v0.13.0/go.mod h1:ECdxehoYosLYHgDDFa2N4yE8Y7aQRAMf0sX9mf2sbGg= -github.com/libp2p/go-libp2p-core v0.14.0 h1:0kYSgiK/D7Eo28GTuRXo5YHsWwAisVpFCqCVPUd/vJs= github.com/libp2p/go-libp2p-core v0.14.0/go.mod h1:tLasfcVdTXnixsLB0QYaT1syJOhsbrhG7q6pGrHtBg8= +github.com/libp2p/go-libp2p-core v0.15.1 h1:0RY+Mi/ARK9DgG1g9xVQLb8dDaaU8tCePMtGALEfBnM= +github.com/libp2p/go-libp2p-core v0.15.1/go.mod h1:agSaboYM4hzB1cWekgVReqV5M4g5M+2eNNejV+1EEhs= github.com/libp2p/go-libp2p-crypto v0.0.1/go.mod h1:yJkNyDmO341d5wwXxDUGO0LykUVT72ImHNUqh5D/dBE= github.com/libp2p/go-libp2p-crypto v0.0.2/go.mod h1:eETI5OUfBnvARGOHrJz2eWNyTUxEGZnBxMcbUjfIj4I= github.com/libp2p/go-libp2p-crypto v0.1.0/go.mod h1:sPUokVISZiy+nNuTTH/TY+leRSxnFj/2GLjtOTW90hI= @@ -857,8 +867,8 @@ github.com/libp2p/go-libp2p-mplex v0.3.0/go.mod h1:l9QWxRbbb5/hQMECEb908GbS9Sm2U github.com/libp2p/go-libp2p-mplex v0.4.0/go.mod h1:yCyWJE2sc6TBTnFpjvLuEJgTSw/u+MamvzILKdX7asw= github.com/libp2p/go-libp2p-mplex v0.4.1/go.mod h1:cmy+3GfqfM1PceHTLL7zQzAAYaryDu6iPSC+CIb094g= github.com/libp2p/go-libp2p-mplex v0.5.0/go.mod h1:eLImPJLkj3iG5t5lq68w3Vm5NAQ5BcKwrrb2VmOYb3M= -github.com/libp2p/go-libp2p-mplex v0.6.0 h1:5ubK4/vLE2JkogKlJ2JLeXcSfA6qY6mE2HMJV9ve/Sk= -github.com/libp2p/go-libp2p-mplex v0.6.0/go.mod h1:i3usuPrBbh9FD2fLZjGpotyNkwr42KStYZQY7BeTiu4= +github.com/libp2p/go-libp2p-mplex v0.7.0 h1:ONTTvHIUaFCwyPO4FRkpe4OFQJq1bDkWQLbhWiD1A44= +github.com/libp2p/go-libp2p-mplex v0.7.0/go.mod h1:SeeXUXh7ZkfxnmsepnFgMPEhfEyACujuTM9k1TkErpc= github.com/libp2p/go-libp2p-nat v0.0.4/go.mod h1:N9Js/zVtAXqaeT99cXgTV9e75KpnWCvVOiGzlcHmBbY= github.com/libp2p/go-libp2p-nat v0.0.5/go.mod h1:1qubaE5bTZMJE+E/uu2URroMbzdubFz1ChgiN79yKPE= github.com/libp2p/go-libp2p-nat v0.0.6/go.mod h1:iV59LVhB3IkFvS6S6sauVTSOrNEANnINbI/fkaLimiw= @@ -871,8 +881,9 @@ github.com/libp2p/go-libp2p-netutil v0.1.0 h1:zscYDNVEcGxyUpMd0JReUZTrpMfia8PmLK github.com/libp2p/go-libp2p-netutil v0.1.0/go.mod h1:3Qv/aDqtMLTUyQeundkKsA+YCThNdbQD54k3TqjpbFU= github.com/libp2p/go-libp2p-noise v0.1.1/go.mod h1:QDFLdKX7nluB7DEnlVPbz7xlLHdwHFA9HiohJRr3vwM= github.com/libp2p/go-libp2p-noise v0.2.0/go.mod h1:IEbYhBBzGyvdLBoxxULL/SGbJARhUeqlO8lVSREYu2Q= -github.com/libp2p/go-libp2p-noise v0.3.0 h1:NCVH7evhVt9njbTQshzT7N1S3Q6fjj9M11FCgfH5+cA= github.com/libp2p/go-libp2p-noise v0.3.0/go.mod h1:JNjHbociDJKHD64KTkzGnzqJ0FEV5gHJa6AB00kbCNQ= +github.com/libp2p/go-libp2p-noise v0.4.0 h1:khcMsGhHNdGqKE5LDLrnHwZvdGVMsrnD4GTkTWkwmLU= +github.com/libp2p/go-libp2p-noise v0.4.0/go.mod h1:BzzY5pyzCYSyJbQy9oD8z5oP2idsafjt4/X42h9DjZU= github.com/libp2p/go-libp2p-peer v0.0.1/go.mod h1:nXQvOBbwVqoP+T5Y5nCjeH4sP9IX/J0AMzcDUVruVoo= github.com/libp2p/go-libp2p-peer v0.1.1/go.mod h1:jkF12jGB4Gk/IOo+yomm+7oLWxF278F7UnrYUQ1Q8es= github.com/libp2p/go-libp2p-peer v0.2.0/go.mod h1:RCffaCvUyW2CJmG2gAWVqwePwW7JMgxjsHm7+J5kjWY= @@ -903,14 +914,14 @@ github.com/libp2p/go-libp2p-quic-transport v0.11.2/go.mod h1:wlanzKtIh6pHrq+0U3p github.com/libp2p/go-libp2p-quic-transport v0.13.0/go.mod h1:39/ZWJ1TW/jx1iFkKzzUg00W6tDJh73FC0xYudjr7Hc= github.com/libp2p/go-libp2p-quic-transport v0.15.0/go.mod h1:wv4uGwjcqe8Mhjj7N/Ic0aKjA+/10UnMlSzLO0yRpYQ= github.com/libp2p/go-libp2p-quic-transport v0.16.0/go.mod h1:1BXjVMzr+w7EkPfiHkKnwsWjPjtfaNT0q8RS3tGDvEQ= -github.com/libp2p/go-libp2p-quic-transport v0.16.1 h1:N/XqYXHurphPLDfXYhll8NyqzdZYQqAF4GIr7+SmLV8= -github.com/libp2p/go-libp2p-quic-transport v0.16.1/go.mod h1:1BXjVMzr+w7EkPfiHkKnwsWjPjtfaNT0q8RS3tGDvEQ= +github.com/libp2p/go-libp2p-quic-transport v0.17.0 h1:yFh4Gf5MlToAYLuw/dRvuzYd1EnE2pX3Lq1N6KDiWRQ= +github.com/libp2p/go-libp2p-quic-transport v0.17.0/go.mod h1:x4pw61P3/GRCcSLypcQJE/Q2+E9f4X+5aRcZLXf20LM= github.com/libp2p/go-libp2p-record v0.0.1/go.mod h1:grzqg263Rug/sRex85QrDOLntdFAymLDLm7lxMgU79Q= github.com/libp2p/go-libp2p-record v0.1.0/go.mod h1:ujNc8iuE5dlKWVy6wuL6dd58t0n7xI4hAIl8pE6wu5Q= github.com/libp2p/go-libp2p-record v0.1.2/go.mod h1:pal0eNcT5nqZaTV7UGhqeGqxFgGdsU/9W//C8dqjQDk= github.com/libp2p/go-libp2p-record v0.1.3 h1:R27hoScIhQf/A8XJZ8lYpnqh9LatJ5YbHs28kCIfql0= github.com/libp2p/go-libp2p-record v0.1.3/go.mod h1:yNUff/adKIfPnYQXgp6FQmNu3gLJ6EMg7+/vv2+9pY4= -github.com/libp2p/go-libp2p-resource-manager v0.1.5/go.mod h1:wJPNjeE4XQlxeidwqVY5G6DLOKqFK33u2n8blpl0I6Y= +github.com/libp2p/go-libp2p-resource-manager v0.2.1/go.mod h1:K+eCkiapf+ey/LADO4TaMpMTP9/Qde/uLlrnRqV4PLQ= github.com/libp2p/go-libp2p-resource-manager v0.3.0 h1:2+cYxUNi33tcydsVLt6K5Fv2E3OTiVeafltecAj15E0= github.com/libp2p/go-libp2p-resource-manager v0.3.0/go.mod h1:K+eCkiapf+ey/LADO4TaMpMTP9/Qde/uLlrnRqV4PLQ= github.com/libp2p/go-libp2p-routing v0.0.1/go.mod h1:N51q3yTr4Zdr7V8Jt2JIktVU+3xBBylx1MZeVA6t1Ys= @@ -947,12 +958,14 @@ github.com/libp2p/go-libp2p-testing v0.4.0/go.mod h1:Q+PFXYoiYFN5CAEG2w3gLPEzotl github.com/libp2p/go-libp2p-testing v0.4.2/go.mod h1:Q+PFXYoiYFN5CAEG2w3gLPEzotlKsNSbKQ/lImlOWF0= github.com/libp2p/go-libp2p-testing v0.5.0/go.mod h1:QBk8fqIL1XNcno/l3/hhaIEn4aLRijpYOR+zVjjlh+A= github.com/libp2p/go-libp2p-testing v0.7.0/go.mod h1:OLbdn9DbgdMwv00v+tlp1l3oe2Cl+FAjoWIA2pa0X6E= -github.com/libp2p/go-libp2p-testing v0.8.0 h1:/te8SOIyj5sGH5Jr1Uoo+qYB00aK8O4+yHGzLgfE3kc= -github.com/libp2p/go-libp2p-testing v0.8.0/go.mod h1:gRdsNxQSxAZowTgcLY7CC33xPmleZzoBpqSYbWenqPc= +github.com/libp2p/go-libp2p-testing v0.9.0/go.mod h1:Td7kbdkWqYTJYQGTwzlgXwaqldraIanyjuRiAbK/XQU= +github.com/libp2p/go-libp2p-testing v0.9.2 h1:dCpODRtRaDZKF8HXT9qqqgON+OMEB423Knrgeod8j84= +github.com/libp2p/go-libp2p-testing v0.9.2/go.mod h1:Td7kbdkWqYTJYQGTwzlgXwaqldraIanyjuRiAbK/XQU= github.com/libp2p/go-libp2p-tls v0.1.3/go.mod h1:wZfuewxOndz5RTnCAxFliGjvYSDA40sKitV4c50uI1M= github.com/libp2p/go-libp2p-tls v0.3.0/go.mod h1:fwF5X6PWGxm6IDRwF3V8AVCCj/hOd5oFlg+wo2FxJDY= -github.com/libp2p/go-libp2p-tls v0.3.1 h1:lsE2zYte+rZCEOHF72J1Fg3XK3dGQyKvI6i5ehJfEp0= github.com/libp2p/go-libp2p-tls v0.3.1/go.mod h1:fwF5X6PWGxm6IDRwF3V8AVCCj/hOd5oFlg+wo2FxJDY= +github.com/libp2p/go-libp2p-tls v0.4.1 h1:1ByJUbyoMXvYXDoW6lLsMxqMViQNXmt+CfQqlnCpY+M= +github.com/libp2p/go-libp2p-tls v0.4.1/go.mod h1:EKCixHEysLNDlLUoKxv+3f/Lp90O2EXNjTr0UQDnrIw= github.com/libp2p/go-libp2p-transport v0.0.1/go.mod h1:UzbUs9X+PHOSw7S3ZmeOxfnwaQY5vGDzZmKPod3N3tk= github.com/libp2p/go-libp2p-transport v0.0.5/go.mod h1:StoY3sx6IqsP6XKoabsPnHCwqKXWUMWU7Rfcsubee/A= github.com/libp2p/go-libp2p-transport-upgrader v0.0.4/go.mod h1:RGq+tupk+oj7PzL2kn/m1w6YXxcIAYJYeI90h6BGgUc= @@ -984,8 +997,8 @@ github.com/libp2p/go-libp2p-yamux v0.5.4/go.mod h1:tfrXbyaTqqSU654GTvK3ocnSZL3Bu github.com/libp2p/go-libp2p-yamux v0.6.0/go.mod h1:MRhd6mAYnFRnSISp4M8i0ClV/j+mWHo2mYLifWGw33k= github.com/libp2p/go-libp2p-yamux v0.8.0/go.mod h1:yTkPgN2ib8FHyU1ZcVD7aelzyAqXXwEPbyx+aSKm9h8= github.com/libp2p/go-libp2p-yamux v0.8.1/go.mod h1:rUozF8Jah2dL9LLGyBaBeTQeARdwhefMCTQVQt6QobE= -github.com/libp2p/go-libp2p-yamux v0.8.2 h1:6GKWntresp0TFxMP/oSoH96nV8XKJRdynXsdp43dn0Y= -github.com/libp2p/go-libp2p-yamux v0.8.2/go.mod h1:rUozF8Jah2dL9LLGyBaBeTQeARdwhefMCTQVQt6QobE= +github.com/libp2p/go-libp2p-yamux v0.9.1 h1:oplewiRix8s45SOrI30rCPZG5mM087YZp+VYhXAh4+c= +github.com/libp2p/go-libp2p-yamux v0.9.1/go.mod h1:wRc6wvyxQINFcKe7daL4BeQ02Iyp+wxyC8WCNfngBrA= github.com/libp2p/go-maddr-filter v0.0.1/go.mod h1:6eT12kSQMA9x2pvFQa+xesMKUBlj9VImZbj3B9FBH/Q= github.com/libp2p/go-maddr-filter v0.0.4/go.mod h1:6eT12kSQMA9x2pvFQa+xesMKUBlj9VImZbj3B9FBH/Q= github.com/libp2p/go-maddr-filter v0.0.5/go.mod h1:Jk+36PMfIqCJhAnaASRH83bdAvfDRp/w6ENFaC9bG+M= @@ -998,14 +1011,15 @@ github.com/libp2p/go-mplex v0.1.2/go.mod h1:Xgz2RDCi3co0LeZfgjm4OgUF15+sVR8SRcu3 github.com/libp2p/go-mplex v0.2.0/go.mod h1:0Oy/A9PQlwBytDRp4wSkFnzHYDKcpLot35JQ6msjvYQ= github.com/libp2p/go-mplex v0.3.0/go.mod h1:0Oy/A9PQlwBytDRp4wSkFnzHYDKcpLot35JQ6msjvYQ= github.com/libp2p/go-mplex v0.4.0/go.mod h1:y26Lx+wNVtMYMaPu300Cbot5LkEZ4tJaNYeHeT9dh6E= -github.com/libp2p/go-mplex v0.6.0 h1:5kKp029zrsLVJT5q6ASt4LwuZFxj3B13wXXaGmFrWg0= -github.com/libp2p/go-mplex v0.6.0/go.mod h1:y26Lx+wNVtMYMaPu300Cbot5LkEZ4tJaNYeHeT9dh6E= +github.com/libp2p/go-mplex v0.7.0 h1:BDhFZdlk5tbr0oyFq/xv/NPGfjbnrsDam1EvutpBDbY= +github.com/libp2p/go-mplex v0.7.0/go.mod h1:rW8ThnRcYWft/Jb2jeORBmPd6xuG3dGxWN/W168L9EU= github.com/libp2p/go-msgio v0.0.2/go.mod h1:63lBBgOTDKQL6EWazRMCwXsEeEeK9O2Cd+0+6OOuipQ= github.com/libp2p/go-msgio v0.0.3/go.mod h1:63lBBgOTDKQL6EWazRMCwXsEeEeK9O2Cd+0+6OOuipQ= github.com/libp2p/go-msgio v0.0.4/go.mod h1:63lBBgOTDKQL6EWazRMCwXsEeEeK9O2Cd+0+6OOuipQ= github.com/libp2p/go-msgio v0.0.6/go.mod h1:4ecVB6d9f4BDSL5fqvPiC4A3KivjWn+Venn/1ALLMWA= -github.com/libp2p/go-msgio v0.1.0 h1:8Q7g/528ivAlfXTFWvWhVjTE8XG8sDTkRUKPYh9+5Q8= github.com/libp2p/go-msgio v0.1.0/go.mod h1:eNlv2vy9V2X/kNldcZ+SShFE++o2Yjxwx6RAYsmgJnE= +github.com/libp2p/go-msgio v0.2.0 h1:W6shmB+FeynDrUVl2dgFQvzfBZcXiyqY4VmpQLu9FqU= +github.com/libp2p/go-msgio v0.2.0/go.mod h1:dBVM1gW3Jk9XqHkU4eKdGvVHdLa51hoGfll6jMJMSlY= github.com/libp2p/go-nat v0.0.3/go.mod h1:88nUEt0k0JD45Bk93NIwDqjlhiOwOoV36GchpcVc1yI= github.com/libp2p/go-nat v0.0.4/go.mod h1:Nmw50VAvKuk38jUBcmNh6p9lUJLoODbJRvYAa/+KSDo= github.com/libp2p/go-nat v0.0.5/go.mod h1:B7NxsVNPZmRLvMOwiEO1scOSyjA56zxYAGv1yQgRkEU= @@ -1082,8 +1096,9 @@ github.com/libp2p/go-yamux/v2 v2.0.0/go.mod h1:NVWira5+sVUIU6tu1JWvaRn1dRnG+cawO github.com/libp2p/go-yamux/v2 v2.2.0/go.mod h1:3So6P6TV6r75R9jiBpiIKgU/66lOarCZjqROGxzPpPQ= github.com/libp2p/go-yamux/v2 v2.3.0/go.mod h1:iTU+lOIn/2h0AgKcL49clNTwfEw+WSfDYrXe05EyKIs= github.com/libp2p/go-yamux/v3 v3.0.1/go.mod h1:s2LsDhHbh+RfCsQoICSYt58U2f8ijtPANFD8BmE74Bo= -github.com/libp2p/go-yamux/v3 v3.0.2 h1:LW0q5+A1Wy0npEsPJP9wmare2NH4ohNluN5EWVwv2mE= github.com/libp2p/go-yamux/v3 v3.0.2/go.mod h1:s2LsDhHbh+RfCsQoICSYt58U2f8ijtPANFD8BmE74Bo= +github.com/libp2p/go-yamux/v3 v3.1.1 h1:X0qSVodCZciOu/f4KTp9V+O0LAqcqP2tdaUGB0+0lng= +github.com/libp2p/go-yamux/v3 v3.1.1/go.mod h1:jeLEQgLXqE2YqX1ilAClIfCMDY+0uXQUKmmb/qp0gT4= github.com/libp2p/zeroconf/v2 v2.1.1 h1:XAuSczA96MYkVwH+LqqqCUZb2yH3krobMJ1YE+0hG2s= github.com/libp2p/zeroconf/v2 v2.1.1/go.mod h1:fuJqLnUwZTshS3U/bMRJ3+ow/v9oid1n0DmyYyNO1Xs= github.com/lightstep/lightstep-tracer-common/golang/gogo v0.0.0-20190605223551-bc2310a04743/go.mod h1:qklhhLq1aX+mtWk9cPHPzaBjWImj5ULL6C7HFJtXQMM= @@ -1092,8 +1107,9 @@ github.com/lucas-clemente/quic-go v0.19.3/go.mod h1:ADXpNbTQjq1hIzCpB+y/k5iz4n4z github.com/lucas-clemente/quic-go v0.21.2/go.mod h1:vF5M1XqhBAHgbjKcJOXY3JZz3GP0T3FQhz/uyOUS38Q= github.com/lucas-clemente/quic-go v0.23.0/go.mod h1:paZuzjXCE5mj6sikVLMvqXk8lJV2AsqtJ6bDhjEfxx0= github.com/lucas-clemente/quic-go v0.24.0/go.mod h1:paZuzjXCE5mj6sikVLMvqXk8lJV2AsqtJ6bDhjEfxx0= -github.com/lucas-clemente/quic-go v0.25.0 h1:K+X9Gvd7JXsOHtU0N2icZ2Nw3rx82uBej3mP4CLgibc= github.com/lucas-clemente/quic-go v0.25.0/go.mod h1:YtzP8bxRVCBlO77yRanE264+fY/T2U9ZlW1AaHOsMOg= +github.com/lucas-clemente/quic-go v0.27.0 h1:v6WY87q9zD4dKASbG8hy/LpzAVNzEQzw8sEIeloJsc4= +github.com/lucas-clemente/quic-go v0.27.0/go.mod h1:AzgQoPda7N+3IqMMMkywBKggIFo2KT6pfnlrQ2QieeI= github.com/lunixbochs/vtclean v1.0.0/go.mod h1:pHhQNgMf3btfWnGBVipUOjRYhoOsdGqdm/+2c2E2WMI= github.com/lyft/protoc-gen-validate v0.0.13/go.mod h1:XbGvPuh87YZc5TdIa2/I4pLk0QoUACkjt2znoq26NVQ= github.com/magiconair/properties v1.8.0/go.mod h1:PppfXfuXeibc/6YijjN8zIbojt8czPbwD3XqdrwzmxQ= @@ -1104,13 +1120,16 @@ github.com/marten-seemann/qtls v0.10.0/go.mod h1:UvMd1oaYDACI99/oZUYLzMCkBXQVT0a github.com/marten-seemann/qtls-go1-15 v0.1.1/go.mod h1:GyFwywLKkRt+6mfU99csTEY1joMZz5vmB1WNZH3P81I= github.com/marten-seemann/qtls-go1-15 v0.1.4/go.mod h1:GyFwywLKkRt+6mfU99csTEY1joMZz5vmB1WNZH3P81I= github.com/marten-seemann/qtls-go1-15 v0.1.5/go.mod h1:GyFwywLKkRt+6mfU99csTEY1joMZz5vmB1WNZH3P81I= -github.com/marten-seemann/qtls-go1-16 v0.1.4 h1:xbHbOGGhrenVtII6Co8akhLEdrawwB2iHl5yhJRpnco= github.com/marten-seemann/qtls-go1-16 v0.1.4/go.mod h1:gNpI2Ol+lRS3WwSOtIUUtRwZEQMXjYK+dQSBFbethAk= +github.com/marten-seemann/qtls-go1-16 v0.1.5 h1:o9JrYPPco/Nukd/HpOHMHZoBDXQqoNtUCmny98/1uqQ= +github.com/marten-seemann/qtls-go1-16 v0.1.5/go.mod h1:gNpI2Ol+lRS3WwSOtIUUtRwZEQMXjYK+dQSBFbethAk= github.com/marten-seemann/qtls-go1-17 v0.1.0-rc.1/go.mod h1:fz4HIxByo+LlWcreM4CZOYNuz3taBQ8rN2X6FqvaWo8= -github.com/marten-seemann/qtls-go1-17 v0.1.0 h1:P9ggrs5xtwiqXv/FHNwntmuLMNq3KaSIG93AtAZ48xk= github.com/marten-seemann/qtls-go1-17 v0.1.0/go.mod h1:fz4HIxByo+LlWcreM4CZOYNuz3taBQ8rN2X6FqvaWo8= -github.com/marten-seemann/qtls-go1-18 v0.1.0-beta.1 h1:EnzzN9fPUkUck/1CuY1FlzBaIYMoiBsdwTNmNGkwUUM= +github.com/marten-seemann/qtls-go1-17 v0.1.1 h1:DQjHPq+aOzUeh9/lixAGunn6rIOQyWChPSI4+hgW7jc= +github.com/marten-seemann/qtls-go1-17 v0.1.1/go.mod h1:C2ekUKcDdz9SDWxec1N/MvcXBpaX9l3Nx67XaR84L5s= github.com/marten-seemann/qtls-go1-18 v0.1.0-beta.1/go.mod h1:PUhIQk19LoFt2174H4+an8TYvWOGjb/hHwphBeaDHwI= +github.com/marten-seemann/qtls-go1-18 v0.1.1 h1:qp7p7XXUFL7fpBvSS1sWD+uSqPvzNQK43DH+/qEkj0Y= +github.com/marten-seemann/qtls-go1-18 v0.1.1/go.mod h1:mJttiymBAByA49mhlNZZGrH5u1uXYZJ+RW28Py7f4m4= github.com/marten-seemann/tcp v0.0.0-20210406111302-dfbc87cc63fd h1:br0buuQ854V8u83wA0rVZ8ttrq5CpaPZdvrK0LP2lOk= github.com/marten-seemann/tcp v0.0.0-20210406111302-dfbc87cc63fd/go.mod h1:QuCEs1Nt24+FYQEqAAncTDPJIuGs+LxK1MCiFL25pMU= github.com/mattn/go-colorable v0.0.9/go.mod h1:9vuHe8Xs5qXnSaW/c/ABM9alt+Vo+STaOChaDxuIBZU= @@ -1139,8 +1158,9 @@ github.com/miekg/dns v1.1.12/go.mod h1:W1PPwlIAgtquWBMBEV9nkV9Cazfe8ScdGz/Lj7v3N github.com/miekg/dns v1.1.28/go.mod h1:KNUDUusw/aVsxyTYZM1oqvCicbwhgbNgztCETuNZ7xM= github.com/miekg/dns v1.1.31/go.mod h1:KNUDUusw/aVsxyTYZM1oqvCicbwhgbNgztCETuNZ7xM= github.com/miekg/dns v1.1.41/go.mod h1:p6aan82bvRIyn+zDIv9xYNUpwa73JcSh9BKwknJysuI= -github.com/miekg/dns v1.1.43 h1:JKfpVSCB84vrAmHzyrsxB5NAr5kLoMXZArPSw7Qlgyg= github.com/miekg/dns v1.1.43/go.mod h1:+evo5L0630/F6ca/Z9+GAqzhjGyn8/c+TBaOyfEl0V4= +github.com/miekg/dns v1.1.48 h1:Ucfr7IIVyMBz4lRE8qmGUuZ4Wt3/ZGu9hmcMT3Uu4tQ= +github.com/miekg/dns v1.1.48/go.mod h1:e3IlAVfNqAllflbibAZEWOXOQ+Ynzk/dDozDxY7XnME= github.com/mikioh/tcp v0.0.0-20190314235350-803a9b46060c h1:bzE/A84HN25pxAuk9Eej1Kz9OUelF97nAc82bDquQI8= github.com/mikioh/tcp v0.0.0-20190314235350-803a9b46060c/go.mod h1:0SQS9kMwD2VsyFEB++InYyBJroV/FRmBgcydeSUcJms= github.com/mikioh/tcpinfo v0.0.0-20190314235526-30a79bb1804b h1:z78hV3sbSMAUoyUMM0I83AUIT6Hu17AWfgjzIbtrYFc= @@ -1176,8 +1196,9 @@ github.com/mr-tron/base58 v1.1.2/go.mod h1:BinMc/sQntlIE1frQmRFPUoPA1Zkr8VRgBdjW github.com/mr-tron/base58 v1.1.3/go.mod h1:BinMc/sQntlIE1frQmRFPUoPA1Zkr8VRgBdjWI2mNwc= github.com/mr-tron/base58 v1.2.0 h1:T/HDJBh4ZCPbU39/+c3rRvE0uKBQlU27+QI8LJ4t64o= github.com/mr-tron/base58 v1.2.0/go.mod h1:BinMc/sQntlIE1frQmRFPUoPA1Zkr8VRgBdjWI2mNwc= -github.com/multiformats/go-base32 v0.0.3 h1:tw5+NhuwaOjJCC5Pp82QuXbrmLzWg7uxlMFp8Nq/kkI= github.com/multiformats/go-base32 v0.0.3/go.mod h1:pLiuGC8y0QR3Ue4Zug5UzK9LjgbkL8NSQj0zQ5Nz/AA= +github.com/multiformats/go-base32 v0.0.4 h1:+qMh4a2f37b4xTNs6mqitDinryCI+tfO2dRVMN9mjSE= +github.com/multiformats/go-base32 v0.0.4/go.mod h1:jNLFzjPZtp3aIARHbJRZIaPuspdH0J6q39uUM5pnABM= github.com/multiformats/go-base36 v0.1.0 h1:JR6TyF7JjGd3m6FbLU2cOxhC0Li8z8dLNGQ89tUg4F4= github.com/multiformats/go-base36 v0.1.0/go.mod h1:kFGE83c6s80PklsHO9sRn2NCoffoRdUUOENyW/Vv6sM= github.com/multiformats/go-multiaddr v0.0.1/go.mod h1:xKVEak1K9cS1VdmPZW3LSIb6lgmoS58qz/pzqmAxV44= @@ -1237,8 +1258,9 @@ github.com/multiformats/go-multistream v0.1.0/go.mod h1:fJTiDfXJVmItycydCnNx4+wS github.com/multiformats/go-multistream v0.1.1/go.mod h1:KmHZ40hzVxiaiwlj3MEbYgK9JFk2/9UktWZAF54Du38= github.com/multiformats/go-multistream v0.2.0/go.mod h1:5GZPQZbkWOLOn3J2y4Y99vVW7vOfsAflxARk3x14o6k= github.com/multiformats/go-multistream v0.2.1/go.mod h1:5GZPQZbkWOLOn3J2y4Y99vVW7vOfsAflxARk3x14o6k= -github.com/multiformats/go-multistream v0.2.2 h1:TCYu1BHTDr1F/Qm75qwYISQdzGcRdC21nFgQW7l7GBo= github.com/multiformats/go-multistream v0.2.2/go.mod h1:UIcnm7Zuo8HKG+HkWgfQsGL+/MIEhyTqbODbIUwSXKs= +github.com/multiformats/go-multistream v0.3.0 h1:yX1v4IWseLPmr0rmnDo148wWJbNx40JxBZGmQb5fUP4= +github.com/multiformats/go-multistream v0.3.0/go.mod h1:ODRoqamLUsETKS9BNcII4gcRsJBU5VAwRIv7O39cEXg= github.com/multiformats/go-varint v0.0.1/go.mod h1:3Ls8CIEsrijN6+B7PbrXRPxHRPuXSrVKRY101jdMZYE= github.com/multiformats/go-varint v0.0.2/go.mod h1:3Ls8CIEsrijN6+B7PbrXRPxHRPuXSrVKRY101jdMZYE= github.com/multiformats/go-varint v0.0.5/go.mod h1:3Ls8CIEsrijN6+B7PbrXRPxHRPuXSrVKRY101jdMZYE= @@ -1527,6 +1549,7 @@ github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9de github.com/yuin/goldmark v1.1.32/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= github.com/yuin/goldmark v1.3.5/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k= +github.com/yuin/goldmark v1.4.1/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k= go.etcd.io/bbolt v1.3.3/go.mod h1:IbVyRI1SCnLcuJnV2u8VeU0CEYM7e686BmAb1XKL+uU= go.etcd.io/etcd v0.0.0-20191023171146-3cf2f69b5738/go.mod h1:dnLIgRNXwCJa5e+c6mIZCrds/GIG4ncV9HhK5PX7jPg= go.opencensus.io v0.18.0/go.mod h1:vKdFvxhtzZ9onBp9VKHK8z/sRpBMnKAsufL7wlDrCOA= @@ -1598,8 +1621,9 @@ go.uber.org/multierr v1.1.0/go.mod h1:wR5kodmAFQ0UK8QlbwjlSNy0Z68gJhDJUG5sjR94q/ go.uber.org/multierr v1.3.0/go.mod h1:VgVr7evmIr6uPjLBxg28wmKNXyqE9akIJ5XnfpiKl+4= go.uber.org/multierr v1.5.0/go.mod h1:FeouvMocqHpRaaGuG9EjoKcStLC43Zu/fmqdUMPcKYU= go.uber.org/multierr v1.6.0/go.mod h1:cdWPpRnG4AhwMwsgIHip0KRBQjJy5kYEpYjJxpXp9iU= -go.uber.org/multierr v1.7.0 h1:zaiO/rmgFjbmCXdSYJWQcdvOCsthmdaHfr3Gm2Kx4Ec= go.uber.org/multierr v1.7.0/go.mod h1:7EAYxJLBy9rStEaz58O2t4Uvip6FSURkq8/ppBp95ak= +go.uber.org/multierr v1.8.0 h1:dg6GjLku4EH+249NNmoIciG9N/jURbDG+pFlTkhzIC8= +go.uber.org/multierr v1.8.0/go.mod h1:7EAYxJLBy9rStEaz58O2t4Uvip6FSURkq8/ppBp95ak= go.uber.org/tools v0.0.0-20190618225709-2cfd321de3ee/go.mod h1:vJERXedbb3MVM5f9Ejo0C68/HhF8uaILCdgjnY+goOA= go.uber.org/zap v1.10.0/go.mod h1:vwi/ZaCAaUcBkycHslxD9B2zi4UTXhF60s6SWpuDF0Q= go.uber.org/zap v1.13.0/go.mod h1:zwrFLgMcdUuIBviXEYEH1YKNaOBnKXsx2IPda5bBwHM= @@ -1649,8 +1673,9 @@ golang.org/x/crypto v0.0.0-20210513164829-c07d793c2f9a/go.mod h1:P+XmwS30IXTQdn5 golang.org/x/crypto v0.0.0-20210711020723-a769d52b0f97/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= golang.org/x/crypto v0.0.0-20210813211128-0a44fdfbc16e/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= golang.org/x/crypto v0.0.0-20210920023735-84f357641f63/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= -golang.org/x/crypto v0.0.0-20210921155107-089bfa567519 h1:7I4JAnoQBe7ZtJcBaYHi5UtiO8tQHbUSXxL+pnGRANg= golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= +golang.org/x/crypto v0.0.0-20220411220226-7b82a4e95df4 h1:kUhD7nTDoI3fVd9G4ORWrbV5NY0liEs/Jg2pv5f+bBA= +golang.org/x/crypto v0.0.0-20220411220226-7b82a4e95df4/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4= golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= golang.org/x/exp v0.0.0-20190306152737-a1d7652674e8/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= golang.org/x/exp v0.0.0-20190510132918-efd6b22b2522/go.mod h1:ZjyILWgesfNpC6sMxTJOJm9Kp84zZh5NQWvqDGG3Qr8= @@ -1687,8 +1712,9 @@ golang.org/x/mod v0.1.1-0.20191107180719-034126e5016b/go.mod h1:QqPTAvyqsEbceGzB golang.org/x/mod v0.1.1-0.20191209134235-331c550502dd/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= golang.org/x/mod v0.2.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= -golang.org/x/mod v0.4.2 h1:Gz96sIWK3OalVv/I/qNygP42zyoKp3xptRVCWRFEBvo= golang.org/x/mod v0.4.2/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= +golang.org/x/mod v0.6.0-dev.0.20220106191415-9b9b3d81d5e3 h1:kQgndtyPBW/JIYERgdxfwMYh3AVStj88WQTlNDi2a+o= +golang.org/x/mod v0.6.0-dev.0.20220106191415-9b9b3d81d5e3/go.mod h1:3p9vT2HGsQu2K1YbXdKPJLVgG5VJdoTa1poYQBtP1AY= golang.org/x/net v0.0.0-20180719180050-a680a1efc54d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= @@ -1744,11 +1770,15 @@ golang.org/x/net v0.0.0-20210423184538-5f58ad60dda6/go.mod h1:OJAsFXCWl8Ukc7SiCT golang.org/x/net v0.0.0-20210428140749-89ef3d95e781/go.mod h1:OJAsFXCWl8Ukc7SiCT/9KSuxbyM7479/AVlXFRxuMCk= golang.org/x/net v0.0.0-20210505024714-0287a6fb4125/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= golang.org/x/net v0.0.0-20210525063256-abc453219eb5/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= +golang.org/x/net v0.0.0-20210726213435-c6fcb2dbf985/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= golang.org/x/net v0.0.0-20210813160813-60bc85c4be6d/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= golang.org/x/net v0.0.0-20210917221730-978cfadd31cf/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= +golang.org/x/net v0.0.0-20211015210444-4f30a5c0130f/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= +golang.org/x/net v0.0.0-20211112202133-69e39bad7dc2/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= golang.org/x/net v0.0.0-20220127200216-cd36cc0744dd/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk= -golang.org/x/net v0.0.0-20220225172249-27dd8689420f h1:oA4XRj0qtSt8Yo1Zms0CUlsT3KG69V2UGQWPBxujDmc= golang.org/x/net v0.0.0-20220225172249-27dd8689420f/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk= +golang.org/x/net v0.0.0-20220418201149-a630d4f3e7a2 h1:6mzvA99KwZxbOrxww4EvWVQUnN1+xEu9tafK5ZxkYeA= +golang.org/x/net v0.0.0-20220418201149-a630d4f3e7a2/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk= golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= golang.org/x/oauth2 v0.0.0-20181017192945-9dcd33a902f4/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= golang.org/x/oauth2 v0.0.0-20181203162652-d668ce993890/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= @@ -1858,10 +1888,11 @@ golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBc golang.org/x/sys v0.0.0-20210630005230-0f9fa26af87c/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20210816183151-1e6c022a8912/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20210903071746-97244b99971b/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20211019181941-9d821ace8654/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20211216021012-1d35b9e2eb4e/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220114195835-da31bd327af9/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20220408201424-a24fb2fb8a0f h1:8w7RhxzTVgUzw/AH/9mUV5q0vMgy40SQRursCcfmkCw= -golang.org/x/sys v0.0.0-20220408201424-a24fb2fb8a0f/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220412211240-33da011f77ad h1:ntjMns5wyP/fN65tdBD4g8J5w8n015+iIIs9rtjXkY0= +golang.org/x/sys v0.0.0-20220412211240-33da011f77ad/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/term v0.0.0-20201117132131-f5c789dd3221/go.mod h1:Nr5EML6q2oocZ2LXRh80K7BxOlk5/8JxuGnuhpl+muw= golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= golang.org/x/term v0.0.0-20210927222741-03fcf44c2211 h1:JGgROgKl9N8DuW20oFS5gxc+lE67/N3FcwmBPMe7ArY= @@ -1937,13 +1968,16 @@ golang.org/x/tools v0.0.0-20201224043029-2b0845dc783e/go.mod h1:emZCQorbCU4vsT4f golang.org/x/tools v0.0.0-20210106214847-113979e3529a/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= golang.org/x/tools v0.1.0/go.mod h1:xkSsbof2nBLbhDlRMhhhyNLN/zl3eTqcnHD5viDpcZ0= golang.org/x/tools v0.1.1/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk= -golang.org/x/tools v0.1.5 h1:ouewzE6p+/VEB31YYnTbEJdi8pFqKp4P4n85vwo3DHA= golang.org/x/tools v0.1.5/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk= +golang.org/x/tools v0.1.6-0.20210726203631-07bc1bf47fb2/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk= +golang.org/x/tools v0.1.10 h1:QjFRCZxdOhBJ/UNgnBZLbNV13DlbnK0quyivTnXJM20= +golang.org/x/tools v0.1.10/go.mod h1:Uh6Zz+xoGYZom868N8YTex3t7RhtHDBrE8Gzo9bV56E= golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= -golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1 h1:go1bK/D/BFZV2I8cIQd1NKEZ+0owSTG1fDTci4IqFcE= golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= +golang.org/x/xerrors v0.0.0-20220411194840-2f41105eb62f h1:GGU+dLjvlC3qDwqYgL6UgRmHXhOOgns0bZu2Ty5mm6U= +golang.org/x/xerrors v0.0.0-20220411194840-2f41105eb62f/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= google.golang.org/api v0.0.0-20180910000450-7ca32eb868bf/go.mod h1:4mhQ8q/RsB7i+udVvVy5NUi08OU8ZlA0gRVgrF7VFY0= google.golang.org/api v0.0.0-20181030000543-1d582fd0359e/go.mod h1:4mhQ8q/RsB7i+udVvVy5NUi08OU8ZlA0gRVgrF7VFY0= google.golang.org/api v0.1.0/go.mod h1:UGEZY7KEX120AnNLIHFMKIo4obdJhkp2tPbaPlQx13Y= @@ -2096,8 +2130,9 @@ honnef.co/go/tools v0.0.1-2019.2.3/go.mod h1:a3bituU0lyd329TUQxRnasdCoJDkEUEAqEt honnef.co/go/tools v0.0.1-2020.1.3/go.mod h1:X/FiERA/W4tHapMX5mGpAtMSVEeEUOyHaw9vFzvIQ3k= honnef.co/go/tools v0.0.1-2020.1.4/go.mod h1:X/FiERA/W4tHapMX5mGpAtMSVEeEUOyHaw9vFzvIQ3k= honnef.co/go/tools v0.1.3/go.mod h1:NgwopIslSNH47DimFoV78dnkksY2EFtX0ajyb3K/las= -lukechampine.com/blake3 v1.1.6 h1:H3cROdztr7RCfoaTpGZFQsrqvweFLrqS73j7L7cmR5c= lukechampine.com/blake3 v1.1.6/go.mod h1:tkKEOtDkNtklkXtLNEOGNq5tcV90tJiA1vAA12R78LA= +lukechampine.com/blake3 v1.1.7 h1:GgRMhmdsuK8+ii6UZFDL8Nb+VyMwadAgcJyfYHxG6n0= +lukechampine.com/blake3 v1.1.7/go.mod h1:tkKEOtDkNtklkXtLNEOGNq5tcV90tJiA1vAA12R78LA= pgregory.net/rapid v0.4.7 h1:MTNRktPuv5FNqOO151TM9mDTa+XHcX6ypYeISDVD14g= pgregory.net/rapid v0.4.7/go.mod h1:UYpPVyjFHzYBGHIxLFoupi8vwk6rXNzRY9OMvVxFIOU= rsc.io/binaryregexp v0.2.0/go.mod h1:qTv7/COck+e2FymRvadv62gMdZztPaShugOCi3I+8D8= diff --git a/test/sharness/.gitignore b/test/sharness/.gitignore index 06ceccc7567..c7ab08146c5 100644 --- a/test/sharness/.gitignore +++ b/test/sharness/.gitignore @@ -2,3 +2,4 @@ lib/sharness/ test-results/ trash directory.*.sh/ plugins +*.DS_Store diff --git a/test/sharness/t0060-daemon.sh b/test/sharness/t0060-daemon.sh index e04060e45c8..d448e035b46 100755 --- a/test/sharness/t0060-daemon.sh +++ b/test/sharness/t0060-daemon.sh @@ -125,11 +125,26 @@ test_expect_success "ipfs help output looks good" ' test_fsh cat help.txt ' -# check transport is encrypted -test_expect_success SOCAT "transport should be encrypted ( needs socat )" ' - socat - tcp:localhost:$SWARM_PORT,connect-timeout=1 > swarmnc < ../t0060-data/mss-ls && +# check transport is encrypted by default and no plaintext is allowed + +test_expect_success SOCAT "default transport should support encryption (TLS, needs socat )" ' + socat - tcp:localhost:$SWARM_PORT,connect-timeout=1 > swarmnc < ../t0060-data/mss-tls && grep -q "/tls" swarmnc && - test_must_fail grep -q "/plaintext/1.0.0" swarmnc || + test_must_fail grep -q "na" swarmnc || + test_fsh cat swarmnc +' + +test_expect_success SOCAT "default transport should support encryption (Noise, needs socat )" ' + socat - tcp:localhost:$SWARM_PORT,connect-timeout=1 > swarmnc < ../t0060-data/mss-noise && + grep -q "/noise" swarmnc && + test_must_fail grep -q "na" swarmnc || + test_fsh cat swarmnc +' + +test_expect_success SOCAT "default transport should not support plaintext (needs socat )" ' + socat - tcp:localhost:$SWARM_PORT,connect-timeout=1 > swarmnc < ../t0060-data/mss-plaintext && + grep -q "na" swarmnc && + test_must_fail grep -q "/plaintext" swarmnc || test_fsh cat swarmnc ' diff --git a/test/sharness/t0060-data/mss-ls b/test/sharness/t0060-data/mss-noise similarity index 71% rename from test/sharness/t0060-data/mss-ls rename to test/sharness/t0060-data/mss-noise index ce39aa9990a..f9d349802e6 100644 --- a/test/sharness/t0060-data/mss-ls +++ b/test/sharness/t0060-data/mss-noise @@ -1,2 +1,2 @@ /multistream/1.0.0 -ls +/noise diff --git a/test/sharness/t0060-data/mss-plaintext b/test/sharness/t0060-data/mss-plaintext new file mode 100644 index 00000000000..e6057b493ef --- /dev/null +++ b/test/sharness/t0060-data/mss-plaintext @@ -0,0 +1,2 @@ +/multistream/1.0.0 +/plaintext/2.0.0 diff --git a/test/sharness/t0060-data/mss-tls b/test/sharness/t0060-data/mss-tls new file mode 100644 index 00000000000..92294bb5b01 --- /dev/null +++ b/test/sharness/t0060-data/mss-tls @@ -0,0 +1,2 @@ +/multistream/1.0.0 + /tls/1.0.0 diff --git a/test/sharness/t0061-daemon-opts.sh b/test/sharness/t0061-daemon-opts.sh index 108fe75abce..531d2d247a5 100755 --- a/test/sharness/t0061-daemon-opts.sh +++ b/test/sharness/t0061-daemon-opts.sh @@ -18,8 +18,9 @@ apiaddr=$API_ADDR # Odd. this fails here, but the inverse works on t0060-daemon. test_expect_success SOCAT 'transport should be unencrypted ( needs socat )' ' - socat - tcp:localhost:$SWARM_PORT,connect-timeout=1 > swarmnc < ../t0060-data/mss-ls && - grep -q "/plaintext" swarmnc || + socat - tcp:localhost:$SWARM_PORT,connect-timeout=1 > swarmnc < ../t0060-data/mss-plaintext && + grep -q "/plaintext" swarmnc && + test_must_fail grep -q "na" swarmnc || test_fsh cat swarmnc ' diff --git a/test/sharness/t0160-resolve.sh b/test/sharness/t0160-resolve.sh index 600e4c07bba..4b967704946 100755 --- a/test/sharness/t0160-resolve.sh +++ b/test/sharness/t0160-resolve.sh @@ -125,7 +125,7 @@ test_resolve_cmd_b32() { local self_hash_b32libp2pkey=$(echo $self_hash | ipfs cid format -v 1 -b b --codec libp2p-key) test_expect_success "resolve of /ipns/{cidv1} with multicodec other than libp2p-key returns a meaningful error" ' test_expect_code 1 ipfs resolve /ipns/$self_hash_b32protobuf 2>cidcodec_error && - grep "Error: peer ID represented as CIDv1 require libp2p-key multicodec: retry with /ipns/$self_hash_b32libp2pkey" cidcodec_error + test_should_contain "Error: peer ID represented as CIDv1 require libp2p-key multicodec: retry with /ipns/$self_hash_b32libp2pkey" cidcodec_error ' } diff --git a/test/sharness/t0182-circuit-relay.sh b/test/sharness/t0182-circuit-relay.sh index 2b855844db0..d6e439ae318 100755 --- a/test/sharness/t0182-circuit-relay.sh +++ b/test/sharness/t0182-circuit-relay.sh @@ -31,8 +31,14 @@ test_expect_success 'configure the relay node as a static relay for node A' ' ' test_expect_success 'configure the relay node' ' - ipfsi 1 config --json Addresses.Swarm "$relayaddrs" && - ipfsi 1 config Internal.Libp2pForceReachability public + ipfsi 1 config Internal.Libp2pForceReachability public && + ipfsi 1 config --json Swarm.RelayService.Enabled true && + ipfsi 1 config --json Addresses.Swarm "$relayaddrs" +' + +test_expect_success 'configure the node B' ' + ipfsi 2 config Internal.Libp2pForceReachability private && + ipfsi 2 config --json Swarm.RelayClient.Enabled true ' test_expect_success 'restart nodes' ' @@ -50,7 +56,14 @@ test_expect_success 'connect B <-> Relay' ' ' test_expect_success 'wait until relay is ready to do work' ' - sleep 1 + while ! ipfsi 2 swarm connect /p2p/$PEERID_1/p2p-circuit/p2p/$PEERID_0; do + iptb stop && + iptb_wait_stop && + iptb start -wait -- --routing=none && + iptb connect 0 1 && + iptb connect 2 1 && + sleep 5 + done ' test_expect_success 'connect A <-Relay-> B' ' diff --git a/test/sharness/t0280-plugin-dag-jose.sh b/test/sharness/t0280-plugin-dag-jose.sh old mode 100644 new mode 100755 From 4f7d4bcc0581f8157523f0a05a4a7665669a7572 Mon Sep 17 00:00:00 2001 From: SukkaW Date: Thu, 28 Apr 2022 21:39:42 +0800 Subject: [PATCH 372/414] docs: replace all git.io links with their actual URLs --- core/commands/root.go | 2 +- core/coreapi/unixfs.go | 2 +- docs/implement-api-bindings.md | 12 ++++++------ fuse/node/mount_notsupp.go | 2 +- test/sharness/t0112-gateway-cors.sh | 4 ++-- 5 files changed, 11 insertions(+), 11 deletions(-) diff --git a/core/commands/root.go b/core/commands/root.go index ef17d2f70c7..bbdb019766c 100644 --- a/core/commands/root.go +++ b/core/commands/root.go @@ -152,7 +152,7 @@ var rootSubcommands = map[string]*cmds.Command{ "swarm": SwarmCmd, "tar": TarCmd, "file": unixfs.UnixFSCmd, - "update": ExternalBinary("Please see https://git.io/fjylH for installation instructions."), + "update": ExternalBinary("Please see https://github.com/ipfs/ipfs-update/blob/master/README.md#install for installation instructions."), "urlstore": urlStoreCmd, "version": VersionCmd, "shutdown": daemonShutdownCmd, diff --git a/core/coreapi/unixfs.go b/core/coreapi/unixfs.go index 5d3d7e80e30..da1202f60cb 100644 --- a/core/coreapi/unixfs.go +++ b/core/coreapi/unixfs.go @@ -96,7 +96,7 @@ func (api *UnixfsAPI) Add(ctx context.Context, files files.Node, opts ...options //} if settings.NoCopy && !(cfg.Experimental.FilestoreEnabled || cfg.Experimental.UrlstoreEnabled) { - return nil, fmt.Errorf("either the filestore or the urlstore must be enabled to use nocopy, see: https://git.io/vNItf") + return nil, fmt.Errorf("either the filestore or the urlstore must be enabled to use nocopy, see: https://github.com/ipfs/go-ipfs/blob/master/docs/experimental-features.md#ipfs-filestore") } addblockstore := api.blockstore diff --git a/docs/implement-api-bindings.md b/docs/implement-api-bindings.md index 364f3265e2e..c7bf9bdf0df 100644 --- a/docs/implement-api-bindings.md +++ b/docs/implement-api-bindings.md @@ -63,7 +63,7 @@ In HTTP, our API layering uses a REST-like mapping, where: There is a "standard IPFS API" which is currently defined as "all the commands exposed by the go-ipfs implementation". There are auto-generated [API Docs](https://ipfs.io/docs/api/). -You can Also see [a listing here](https://git.io/v5KG1), or get a list of +You can Also see [a listing here](https://github.com/ipfs/go-ipfs/blob/94b832df861728c65e912935641d08880c341e0a/core/commands/root.go#L96-L130), or get a list of commands by running `ipfs commands` locally. ## Implementing bindings for the HTTP API @@ -80,8 +80,8 @@ To date, we have two different HTTP API clients: - [js-ipfs-api](https://github.com/ipfs/js-ipfs-api) - simple javascript wrapper -- best to look at -- [go-ipfs/commands/http](https://git.io/v5KnB) - - generalized transport based on the [command definitions](https://git.io/v5KnE) +- [go-ipfs/commands/http](https://github.com/ipfs/go-ipfs/tree/916f987de2c35db71815b54bbb9a0a71df829838/commands/http) - + generalized transport based on the [command definitions](https://github.com/ipfs/go-ipfs/tree/916f987de2c35db71815b54bbb9a0a71df829838/core/commands) The Go implementation is good to answer harder questions, like how is multipart handled, or what headers should be set in edge conditions. But the javascript @@ -90,12 +90,12 @@ implementation is very concise, and easy to follow. #### Anatomy of node-ipfs-api Currently, node-ipfs-api has three main files -- [src/index.js](https://git.io/v5Kn2) defines the functions clients of the API +- [src/index.js](https://github.com/ipfs-inactive/js-ipfs-http-client/blob/66d1462bd02181d46e8baf4cd9d476b213426ad8/src/index.js) defines the functions clients of the API module will use. uses `RequestAPI`, and translates function call parameters to the API almost directly. -- [src/get-files-stream.js](https://git.io/v5Knr) implements the hardest part: +- [src/get-files-stream.js](https://github.com/ipfs-inactive/js-ipfs-http-client/blob/66d1462bd02181d46e8baf4cd9d476b213426ad8/src/get-files-stream.js) implements the hardest part: file streaming. This one uses multipart. -- [src/request-api.js](https://git.io/v5KnP) generic function call to perform +- [src/request-api.js](https://github.com/ipfs-inactive/js-ipfs-http-client/blob/66d1462bd02181d46e8baf4cd9d476b213426ad8/src/request-api.js) generic function call to perform the actual HTTP requests ## Note on multipart + inspecting requests diff --git a/fuse/node/mount_notsupp.go b/fuse/node/mount_notsupp.go index 929cdf7df90..c1cd625a1e2 100644 --- a/fuse/node/mount_notsupp.go +++ b/fuse/node/mount_notsupp.go @@ -9,5 +9,5 @@ import ( ) func Mount(node *core.IpfsNode, fsdir, nsdir string) error { - return errors.New("FUSE not supported on OpenBSD or NetBSD. See #5334 (https://git.io/fjMuC).") + return errors.New("FUSE not supported on OpenBSD or NetBSD. See #5334 (https://github.com/ipfs/go-ipfs/issues/5334).") } diff --git a/test/sharness/t0112-gateway-cors.sh b/test/sharness/t0112-gateway-cors.sh index 9670b7ffa16..cebb4e05aab 100755 --- a/test/sharness/t0112-gateway-cors.sh +++ b/test/sharness/t0112-gateway-cors.sh @@ -77,8 +77,8 @@ test_expect_success "GET to API succeeds" ' curl -svX GET "http://127.0.0.1:$GWAY_PORT/api/v0/cat?arg=$thash" >/dev/null 2>curl_output ' # GET Response from the API should NOT contain CORS headers -# Blacklisting: https://git.io/vzaj2 -# Rationale: https://git.io/vzajX +# Blacklisting: https://github.com/ipfs/go-ipfs/blob/5d9ee59908099df3f7e85679f7384c98d4ac8111/commands/http/handler.go#L71-L82 +# Rationale: https://github.com/ipfs/go-ipfs/pull/1529#issuecomment-125702347 test_expect_success "OPTIONS response for API looks good" ' grep -q "Access-Control-Allow-" curl_output && false || true ' From 25cc85fa9359f907f348e0c2139f2b535313c56c Mon Sep 17 00:00:00 2001 From: Lucas Molas Date: Thu, 28 Apr 2022 14:36:57 -0300 Subject: [PATCH 373/414] feat(gateway): Gateway.FastDirIndexThreshold (#8853) * fix(core/gateway): option to limit directory size listing * feat(gw): HTMLDirListingLimit This is alternative take on the way we limit the HTML listing output. Instead of a hard cut-off, we list up to HTMLDirListingLimit. When a directory has more items than HTMLDirListingLimit we show additional header and footer informing user that only $HTMLDirListingLimit items are listed. This is a better UX. * fix: 0 disables Gateway.HTMLDirListingLimit * refactor: Gateway.FastDirIndexThreshold see explainer in docs/config.md * refactor: prealoc slices * docs: Gateway.FastDirIndexThreshold * refactor: core/corehttp/gateway_handler.go https://github.com/ipfs/go-ipfs/pull/8853#discussion_r851437088 * docs: apply suggestions from code review Co-authored-by: Alan Shaw Co-authored-by: Marcin Rataj Co-authored-by: Alan Shaw --- assets/dir-index-html/dir-index.html | 2 +- assets/dir-index-html/src/dir-index.html | 2 +- assets/dir-index-html/test/main.go | 17 +++--- config/gateway.go | 10 +++- core/coreapi/unixfs.go | 2 +- core/corehttp/gateway.go | 14 +++-- core/corehttp/gateway_handler_unixfs.go | 2 + core/corehttp/gateway_handler_unixfs_dir.go | 66 ++++++++++++--------- core/corehttp/gateway_indexPage.go | 17 +++--- docs/config.md | 15 +++++ test/sharness/lib/test-lib.sh | 9 +++ test/sharness/t0115-gateway-dir-listing.sh | 26 +++++++- 12 files changed, 128 insertions(+), 54 deletions(-) diff --git a/assets/dir-index-html/dir-index.html b/assets/dir-index-html/dir-index.html index ec00da79880..49ac2bb1f1a 100644 --- a/assets/dir-index-html/dir-index.html +++ b/assets/dir-index-html/dir-index.html @@ -31,7 +31,7 @@

    diff --git a/assets/dir-index-html/src/dir-index.html b/assets/dir-index-html/src/dir-index.html index f3dfd632878..376c4cd7705 100644 --- a/assets/dir-index-html/src/dir-index.html +++ b/assets/dir-index-html/src/dir-index.html @@ -30,7 +30,7 @@ diff --git a/assets/dir-index-html/test/main.go b/assets/dir-index-html/test/main.go index c02523a9f40..43b4a098101 100644 --- a/assets/dir-index-html/test/main.go +++ b/assets/dir-index-html/test/main.go @@ -12,14 +12,15 @@ const templateFile = "../dir-index.html" // Copied from go-ipfs/core/corehttp/gateway_indexPage.go type listingTemplateData struct { - GatewayURL string - DNSLink bool - Listing []directoryItem - Size string - Path string - Breadcrumbs []breadcrumb - BackLink string - Hash string + GatewayURL string + DNSLink bool + Listing []directoryItem + Size string + Path string + Breadcrumbs []breadcrumb + BackLink string + Hash string + FastDirIndexThreshold int } type directoryItem struct { diff --git a/config/gateway.go b/config/gateway.go index e85cda98688..486089b7123 100644 --- a/config/gateway.go +++ b/config/gateway.go @@ -53,7 +53,15 @@ type Gateway struct { // } PathPrefixes []string - // FIXME: Not yet implemented + // FastDirIndexThreshold is the maximum number of items in a directory + // before the Gateway switches to a shallow, faster listing which only + // requires the root node. This allows for listing big directories fast, + // without the linear slowdown caused by reading size metadata from child + // nodes. + // Setting to 0 will enable fast listings for all directories. + FastDirIndexThreshold *OptionalInteger `json:",omitempty"` + + // FIXME: Not yet implemented: https://github.com/ipfs/go-ipfs/issues/8059 APICommands []string // NoFetch configures the gateway to _not_ fetch blocks in response to diff --git a/core/coreapi/unixfs.go b/core/coreapi/unixfs.go index da1202f60cb..b4e1bbc3ee5 100644 --- a/core/coreapi/unixfs.go +++ b/core/coreapi/unixfs.go @@ -302,7 +302,7 @@ func (api *UnixfsAPI) processLink(ctx context.Context, linkres ft.LinkResult, se } func (api *UnixfsAPI) lsFromLinksAsync(ctx context.Context, dir uio.Directory, settings *options.UnixfsLsSettings) (<-chan coreiface.DirEntry, error) { - out := make(chan coreiface.DirEntry) + out := make(chan coreiface.DirEntry, uio.DefaultShardWidth) go func() { defer close(out) diff --git a/core/corehttp/gateway.go b/core/corehttp/gateway.go index 2e794b53ffc..a4ae5383179 100644 --- a/core/corehttp/gateway.go +++ b/core/corehttp/gateway.go @@ -16,9 +16,10 @@ import ( ) type GatewayConfig struct { - Headers map[string][]string - Writable bool - PathPrefixes []string + Headers map[string][]string + Writable bool + PathPrefixes []string + FastDirIndexThreshold int } // A helper function to clean up a set of headers: @@ -89,9 +90,10 @@ func GatewayOption(writable bool, paths ...string) ServeOption { }, headers[ACEHeadersName]...)) var gateway http.Handler = newGatewayHandler(GatewayConfig{ - Headers: headers, - Writable: writable, - PathPrefixes: cfg.Gateway.PathPrefixes, + Headers: headers, + Writable: writable, + PathPrefixes: cfg.Gateway.PathPrefixes, + FastDirIndexThreshold: int(cfg.Gateway.FastDirIndexThreshold.WithDefault(100)), }, api) gateway = otelhttp.NewHandler(gateway, "Gateway.Request") diff --git a/core/corehttp/gateway_handler_unixfs.go b/core/corehttp/gateway_handler_unixfs.go index f91e2df3b37..b318a641a09 100644 --- a/core/corehttp/gateway_handler_unixfs.go +++ b/core/corehttp/gateway_handler_unixfs.go @@ -18,6 +18,7 @@ import ( func (i *gatewayHandler) serveUnixFS(ctx context.Context, w http.ResponseWriter, r *http.Request, resolvedPath ipath.Resolved, contentPath ipath.Path, begin time.Time, logger *zap.SugaredLogger) { ctx, span := tracing.Span(ctx, "Gateway", "ServeUnixFS", trace.WithAttributes(attribute.String("path", resolvedPath.String()))) defer span.End() + // Handling UnixFS dr, err := i.api.Unixfs().Get(ctx, resolvedPath) if err != nil { @@ -39,6 +40,7 @@ func (i *gatewayHandler) serveUnixFS(ctx context.Context, w http.ResponseWriter, internalWebError(w, fmt.Errorf("unsupported UnixFS type")) return } + logger.Debugw("serving unixfs directory", "path", contentPath) i.serveDirectory(ctx, w, r, resolvedPath, contentPath, dir, begin, logger) } diff --git a/core/corehttp/gateway_handler_unixfs_dir.go b/core/corehttp/gateway_handler_unixfs_dir.go index d2cce586801..1e059200a3b 100644 --- a/core/corehttp/gateway_handler_unixfs_dir.go +++ b/core/corehttp/gateway_handler_unixfs_dir.go @@ -15,6 +15,7 @@ import ( "github.com/ipfs/go-ipfs/tracing" path "github.com/ipfs/go-path" "github.com/ipfs/go-path/resolver" + options "github.com/ipfs/interface-go-ipfs-core/options" ipath "github.com/ipfs/interface-go-ipfs-core/path" "go.opentelemetry.io/otel/attribute" "go.opentelemetry.io/otel/trace" @@ -102,36 +103,46 @@ func (i *gatewayHandler) serveDirectory(ctx context.Context, w http.ResponseWrit return } + // Optimization 1: + // List children without fetching their root blocks (fast, but no size info) + results, err := i.api.Unixfs().Ls(ctx, resolvedPath, options.Unixfs.ResolveChildren(false)) + if err != nil { + internalWebError(w, err) + return + } + // storage for directory listing - var dirListing []directoryItem - dirit := dir.Entries() - for dirit.Next() { - size := "?" - if s, err := dirit.Node().Size(); err == nil { - // Size may not be defined/supported. Continue anyways. - size = humanize.Bytes(uint64(s)) - } + dirListing := make([]directoryItem, 0, len(results)) - resolved, err := i.api.ResolvePath(ctx, ipath.Join(resolvedPath, dirit.Name())) - if err != nil { + for link := range results { + if link.Err != nil { internalWebError(w, err) return } - hash := resolved.Cid().String() - - // See comment above where originalUrlPath is declared. + hash := link.Cid.String() di := directoryItem{ - Size: size, - Name: dirit.Name(), - Path: gopath.Join(originalUrlPath, dirit.Name()), + Size: "", // no size because we did not fetch child nodes + Name: link.Name, + Path: gopath.Join(originalUrlPath, link.Name), Hash: hash, ShortHash: shortHash(hash), } dirListing = append(dirListing, di) } - if dirit.Err() != nil { - internalWebError(w, dirit.Err()) - return + + // Optimization 2: fetch sizes only for dirs below FastDirIndexThreshold + if len(dirListing) < i.config.FastDirIndexThreshold { + dirit := dir.Entries() + linkNo := 0 + for dirit.Next() { + size := "?" + if s, err := dirit.Node().Size(); err == nil { + // Size may not be defined/supported. Continue anyways. + size = humanize.Bytes(uint64(s)) + } + dirListing[linkNo].Size = size + linkNo++ + } } // construct the correct back link @@ -180,14 +191,15 @@ func (i *gatewayHandler) serveDirectory(ctx context.Context, w http.ResponseWrit // See comment above where originalUrlPath is declared. tplData := listingTemplateData{ - GatewayURL: gwURL, - DNSLink: dnslink, - Listing: dirListing, - Size: size, - Path: contentPath.String(), - Breadcrumbs: breadcrumbs(contentPath.String(), dnslink), - BackLink: backLink, - Hash: hash, + GatewayURL: gwURL, + DNSLink: dnslink, + Listing: dirListing, + Size: size, + Path: contentPath.String(), + Breadcrumbs: breadcrumbs(contentPath.String(), dnslink), + BackLink: backLink, + Hash: hash, + FastDirIndexThreshold: i.config.FastDirIndexThreshold, } logger.Debugw("request processed", "tplDataDNSLink", dnslink, "tplDataSize", size, "tplDataBackLink", backLink, "tplDataHash", hash) diff --git a/core/corehttp/gateway_indexPage.go b/core/corehttp/gateway_indexPage.go index fbea91649d3..6cc548cdc4d 100644 --- a/core/corehttp/gateway_indexPage.go +++ b/core/corehttp/gateway_indexPage.go @@ -12,14 +12,15 @@ import ( // structs for directory listing type listingTemplateData struct { - GatewayURL string - DNSLink bool - Listing []directoryItem - Size string - Path string - Breadcrumbs []breadcrumb - BackLink string - Hash string + GatewayURL string + DNSLink bool + Listing []directoryItem + Size string + Path string + Breadcrumbs []breadcrumb + BackLink string + Hash string + FastDirIndexThreshold int } type directoryItem struct { diff --git a/docs/config.md b/docs/config.md index 4261244e502..d80c7831a13 100644 --- a/docs/config.md +++ b/docs/config.md @@ -51,6 +51,7 @@ config file at runtime. - [`Gateway.NoDNSLink`](#gatewaynodnslink) - [`Gateway.HTTPHeaders`](#gatewayhttpheaders) - [`Gateway.RootRedirect`](#gatewayrootredirect) + - [`Gateway.FastDirIndexThreshold`](#gatewayfastdirindexthreshold) - [`Gateway.Writable`](#gatewaywritable) - [`Gateway.PathPrefixes`](#gatewaypathprefixes) - [`Gateway.PublicGateways`](#gatewaypublicgateways) @@ -646,6 +647,20 @@ Default: `""` Type: `string` (url) +### `Gateway.FastDirIndexThreshold` + +The maximum number of items in a directory before the Gateway switches +to a shallow, faster listing which only requires the root node. + +This allows for fast listings of big directories, without the linear slowdown caused +by reading size metadata from child nodes. + +Setting to 0 will enable fast listings for all directories. + +Default: `100` + +Type: `optionalInteger` + ### `Gateway.Writable` A boolean to configure whether the gateway is writeable or not. diff --git a/test/sharness/lib/test-lib.sh b/test/sharness/lib/test-lib.sh index 38f12a0250c..0757c323cf9 100644 --- a/test/sharness/lib/test-lib.sh +++ b/test/sharness/lib/test-lib.sh @@ -388,6 +388,15 @@ test_should_contain() { fi } +test_should_not_contain() { + test "$#" = 2 || error "bug in the test script: not 2 parameters to test_should_not_contain" + if grep -q "$1" "$2" + then + echo "'$2' contains undesired value '$1'" + return 1 + fi +} + test_str_contains() { find=$1 shift diff --git a/test/sharness/t0115-gateway-dir-listing.sh b/test/sharness/t0115-gateway-dir-listing.sh index 0fc86ed7904..91ab8afe1fa 100755 --- a/test/sharness/t0115-gateway-dir-listing.sh +++ b/test/sharness/t0115-gateway-dir-listing.sh @@ -28,7 +28,9 @@ test_expect_success "Add the test directory" ' echo "I am a txt file in confusing /ipfs dir" > rootDir/ipfs/file.txt && echo "I am a txt file in confusing /ipns dir" > rootDir/ipns/file.txt && DIR_CID=$(ipfs add -Qr --cid-version 1 rootDir) && - FILE_CID=$(ipfs files stat /ipfs/$DIR_CID/ą/ę/file-źł.txt | head -1) + FILE_CID=$(ipfs files stat --enc=json /ipfs/$DIR_CID/ą/ę/file-źł.txt | jq -r .Hash) && + FILE_SIZE=$(ipfs files stat --enc=json /ipfs/$DIR_CID/ą/ę/file-źł.txt | jq -r .Size) + echo "$FILE_CID / $FILE_SIZE" ' ## ============================================================================ @@ -135,6 +137,28 @@ test_expect_success "dnslink gw: hash column should be a CID link to cid.ipfs.io test_should_contain "" list_response ' +## ============================================================================ +## Test dir listing of a big directory +## ============================================================================ + +test_expect_success "dir listing should resolve child sizes if under Gateway.FastDirIndexThreshold" ' + curl -sD - http://127.0.0.1:$GWAY_PORT/ipfs/${DIR_CID}/ą/ę/ | tee list_response && + test_should_contain "/ipfs/${FILE_CID}?filename" list_response && + test_should_contain ">${FILE_SIZE} B" list_response +' + +# force fast dir index for all responses +ipfs config --json Gateway.FastDirIndexThreshold 0 +# restart daemon to apply config changes +test_kill_ipfs_daemon +test_launch_ipfs_daemon + +test_expect_success "dir listing should not resolve child sizes beyond Gateway.FastDirIndexThreshold" ' + curl -sD - http://127.0.0.1:$GWAY_PORT/ipfs/${DIR_CID}/ą/ę/ | tee list_response && + test_should_contain "/ipfs/${FILE_CID}?filename" list_response && + test_should_not_contain ">${FILE_SIZE} B" list_response +' + ## ============================================================================ ## End of tests, cleanup ## ============================================================================ From 6f4fc1ae8e51db08bbad61c6c3bb217479db0643 Mon Sep 17 00:00:00 2001 From: Adin Schmahmann Date: Tue, 3 May 2022 11:56:10 -0400 Subject: [PATCH 374/414] ci: add more golang strictness checks --- .github/workflows/golang-analysis.yml | 37 +++++++++++++++++++++++++++ 1 file changed, 37 insertions(+) create mode 100644 .github/workflows/golang-analysis.yml diff --git a/.github/workflows/golang-analysis.yml b/.github/workflows/golang-analysis.yml new file mode 100644 index 00000000000..12cd73078b5 --- /dev/null +++ b/.github/workflows/golang-analysis.yml @@ -0,0 +1,37 @@ +on: [push, pull_request] +name: Go Checks + +jobs: + unit: + runs-on: ubuntu-latest + name: All + steps: + - uses: actions/checkout@v2 + with: + submodules: recursive + - uses: actions/setup-go@v2 + with: + go-version: "1.17.x" + - name: Check that go.mod is tidy + uses: protocol/multiple-go-modules@v1.2 + with: + run: | + go mod tidy + if [[ -n $(git ls-files --other --exclude-standard --directory -- go.sum) ]]; then + echo "go.sum was added by go mod tidy" + exit 1 + fi + git diff --exit-code -- go.sum go.mod + - name: gofmt + if: always() # run this step even if the previous one failed + run: | + out=$(gofmt -s -l .) + if [[ -n "$out" ]]; then + echo $out | awk '{print "::error file=" $0 ",line=0,col=0::File is not gofmt-ed."}' + exit 1 + fi + - name: go vet + if: always() # run this step even if the previous one failed + uses: protocol/multiple-go-modules@v1.2 + with: + run: go vet ./... From 1f37a1481b095bfd52a73ea7531941c66e4459ab Mon Sep 17 00:00:00 2001 From: Adin Schmahmann Date: Tue, 3 May 2022 11:58:03 -0400 Subject: [PATCH 375/414] go fmt --- cmd/ipfs/daemon_linux.go | 1 + cmd/ipfs/daemon_other.go | 1 + cmd/ipfs/runmain_test.go | 1 + cmd/ipfs/util/signal.go | 1 + cmd/ipfs/util/ui.go | 3 ++- cmd/ipfs/util/ulimit_freebsd.go | 1 + cmd/ipfs/util/ulimit_test.go | 1 + cmd/ipfs/util/ulimit_unix.go | 1 + cmd/ipfs/util/ulimit_windows.go | 1 + cmd/ipfswatch/ipfswatch_test.go | 1 + core/commands/mount_nofuse.go | 1 + core/commands/root.go | 10 +++++----- coverage/main/main.go | 1 + fuse/ipns/ipns_test.go | 1 + fuse/ipns/ipns_unix.go | 1 + fuse/ipns/link_unix.go | 1 + fuse/ipns/mount_unix.go | 1 + fuse/mount/fuse.go | 1 + fuse/node/mount_darwin.go | 1 + fuse/node/mount_nofuse.go | 1 + fuse/node/mount_notsupp.go | 1 + fuse/node/mount_test.go | 1 + fuse/node/mount_unix.go | 1 + fuse/readonly/ipfs_test.go | 1 + fuse/readonly/mount_unix.go | 1 + plugin/loader/load_nocgo.go | 4 +++- plugin/loader/load_noplugin.go | 1 + plugin/loader/load_unix.go | 4 +++- test/dependencies/dependencies.go | 1 + 29 files changed, 38 insertions(+), 8 deletions(-) diff --git a/cmd/ipfs/daemon_linux.go b/cmd/ipfs/daemon_linux.go index a1123b003aa..d06baf286b0 100644 --- a/cmd/ipfs/daemon_linux.go +++ b/cmd/ipfs/daemon_linux.go @@ -1,3 +1,4 @@ +//go:build linux // +build linux package main diff --git a/cmd/ipfs/daemon_other.go b/cmd/ipfs/daemon_other.go index 4ffdd8b8ef3..cb96ce1b90c 100644 --- a/cmd/ipfs/daemon_other.go +++ b/cmd/ipfs/daemon_other.go @@ -1,3 +1,4 @@ +//go:build !linux // +build !linux package main diff --git a/cmd/ipfs/runmain_test.go b/cmd/ipfs/runmain_test.go index 8eecce3347f..360f2bc533d 100644 --- a/cmd/ipfs/runmain_test.go +++ b/cmd/ipfs/runmain_test.go @@ -1,3 +1,4 @@ +//go:build testrunmain // +build testrunmain package main diff --git a/cmd/ipfs/util/signal.go b/cmd/ipfs/util/signal.go index 393a953b907..2cfd0d5bd2d 100644 --- a/cmd/ipfs/util/signal.go +++ b/cmd/ipfs/util/signal.go @@ -1,3 +1,4 @@ +//go:build !wasm // +build !wasm package util diff --git a/cmd/ipfs/util/ui.go b/cmd/ipfs/util/ui.go index d68c9d7a504..cf8ad506744 100644 --- a/cmd/ipfs/util/ui.go +++ b/cmd/ipfs/util/ui.go @@ -1,4 +1,5 @@ -//+build !windows +//go:build !windows +// +build !windows package util diff --git a/cmd/ipfs/util/ulimit_freebsd.go b/cmd/ipfs/util/ulimit_freebsd.go index d4a36de44bf..27b31349b4b 100644 --- a/cmd/ipfs/util/ulimit_freebsd.go +++ b/cmd/ipfs/util/ulimit_freebsd.go @@ -1,3 +1,4 @@ +//go:build freebsd // +build freebsd package util diff --git a/cmd/ipfs/util/ulimit_test.go b/cmd/ipfs/util/ulimit_test.go index 80862ee5852..bef480fffbf 100644 --- a/cmd/ipfs/util/ulimit_test.go +++ b/cmd/ipfs/util/ulimit_test.go @@ -1,3 +1,4 @@ +//go:build !windows && !plan9 // +build !windows,!plan9 package util diff --git a/cmd/ipfs/util/ulimit_unix.go b/cmd/ipfs/util/ulimit_unix.go index ee30dadaf5c..d3b0ec43c89 100644 --- a/cmd/ipfs/util/ulimit_unix.go +++ b/cmd/ipfs/util/ulimit_unix.go @@ -1,3 +1,4 @@ +//go:build darwin || linux || netbsd || openbsd // +build darwin linux netbsd openbsd package util diff --git a/cmd/ipfs/util/ulimit_windows.go b/cmd/ipfs/util/ulimit_windows.go index 3cd9908c327..5dbfd26f7d7 100644 --- a/cmd/ipfs/util/ulimit_windows.go +++ b/cmd/ipfs/util/ulimit_windows.go @@ -1,3 +1,4 @@ +//go:build windows // +build windows package util diff --git a/cmd/ipfswatch/ipfswatch_test.go b/cmd/ipfswatch/ipfswatch_test.go index f6a6f7eecb4..b5a41c6bc2a 100644 --- a/cmd/ipfswatch/ipfswatch_test.go +++ b/cmd/ipfswatch/ipfswatch_test.go @@ -1,3 +1,4 @@ +//go:build !plan9 // +build !plan9 package main diff --git a/core/commands/mount_nofuse.go b/core/commands/mount_nofuse.go index ea535068808..46e9df0cefc 100644 --- a/core/commands/mount_nofuse.go +++ b/core/commands/mount_nofuse.go @@ -1,3 +1,4 @@ +//go:build !windows && nofuse // +build !windows,nofuse package commands diff --git a/core/commands/root.go b/core/commands/root.go index bbdb019766c..87bc3fd6f5d 100644 --- a/core/commands/root.go +++ b/core/commands/root.go @@ -21,11 +21,11 @@ var ErrNotOnline = errors.New("this command must be run in online mode. Try runn const ( RepoDirOption = "repo-dir" ConfigFileOption = "config-file" - ConfigOption = "config" - DebugOption = "debug" - LocalOption = "local" // DEPRECATED: use OfflineOption - OfflineOption = "offline" - ApiOption = "api" + ConfigOption = "config" + DebugOption = "debug" + LocalOption = "local" // DEPRECATED: use OfflineOption + OfflineOption = "offline" + ApiOption = "api" ) var Root = &cmds.Command{ diff --git a/coverage/main/main.go b/coverage/main/main.go index be616e08d72..7efa0f694d4 100644 --- a/coverage/main/main.go +++ b/coverage/main/main.go @@ -1,3 +1,4 @@ +//go:build testrunmain // +build testrunmain package main diff --git a/fuse/ipns/ipns_test.go b/fuse/ipns/ipns_test.go index e9fce165403..cc725d8cb12 100644 --- a/fuse/ipns/ipns_test.go +++ b/fuse/ipns/ipns_test.go @@ -1,3 +1,4 @@ +//go:build !nofuse && !openbsd && !netbsd && !plan9 // +build !nofuse,!openbsd,!netbsd,!plan9 package ipns diff --git a/fuse/ipns/ipns_unix.go b/fuse/ipns/ipns_unix.go index b8caf0ca2fe..413999b9e9b 100644 --- a/fuse/ipns/ipns_unix.go +++ b/fuse/ipns/ipns_unix.go @@ -1,3 +1,4 @@ +//go:build !nofuse && !openbsd && !netbsd && !plan9 // +build !nofuse,!openbsd,!netbsd,!plan9 // package fuse/ipns implements a fuse filesystem that interfaces diff --git a/fuse/ipns/link_unix.go b/fuse/ipns/link_unix.go index 3be52da99b2..355787b3c5e 100644 --- a/fuse/ipns/link_unix.go +++ b/fuse/ipns/link_unix.go @@ -1,3 +1,4 @@ +//go:build !nofuse && !openbsd && !netbsd && !plan9 // +build !nofuse,!openbsd,!netbsd,!plan9 package ipns diff --git a/fuse/ipns/mount_unix.go b/fuse/ipns/mount_unix.go index 7c24e53beff..c59701146fb 100644 --- a/fuse/ipns/mount_unix.go +++ b/fuse/ipns/mount_unix.go @@ -1,3 +1,4 @@ +//go:build (linux || darwin || freebsd || netbsd || openbsd) && !nofuse // +build linux darwin freebsd netbsd openbsd // +build !nofuse diff --git a/fuse/mount/fuse.go b/fuse/mount/fuse.go index 7fd29e33df2..99f374043d2 100644 --- a/fuse/mount/fuse.go +++ b/fuse/mount/fuse.go @@ -1,3 +1,4 @@ +//go:build !nofuse && !windows && !openbsd && !netbsd && !plan9 // +build !nofuse,!windows,!openbsd,!netbsd,!plan9 package mount diff --git a/fuse/node/mount_darwin.go b/fuse/node/mount_darwin.go index a27d64ccd0a..382f575e2cf 100644 --- a/fuse/node/mount_darwin.go +++ b/fuse/node/mount_darwin.go @@ -1,3 +1,4 @@ +//go:build !nofuse // +build !nofuse package node diff --git a/fuse/node/mount_nofuse.go b/fuse/node/mount_nofuse.go index 7f824ef3e12..a5433c8c39e 100644 --- a/fuse/node/mount_nofuse.go +++ b/fuse/node/mount_nofuse.go @@ -1,3 +1,4 @@ +//go:build !windows && nofuse // +build !windows,nofuse package node diff --git a/fuse/node/mount_notsupp.go b/fuse/node/mount_notsupp.go index c1cd625a1e2..d0db6f6b483 100644 --- a/fuse/node/mount_notsupp.go +++ b/fuse/node/mount_notsupp.go @@ -1,3 +1,4 @@ +//go:build (!nofuse && openbsd) || (!nofuse && netbsd) || (!nofuse && plan9) // +build !nofuse,openbsd !nofuse,netbsd !nofuse,plan9 package node diff --git a/fuse/node/mount_test.go b/fuse/node/mount_test.go index 2d1642cb9f4..23eba3bc3f5 100644 --- a/fuse/node/mount_test.go +++ b/fuse/node/mount_test.go @@ -1,3 +1,4 @@ +//go:build !openbsd && !nofuse && !netbsd && !plan9 // +build !openbsd,!nofuse,!netbsd,!plan9 package node diff --git a/fuse/node/mount_unix.go b/fuse/node/mount_unix.go index 5388333ac78..85228435796 100644 --- a/fuse/node/mount_unix.go +++ b/fuse/node/mount_unix.go @@ -1,3 +1,4 @@ +//go:build !windows && !openbsd && !netbsd && !plan9 && !nofuse // +build !windows,!openbsd,!netbsd,!plan9,!nofuse package node diff --git a/fuse/readonly/ipfs_test.go b/fuse/readonly/ipfs_test.go index feb2d4ec454..d869e3d5da4 100644 --- a/fuse/readonly/ipfs_test.go +++ b/fuse/readonly/ipfs_test.go @@ -1,3 +1,4 @@ +//go:build !nofuse && !openbsd && !netbsd && !plan9 // +build !nofuse,!openbsd,!netbsd,!plan9 package readonly diff --git a/fuse/readonly/mount_unix.go b/fuse/readonly/mount_unix.go index e1065a2a1cd..719cb5ef295 100644 --- a/fuse/readonly/mount_unix.go +++ b/fuse/readonly/mount_unix.go @@ -1,3 +1,4 @@ +//go:build (linux || darwin || freebsd) && !nofuse // +build linux darwin freebsd // +build !nofuse diff --git a/plugin/loader/load_nocgo.go b/plugin/loader/load_nocgo.go index 3c73059e16c..26bb215f29c 100644 --- a/plugin/loader/load_nocgo.go +++ b/plugin/loader/load_nocgo.go @@ -1,4 +1,6 @@ -// +build !cgo,!noplugin +//go:build !cgo && !noplugin && (linux || darwin || freebsd) +// +build !cgo +// +build !noplugin // +build linux darwin freebsd package loader diff --git a/plugin/loader/load_noplugin.go b/plugin/loader/load_noplugin.go index dfe1e3cac35..25b1c0c3879 100644 --- a/plugin/loader/load_noplugin.go +++ b/plugin/loader/load_noplugin.go @@ -1,3 +1,4 @@ +//go:build noplugin // +build noplugin package loader diff --git a/plugin/loader/load_unix.go b/plugin/loader/load_unix.go index e7d744cbd97..19ca4988974 100644 --- a/plugin/loader/load_unix.go +++ b/plugin/loader/load_unix.go @@ -1,4 +1,6 @@ -// +build cgo,!noplugin +//go:build cgo && !noplugin && (linux || darwin || freebsd) +// +build cgo +// +build !noplugin // +build linux darwin freebsd package loader diff --git a/test/dependencies/dependencies.go b/test/dependencies/dependencies.go index 9dc48969801..0d56cd5a7c5 100644 --- a/test/dependencies/dependencies.go +++ b/test/dependencies/dependencies.go @@ -1,3 +1,4 @@ +//go:build tools // +build tools package tools From be1acfa1c50052f7c198a5f8b6f52863a35d15ca Mon Sep 17 00:00:00 2001 From: Adin Schmahmann Date: Tue, 3 May 2022 10:10:45 -0400 Subject: [PATCH 376/414] chore: update go-libp2p --- go.mod | 2 +- go.sum | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/go.mod b/go.mod index 293ac707038..31bf59cacbc 100644 --- a/go.mod +++ b/go.mod @@ -68,7 +68,7 @@ require ( github.com/jbenet/go-temp-err-catcher v0.1.0 github.com/jbenet/goprocess v0.1.4 github.com/libp2p/go-doh-resolver v0.4.0 - github.com/libp2p/go-libp2p v0.19.0 + github.com/libp2p/go-libp2p v0.19.1 github.com/libp2p/go-libp2p-connmgr v0.3.2-0.20220115145817-a7820a5879c7 // indirect github.com/libp2p/go-libp2p-core v0.15.1 github.com/libp2p/go-libp2p-discovery v0.6.0 diff --git a/go.sum b/go.sum index 6859a1fddf5..f398dfc688b 100644 --- a/go.sum +++ b/go.sum @@ -764,8 +764,8 @@ github.com/libp2p/go-libp2p v0.13.0/go.mod h1:pM0beYdACRfHO1WcJlp65WXyG2A6NqYM+t github.com/libp2p/go-libp2p v0.14.3/go.mod h1:d12V4PdKbpL0T1/gsUNN8DfgMuRPDX8bS2QxCZlwRH0= github.com/libp2p/go-libp2p v0.14.4/go.mod h1:EIRU0Of4J5S8rkockZM7eJp2S0UrCyi55m2kJVru3rM= github.com/libp2p/go-libp2p v0.16.0/go.mod h1:ump42BsirwAWxKzsCiFnTtN1Yc+DuPu76fyMX364/O4= -github.com/libp2p/go-libp2p v0.19.0 h1:zosskMbaobL7UDCVLEe1m5CGs1TaFNFoN/M5XLiKg0U= -github.com/libp2p/go-libp2p v0.19.0/go.mod h1:Ki9jJXLO2YqrTIFxofV7Twyd3INWPT97+r8hGt7XPjI= +github.com/libp2p/go-libp2p v0.19.1 h1:ysBA1vDxhvgy9WmXpDeuk082EakewbJAwfU+ApdTG6I= +github.com/libp2p/go-libp2p v0.19.1/go.mod h1:Ki9jJXLO2YqrTIFxofV7Twyd3INWPT97+r8hGt7XPjI= github.com/libp2p/go-libp2p-asn-util v0.0.0-20200825225859-85005c6cf052/go.mod h1:nRMRTab+kZuk0LnKZpxhOVH/ndsdr2Nr//Zltc/vwgo= github.com/libp2p/go-libp2p-asn-util v0.1.0/go.mod h1:wu+AnM9Ii2KgO5jMmS1rz9dvzTdj8BXqsPR9HR0XB7I= github.com/libp2p/go-libp2p-asn-util v0.2.0 h1:rg3+Os8jbnO5DxkC7K/Utdi+DkY3q/d1/1q+8WeNAsw= From 7ad6447453856f8a92bdd01fb02dbc9e8038e98c Mon Sep 17 00:00:00 2001 From: Adin Schmahmann Date: Tue, 3 May 2022 10:10:13 -0400 Subject: [PATCH 377/414] feat: enable hole-punching by default --- .circleci/main.yml | 2 +- core/node/libp2p/relay.go | 5 +++-- docs/config.md | 2 +- 3 files changed, 5 insertions(+), 4 deletions(-) diff --git a/.circleci/main.yml b/.circleci/main.yml index ab7bc622b2a..8e3265dec9c 100644 --- a/.circleci/main.yml +++ b/.circleci/main.yml @@ -245,7 +245,7 @@ jobs: command: | npm init -y npm install ipfs@^0.61.0 - npm install ipfs-interop@^8.0.0 + npm install ipfs-interop@^8.0.10 npm install mocha-circleci-reporter@0.0.3 working_directory: ~/ipfs/go-ipfs/interop - run: diff --git a/core/node/libp2p/relay.go b/core/node/libp2p/relay.go index 5e218dcfe82..06bf3d791e2 100644 --- a/core/node/libp2p/relay.go +++ b/core/node/libp2p/relay.go @@ -69,9 +69,10 @@ func AutoRelay(staticRelays []string, peerChan <-chan peer.AddrInfo) func() (opt func HolePunching(flag config.Flag, hasRelayClient bool) func() (opts Libp2pOpts, err error) { return func() (opts Libp2pOpts, err error) { - if flag.WithDefault(false) { + if flag.WithDefault(true) { if !hasRelayClient { - log.Fatal("To enable `Swarm.EnableHolePunching` requires `Swarm.RelayClient.Enabled` to be enabled.") + log.Fatal("Failed to enable `Swarm.EnableHolePunching`, it requires `Swarm.RelayClient.Enabled` to be true.") + return } opts.Opts = append(opts.Opts, libp2p.EnableHolePunching()) } diff --git a/docs/config.md b/docs/config.md index d80c7831a13..0aa9e002d36 100644 --- a/docs/config.md +++ b/docs/config.md @@ -1383,7 +1383,7 @@ to [upgrade to a direct connection](https://github.com/libp2p/specs/blob/master/ through a NAT/firewall whenever possible. This feature requires `Swarm.RelayClient.Enabled` to be set to `true`. -Default: `false` +Default: `true` Type: `flag` From 346fd9d8544152e906da9eede6f7cde93a5810d5 Mon Sep 17 00:00:00 2001 From: Adin Schmahmann Date: Tue, 3 May 2022 11:39:22 -0400 Subject: [PATCH 378/414] fix: when the relay client is disabled and hole punching is left in its default state silently turn off hole punching instead of panicking --- core/node/libp2p/relay.go | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/core/node/libp2p/relay.go b/core/node/libp2p/relay.go index 06bf3d791e2..b3d93e19e0d 100644 --- a/core/node/libp2p/relay.go +++ b/core/node/libp2p/relay.go @@ -71,7 +71,11 @@ func HolePunching(flag config.Flag, hasRelayClient bool) func() (opts Libp2pOpts return func() (opts Libp2pOpts, err error) { if flag.WithDefault(true) { if !hasRelayClient { - log.Fatal("Failed to enable `Swarm.EnableHolePunching`, it requires `Swarm.RelayClient.Enabled` to be true.") + // If hole punching is explicitly enabled but the relay client is disabled then panic, + // otherwise just silently disable hole punching + if flag != config.Default { + log.Fatal("Failed to enable `Swarm.EnableHolePunching`, it requires `Swarm.RelayClient.Enabled` to be true.") + } return } opts.Opts = append(opts.Opts, libp2p.EnableHolePunching()) From 185971b259d3e53ab5b19ac4021e3059961fcf28 Mon Sep 17 00:00:00 2001 From: Adin Schmahmann Date: Tue, 3 May 2022 14:23:24 -0400 Subject: [PATCH 379/414] fix: add info log indicating that hole punching has been disabled when it is left as the default but the relay client is disabled. --- core/node/libp2p/relay.go | 2 ++ 1 file changed, 2 insertions(+) diff --git a/core/node/libp2p/relay.go b/core/node/libp2p/relay.go index b3d93e19e0d..5bb8b946e51 100644 --- a/core/node/libp2p/relay.go +++ b/core/node/libp2p/relay.go @@ -75,6 +75,8 @@ func HolePunching(flag config.Flag, hasRelayClient bool) func() (opts Libp2pOpts // otherwise just silently disable hole punching if flag != config.Default { log.Fatal("Failed to enable `Swarm.EnableHolePunching`, it requires `Swarm.RelayClient.Enabled` to be true.") + } else { + log.Info("HolePunching has been disabled due to the RelayClient being disabled.") } return } From cab69276e9af76c5e1c9cb8b19930b8c5d1b32fa Mon Sep 17 00:00:00 2001 From: Marcin Rataj Date: Thu, 28 Apr 2022 20:13:58 +0200 Subject: [PATCH 380/414] docs: Swarm.ResourceMgr.Limits --- docs/config.md | 19 ++++++++----------- 1 file changed, 8 insertions(+), 11 deletions(-) diff --git a/docs/config.md b/docs/config.md index 0aa9e002d36..090bcdfa9a4 100644 --- a/docs/config.md +++ b/docs/config.md @@ -131,6 +131,7 @@ config file at runtime. - [`Swarm.ConnMgr.GracePeriod`](#swarmconnmgrgraceperiod) - [`Swarm.ResourceMgr`](#swarmresourcemgr) - [`Swarm.ResourceMgr.Enabled`](#swarmresourcemgrenabled) + - [`Swarm.ResourceMgr.Limits`](#swarmresourcemgrlimits) - [`Swarm.Transports`](#swarmtransports) - [`Swarm.Transports.Network`](#swarmtransportsnetwork) - [`Swarm.Transports.Network.TCP`](#swarmtransportsnetworktcp) @@ -1641,14 +1642,12 @@ Default: `false` Type: `flag` - ### `Swarm.Transports` From afd11f1019f0c79a4a6f8b25cc4232239409cc58 Mon Sep 17 00:00:00 2001 From: Antonio Navarro Perez Date: Wed, 4 May 2022 17:02:07 +0200 Subject: [PATCH 381/414] chore: fix linting errors (#8930) --- commands/reqlog.go | 2 +- core/commands/version.go | 2 +- core/coreapi/name.go | 1 + core/corehttp/hostname.go | 1 + 4 files changed, 4 insertions(+), 2 deletions(-) diff --git a/commands/reqlog.go b/commands/reqlog.go index cd52d75bf2f..14c10a7c0f8 100644 --- a/commands/reqlog.go +++ b/commands/reqlog.go @@ -42,7 +42,7 @@ func (rl *ReqLog) AddEntry(rle *ReqLogEntry) { rl.nextID++ rl.Requests = append(rl.Requests, rle) - if rle == nil || !rle.Active { + if !rle.Active { rl.maybeCleanup() } } diff --git a/core/commands/version.go b/core/commands/version.go index 70686da24dc..93ec5dd87a8 100644 --- a/core/commands/version.go +++ b/core/commands/version.go @@ -71,7 +71,7 @@ var VersionCmd = &cmds.Command{ return nil } - fmt.Fprint(w, fmt.Sprintf("ipfs version %s%s\n", version.Version, commitTxt)) + fmt.Fprintf(w, "ipfs version %s%s\n", version.Version, commitTxt) return nil }), }, diff --git a/core/coreapi/name.go b/core/coreapi/name.go index d2ef99bb338..e39c05d0f5f 100644 --- a/core/coreapi/name.go +++ b/core/coreapi/name.go @@ -75,6 +75,7 @@ func (api *NameAPI) Publish(ctx context.Context, p path.Path, opts ...caopts.Nam } if options.TTL != nil { + // nolint: staticcheck // non-backward compatible change ctx = context.WithValue(ctx, "ipns-publish-ttl", *options.TTL) } diff --git a/core/corehttp/hostname.go b/core/corehttp/hostname.go index 6c0ad5bca13..93dde67ab28 100644 --- a/core/corehttp/hostname.go +++ b/core/corehttp/hostname.go @@ -249,6 +249,7 @@ func withHostnameContext(r *http.Request, hostname string) *http.Request { // on subdomain and dnslink gateways. While DNSlink could read value from // Host header, subdomain gateways have more comples rules (knownSubdomainDetails) // More: https://github.com/ipfs/dir-index-html/issues/42 + // nolint: staticcheck // non-backward compatible change ctx := context.WithValue(r.Context(), "gw-hostname", hostname) return r.WithContext(ctx) } From 0f8a1a35d2da129e6c4b4d532259c8f5c4cdd49e Mon Sep 17 00:00:00 2001 From: Antonio Navarro Perez Date: Wed, 4 May 2022 17:34:55 +0200 Subject: [PATCH 382/414] chore: Update test/dependencies to match go-ipfs dependencies. (#8928) --- test/dependencies/go.mod | 306 ++- test/dependencies/go.sum | 1975 ++++++++++++++--- .../graphsync-get/graphsync-get.go | 18 +- test/dependencies/ma-pipe-unidir/main.go | 2 +- test/dependencies/pollEndpoint/main.go | 2 +- 5 files changed, 1982 insertions(+), 321 deletions(-) diff --git a/test/dependencies/go.mod b/test/dependencies/go.mod index a742030a73a..b81021b3056 100644 --- a/test/dependencies/go.mod +++ b/test/dependencies/go.mod @@ -1,30 +1,300 @@ module github.com/ipfs/go-ipfs/test/dependencies -go 1.13 +go 1.17 require ( github.com/Kubuxu/gocovmerge v0.0.0-20161216165753-7ecaa51963cd - github.com/golangci/golangci-lint v1.26.0 - github.com/ipfs/go-blockservice v0.1.3 - github.com/ipfs/go-cid v0.0.6 + github.com/golangci/golangci-lint v1.45.2 + github.com/ipfs/go-blockservice v0.3.0 + github.com/ipfs/go-cid v0.1.0 github.com/ipfs/go-cidutil v0.0.2 - github.com/ipfs/go-datastore v0.4.4 - github.com/ipfs/go-graphsync v0.1.1 - github.com/ipfs/go-ipfs-blockstore v1.0.0 - github.com/ipfs/go-ipfs-exchange-offline v0.0.1 - github.com/ipfs/go-log v1.0.4 - github.com/ipfs/go-merkledag v0.3.2 - github.com/ipfs/go-unixfs v0.2.4 - github.com/ipfs/hang-fds v0.0.2 + github.com/ipfs/go-datastore v0.5.1 + github.com/ipfs/go-graphsync v0.11.0 + github.com/ipfs/go-ipfs-blockstore v1.2.0 + github.com/ipfs/go-ipfs-exchange-offline v0.2.0 + github.com/ipfs/go-log v1.0.5 + github.com/ipfs/go-merkledag v0.6.0 + github.com/ipfs/go-unixfs v0.3.1 + github.com/ipfs/hang-fds v0.1.0 github.com/ipfs/iptb v1.4.0 github.com/ipfs/iptb-plugins v0.3.0 - github.com/ipld/go-ipld-prime v0.0.4-0.20200503082126-7e0619f3a984 + github.com/ipld/go-ipld-prime v0.16.0 github.com/jbenet/go-random v0.0.0-20190219211222-123a90aedc0c github.com/jbenet/go-random-files v0.0.0-20190219210431-31b3f20ebded - github.com/libp2p/go-libp2p v0.9.6 - github.com/libp2p/go-libp2p-core v0.5.7 - github.com/multiformats/go-multiaddr v0.2.2 - github.com/multiformats/go-multiaddr-net v0.1.5 - github.com/multiformats/go-multihash v0.0.13 + github.com/libp2p/go-libp2p v0.19.0 + github.com/libp2p/go-libp2p-core v0.15.1 + github.com/multiformats/go-multiaddr v0.5.0 + github.com/multiformats/go-multihash v0.1.0 gotest.tools/gotestsum v0.4.2 ) + +require ( + 4d63.com/gochecknoglobals v0.1.0 // indirect + github.com/Antonboom/errname v0.1.5 // indirect + github.com/Antonboom/nilnil v0.1.0 // indirect + github.com/BurntSushi/toml v1.0.0 // indirect + github.com/Djarvur/go-err113 v0.0.0-20210108212216-aea10b59be24 // indirect + github.com/Masterminds/semver v1.5.0 // indirect + github.com/OpenPeeDeeP/depguard v1.1.0 // indirect + github.com/alecthomas/units v0.0.0-20210927113745-59d0afb8317a // indirect + github.com/alexkohler/prealloc v1.0.0 // indirect + github.com/ashanbrown/forbidigo v1.3.0 // indirect + github.com/ashanbrown/makezero v1.1.1 // indirect + github.com/benbjohnson/clock v1.3.0 // indirect + github.com/beorn7/perks v1.0.1 // indirect + github.com/bkielbasa/cyclop v1.2.0 // indirect + github.com/blizzy78/varnamelen v0.6.1 // indirect + github.com/bombsimon/wsl/v3 v3.3.0 // indirect + github.com/breml/bidichk v0.2.2 // indirect + github.com/breml/errchkjson v0.2.3 // indirect + github.com/btcsuite/btcd v0.22.0-beta // indirect + github.com/butuzov/ireturn v0.1.1 // indirect + github.com/cespare/xxhash/v2 v2.1.2 // indirect + github.com/charithe/durationcheck v0.0.9 // indirect + github.com/chavacava/garif v0.0.0-20210405164556-e8a0a408d6af // indirect + github.com/cheekybits/genny v1.0.0 // indirect + github.com/containerd/cgroups v1.0.3 // indirect + github.com/coreos/go-systemd/v22 v22.3.2 // indirect + github.com/cpuguy83/go-md2man/v2 v2.0.1 // indirect + github.com/daixiang0/gci v0.3.3 // indirect + github.com/davecgh/go-spew v1.1.1 // indirect + github.com/davidlazar/go-crypto v0.0.0-20200604182044-b73af7476f6c // indirect + github.com/denis-tingaikin/go-header v0.4.3 // indirect + github.com/docker/go-units v0.4.0 // indirect + github.com/dustin/go-humanize v1.0.0 // indirect + github.com/elastic/gosigar v0.14.2 // indirect + github.com/esimonov/ifshort v1.0.4 // indirect + github.com/ettle/strcase v0.1.1 // indirect + github.com/facebookgo/atomicfile v0.0.0-20151019160806-2de1f203e7d5 // indirect + github.com/fatih/color v1.13.0 // indirect + github.com/fatih/structtag v1.2.0 // indirect + github.com/flynn/noise v1.0.0 // indirect + github.com/francoispqt/gojay v1.2.13 // indirect + github.com/fsnotify/fsnotify v1.5.1 // indirect + github.com/fzipp/gocyclo v0.4.0 // indirect + github.com/go-critic/go-critic v0.6.2 // indirect + github.com/go-task/slim-sprig v0.0.0-20210107165309-348f09dbbbc0 // indirect + github.com/go-toolsmith/astcast v1.0.0 // indirect + github.com/go-toolsmith/astcopy v1.0.0 // indirect + github.com/go-toolsmith/astequal v1.0.1 // indirect + github.com/go-toolsmith/astfmt v1.0.0 // indirect + github.com/go-toolsmith/astp v1.0.0 // indirect + github.com/go-toolsmith/strparse v1.0.0 // indirect + github.com/go-toolsmith/typep v1.0.2 // indirect + github.com/go-xmlfmt/xmlfmt v0.0.0-20191208150333-d5b6f63a941b // indirect + github.com/gobwas/glob v0.2.3 // indirect + github.com/godbus/dbus/v5 v5.1.0 // indirect + github.com/gofrs/flock v0.8.1 // indirect + github.com/gogo/protobuf v1.3.2 // indirect + github.com/golang/protobuf v1.5.2 // indirect + github.com/golangci/check v0.0.0-20180506172741-cfe4005ccda2 // indirect + github.com/golangci/dupl v0.0.0-20180902072040-3e9179ac440a // indirect + github.com/golangci/go-misc v0.0.0-20180628070357-927a3d87b613 // indirect + github.com/golangci/gofmt v0.0.0-20190930125516-244bba706f1a // indirect + github.com/golangci/lint-1 v0.0.0-20191013205115-297bf364a8e0 // indirect + github.com/golangci/maligned v0.0.0-20180506175553-b1d89398deca // indirect + github.com/golangci/misspell v0.3.5 // indirect + github.com/golangci/revgrep v0.0.0-20210930125155-c22e5001d4f2 // indirect + github.com/golangci/unconvert v0.0.0-20180507085042-28b1c447d1f4 // indirect + github.com/google/go-cmp v0.5.7 // indirect + github.com/google/gopacket v1.1.19 // indirect + github.com/google/uuid v1.3.0 // indirect + github.com/gordonklaus/ineffassign v0.0.0-20210914165742-4cc7213b9bc8 // indirect + github.com/gorilla/websocket v1.5.0 // indirect + github.com/gostaticanalysis/analysisutil v0.7.1 // indirect + github.com/gostaticanalysis/comment v1.4.2 // indirect + github.com/gostaticanalysis/forcetypeassert v0.1.0 // indirect + github.com/gostaticanalysis/nilerr v0.1.1 // indirect + github.com/gxed/go-shellwords v1.0.3 // indirect + github.com/hannahhoward/go-pubsub v0.0.0-20200423002714-8d62886cc36e // indirect + github.com/hashicorp/errwrap v1.0.0 // indirect + github.com/hashicorp/go-multierror v1.1.1 // indirect + github.com/hashicorp/go-version v1.4.0 // indirect + github.com/hashicorp/golang-lru v0.5.4 // indirect + github.com/hashicorp/hcl v1.0.0 // indirect + github.com/hexops/gotextdiff v1.0.3 // indirect + github.com/huin/goupnp v1.0.3 // indirect + github.com/inconshreveable/mousetrap v1.0.0 // indirect + github.com/ipfs/bbloom v0.0.4 // indirect + github.com/ipfs/go-bitfield v1.0.0 // indirect + github.com/ipfs/go-block-format v0.0.3 // indirect + github.com/ipfs/go-ipfs-config v0.19.0 // indirect + github.com/ipfs/go-ipfs-ds-help v1.1.0 // indirect + github.com/ipfs/go-ipfs-exchange-interface v0.1.0 // indirect + github.com/ipfs/go-ipfs-pq v0.0.2 // indirect + github.com/ipfs/go-ipfs-util v0.0.2 // indirect + github.com/ipfs/go-ipld-cbor v0.0.5 // indirect + github.com/ipfs/go-ipld-format v0.4.0 // indirect + github.com/ipfs/go-ipld-legacy v0.1.0 // indirect + github.com/ipfs/go-log/v2 v2.5.1 // indirect + github.com/ipfs/go-metrics-interface v0.0.1 // indirect + github.com/ipfs/go-peertaskqueue v0.7.0 // indirect + github.com/ipfs/go-verifcid v0.0.1 // indirect + github.com/ipfs/interface-go-ipfs-core v0.4.0 // indirect + github.com/ipld/go-codec-dagpb v1.4.0 // indirect + github.com/jackpal/go-nat-pmp v1.0.2 // indirect + github.com/jbenet/go-temp-err-catcher v0.1.0 // indirect + github.com/jbenet/goprocess v0.1.4 // indirect + github.com/jgautheron/goconst v1.5.1 // indirect + github.com/jingyugao/rowserrcheck v1.1.1 // indirect + github.com/jirfag/go-printf-func-name v0.0.0-20200119135958-7558a9eaa5af // indirect + github.com/jonboulle/clockwork v0.2.0 // indirect + github.com/julz/importas v0.1.0 // indirect + github.com/kisielk/errcheck v1.6.0 // indirect + github.com/kisielk/gotool v1.0.0 // indirect + github.com/klauspost/compress v1.15.1 // indirect + github.com/klauspost/cpuid/v2 v2.0.12 // indirect + github.com/koron/go-ssdp v0.0.2 // indirect + github.com/kulti/thelper v0.5.1 // indirect + github.com/kunwardeep/paralleltest v1.0.3 // indirect + github.com/kyoh86/exportloopref v0.1.8 // indirect + github.com/ldez/gomoddirectives v0.2.2 // indirect + github.com/ldez/tagliatelle v0.3.1 // indirect + github.com/leonklingele/grouper v1.1.0 // indirect + github.com/libp2p/go-buffer-pool v0.0.2 // indirect + github.com/libp2p/go-cidranger v1.1.0 // indirect + github.com/libp2p/go-conn-security-multistream v0.3.0 // indirect + github.com/libp2p/go-eventbus v0.2.1 // indirect + github.com/libp2p/go-flow-metrics v0.0.3 // indirect + github.com/libp2p/go-libp2p-asn-util v0.2.0 // indirect + github.com/libp2p/go-libp2p-blankhost v0.3.0 // indirect + github.com/libp2p/go-libp2p-mplex v0.7.0 // indirect + github.com/libp2p/go-libp2p-nat v0.1.0 // indirect + github.com/libp2p/go-libp2p-noise v0.4.0 // indirect + github.com/libp2p/go-libp2p-peerstore v0.6.0 // indirect + github.com/libp2p/go-libp2p-pnet v0.2.0 // indirect + github.com/libp2p/go-libp2p-quic-transport v0.17.0 // indirect + github.com/libp2p/go-libp2p-record v0.1.3 // indirect + github.com/libp2p/go-libp2p-resource-manager v0.3.0 // indirect + github.com/libp2p/go-libp2p-swarm v0.10.2 // indirect + github.com/libp2p/go-libp2p-tls v0.4.1 // indirect + github.com/libp2p/go-libp2p-transport-upgrader v0.7.1 // indirect + github.com/libp2p/go-libp2p-yamux v0.9.1 // indirect + github.com/libp2p/go-msgio v0.2.0 // indirect + github.com/libp2p/go-nat v0.1.0 // indirect + github.com/libp2p/go-netroute v0.2.0 // indirect + github.com/libp2p/go-openssl v0.0.7 // indirect + github.com/libp2p/go-reuseport v0.1.0 // indirect + github.com/libp2p/go-reuseport-transport v0.1.0 // indirect + github.com/libp2p/go-stream-muxer-multistream v0.4.0 // indirect + github.com/libp2p/go-tcp-transport v0.5.1 // indirect + github.com/libp2p/go-ws-transport v0.6.0 // indirect + github.com/libp2p/go-yamux/v3 v3.1.1 // indirect + github.com/lucas-clemente/quic-go v0.27.0 // indirect + github.com/magiconair/properties v1.8.5 // indirect + github.com/maratori/testpackage v1.0.1 // indirect + github.com/marten-seemann/qtls-go1-16 v0.1.5 // indirect + github.com/marten-seemann/qtls-go1-17 v0.1.1 // indirect + github.com/marten-seemann/qtls-go1-18 v0.1.1 // indirect + github.com/marten-seemann/tcp v0.0.0-20210406111302-dfbc87cc63fd // indirect + github.com/matoous/godox v0.0.0-20210227103229-6504466cf951 // indirect + github.com/mattn/go-colorable v0.1.12 // indirect + github.com/mattn/go-isatty v0.0.14 // indirect + github.com/mattn/go-runewidth v0.0.9 // indirect + github.com/matttproud/golang_protobuf_extensions v1.0.1 // indirect + github.com/mbilski/exhaustivestruct v1.2.0 // indirect + github.com/mgechev/revive v1.1.4 // indirect + github.com/miekg/dns v1.1.48 // indirect + github.com/mikioh/tcpinfo v0.0.0-20190314235526-30a79bb1804b // indirect + github.com/mikioh/tcpopt v0.0.0-20190314235656-172688c1accc // indirect + github.com/minio/blake2b-simd v0.0.0-20160723061019-3f5f724cb5b1 // indirect + github.com/minio/sha256-simd v1.0.0 // indirect + github.com/mitchellh/go-homedir v1.1.0 // indirect + github.com/mitchellh/mapstructure v1.4.3 // indirect + github.com/moricho/tparallel v0.2.1 // indirect + github.com/mr-tron/base58 v1.2.0 // indirect + github.com/multiformats/go-base32 v0.0.4 // indirect + github.com/multiformats/go-base36 v0.1.0 // indirect + github.com/multiformats/go-multiaddr-dns v0.3.1 // indirect + github.com/multiformats/go-multiaddr-fmt v0.1.0 // indirect + github.com/multiformats/go-multibase v0.0.3 // indirect + github.com/multiformats/go-multicodec v0.4.1 // indirect + github.com/multiformats/go-multistream v0.3.0 // indirect + github.com/multiformats/go-varint v0.0.6 // indirect + github.com/nakabonne/nestif v0.3.1 // indirect + github.com/nbutton23/zxcvbn-go v0.0.0-20210217022336-fa2cb2858354 // indirect + github.com/nishanths/exhaustive v0.7.11 // indirect + github.com/nishanths/predeclared v0.2.1 // indirect + github.com/nxadm/tail v1.4.8 // indirect + github.com/olekukonko/tablewriter v0.0.5 // indirect + github.com/onsi/ginkgo v1.16.5 // indirect + github.com/opencontainers/runtime-spec v1.0.2 // indirect + github.com/opentracing/opentracing-go v1.2.0 // indirect + github.com/pbnjay/memory v0.0.0-20210728143218-7b4eea64cf58 // indirect + github.com/pelletier/go-toml v1.9.4 // indirect + github.com/phayes/checkstyle v0.0.0-20170904204023-bfd46e6a821d // indirect + github.com/pkg/errors v0.9.1 // indirect + github.com/pmezard/go-difflib v1.0.0 // indirect + github.com/polydawn/refmt v0.0.0-20201211092308-30ac6d18308e // indirect + github.com/polyfloyd/go-errorlint v0.0.0-20211125173453-6d6d39c5bb8b // indirect + github.com/prometheus/client_golang v1.12.1 // indirect + github.com/prometheus/client_model v0.2.0 // indirect + github.com/prometheus/common v0.33.0 // indirect + github.com/prometheus/procfs v0.7.3 // indirect + github.com/quasilyte/go-ruleguard v0.3.15 // indirect + github.com/quasilyte/gogrep v0.0.0-20220103110004-ffaa07af02e3 // indirect + github.com/quasilyte/regex/syntax v0.0.0-20200407221936-30656e2c4a95 // indirect + github.com/raulk/clock v1.1.0 // indirect + github.com/raulk/go-watchdog v1.2.0 // indirect + github.com/russross/blackfriday/v2 v2.1.0 // indirect + github.com/ryancurrah/gomodguard v1.2.3 // indirect + github.com/ryanrolds/sqlclosecheck v0.3.0 // indirect + github.com/sanposhiho/wastedassign/v2 v2.0.6 // indirect + github.com/securego/gosec/v2 v2.10.0 // indirect + github.com/shazow/go-diff v0.0.0-20160112020656-b6b7b6733b8c // indirect + github.com/sirupsen/logrus v1.8.1 // indirect + github.com/sivchari/containedctx v1.0.2 // indirect + github.com/sivchari/tenv v1.4.7 // indirect + github.com/sonatard/noctx v0.0.1 // indirect + github.com/sourcegraph/go-diff v0.6.1 // indirect + github.com/spacemonkeygo/spacelog v0.0.0-20180420211403-2296661a0572 // indirect + github.com/spaolacci/murmur3 v1.1.0 // indirect + github.com/spf13/afero v1.6.0 // indirect + github.com/spf13/cast v1.4.1 // indirect + github.com/spf13/cobra v1.4.0 // indirect + github.com/spf13/jwalterweatherman v1.1.0 // indirect + github.com/spf13/pflag v1.0.5 // indirect + github.com/spf13/viper v1.10.1 // indirect + github.com/ssgreg/nlreturn/v2 v2.2.1 // indirect + github.com/stretchr/objx v0.2.0 // indirect + github.com/stretchr/testify v1.7.1 // indirect + github.com/subosito/gotenv v1.2.0 // indirect + github.com/sylvia7788/contextcheck v1.0.4 // indirect + github.com/tdakkota/asciicheck v0.1.1 // indirect + github.com/tetafro/godot v1.4.11 // indirect + github.com/timakin/bodyclose v0.0.0-20210704033933-f49887972144 // indirect + github.com/tomarrell/wrapcheck/v2 v2.5.0 // indirect + github.com/tommy-muehle/go-mnd/v2 v2.5.0 // indirect + github.com/ultraware/funlen v0.0.3 // indirect + github.com/ultraware/whitespace v0.0.5 // indirect + github.com/urfave/cli v1.22.2 // indirect + github.com/uudashr/gocognit v1.0.5 // indirect + github.com/whyrusleeping/cbor-gen v0.0.0-20210219115102-f37d292932f2 // indirect + github.com/whyrusleeping/multiaddr-filter v0.0.0-20160516205228-e903e4adabd7 // indirect + github.com/yagipy/maintidx v1.0.0 // indirect + github.com/yeya24/promlinter v0.1.1-0.20210918184747-d757024714a1 // indirect + gitlab.com/bosi/decorder v0.2.1 // indirect + go.uber.org/atomic v1.9.0 // indirect + go.uber.org/multierr v1.8.0 // indirect + go.uber.org/zap v1.21.0 // indirect + golang.org/x/crypto v0.0.0-20220411220226-7b82a4e95df4 // indirect + golang.org/x/mod v0.6.0-dev.0.20220106191415-9b9b3d81d5e3 // indirect + golang.org/x/net v0.0.0-20220418201149-a630d4f3e7a2 // indirect + golang.org/x/sync v0.0.0-20210220032951-036812b2e83c // indirect + golang.org/x/sys v0.0.0-20220412211240-33da011f77ad // indirect + golang.org/x/term v0.0.0-20210927222741-03fcf44c2211 // indirect + golang.org/x/text v0.3.7 // indirect + golang.org/x/tools v0.1.10 // indirect + golang.org/x/xerrors v0.0.0-20220411194840-2f41105eb62f // indirect + google.golang.org/protobuf v1.28.0 // indirect + gopkg.in/ini.v1 v1.66.2 // indirect + gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7 // indirect + gopkg.in/yaml.v2 v2.4.0 // indirect + gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b // indirect + honnef.co/go/tools v0.2.2 // indirect + lukechampine.com/blake3 v1.1.7 // indirect + mvdan.cc/gofumpt v0.3.0 // indirect + mvdan.cc/interfacer v0.0.0-20180901003855-c20040233aed // indirect + mvdan.cc/lint v0.0.0-20170908181259-adc824a0674b // indirect + mvdan.cc/unparam v0.0.0-20211214103731-d0ef000c54e5 // indirect +) diff --git a/test/dependencies/go.sum b/test/dependencies/go.sum index e54b00cddec..5671560dd29 100644 --- a/test/dependencies/go.sum +++ b/test/dependencies/go.sum @@ -1,236 +1,581 @@ +4d63.com/gochecknoglobals v0.1.0 h1:zeZSRqj5yCg28tCkIV/z/lWbwvNm5qnKVS15PI8nhD0= +4d63.com/gochecknoglobals v0.1.0/go.mod h1:wfdC5ZjKSPr7CybKEcgJhUOgeAQW1+7WcyK8OvUilfo= +bitbucket.org/creachadair/shell v0.0.6/go.mod h1:8Qqi/cYk7vPnsOePHroKXDJYmb5x7ENhtiFtfZq8K+M= cloud.google.com/go v0.26.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw= cloud.google.com/go v0.31.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw= cloud.google.com/go v0.34.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw= cloud.google.com/go v0.37.0/go.mod h1:TS1dMSSfndXH133OKGwekG838Om/cQT0BUHV3HcBgoo= +cloud.google.com/go v0.38.0/go.mod h1:990N+gfupTy94rShfmMCWGDn0LpTmnzTp2qbd1dvSRU= +cloud.google.com/go v0.44.1/go.mod h1:iSa0KzasP4Uvy3f1mN/7PiObzGgflwredwwASm/v6AU= +cloud.google.com/go v0.44.2/go.mod h1:60680Gw3Yr4ikxnPRS/oxxkBccT6SA1yMk63TGekxKY= +cloud.google.com/go v0.45.1/go.mod h1:RpBamKRgapWJb87xiFSdk4g1CME7QZg3uwTez+TSTjc= +cloud.google.com/go v0.46.3/go.mod h1:a6bKKbmY7er1mI7TEI4lsAkts/mkhTSZK8w33B4RAg0= +cloud.google.com/go v0.50.0/go.mod h1:r9sluTvynVuxRIOHXQEHMFffphuXHOMZMycpNR5e6To= +cloud.google.com/go v0.52.0/go.mod h1:pXajvRH/6o3+F9jDHZWQ5PbGhn+o8w9qiu/CffaVdO4= +cloud.google.com/go v0.53.0/go.mod h1:fp/UouUEsRkN6ryDKNW/Upv/JBKnv6WDthjR6+vze6M= +cloud.google.com/go v0.54.0/go.mod h1:1rq2OEkV3YMf6n/9ZvGWI3GWw0VoqH/1x2nd8Is/bPc= +cloud.google.com/go v0.56.0/go.mod h1:jr7tqZxxKOVYizybht9+26Z/gUq7tiRzu+ACVAMbKVk= +cloud.google.com/go v0.57.0/go.mod h1:oXiQ6Rzq3RAkkY7N6t3TcE6jE+CIBBbA36lwQ1JyzZs= +cloud.google.com/go v0.60.0/go.mod h1:yw2G51M9IfRboUH61Us8GqCeF1PzPblB823Mn2q2eAU= +cloud.google.com/go v0.62.0/go.mod h1:jmCYTdRCQuc1PHIIJ/maLInMho30T/Y0M4hTdTShOYc= +cloud.google.com/go v0.65.0/go.mod h1:O5N8zS7uWy9vkA9vayVHs65eM1ubvY4h553ofrNHObY= +cloud.google.com/go v0.72.0/go.mod h1:M+5Vjvlc2wnp6tjzE102Dw08nGShTscUx2nZMufOKPI= +cloud.google.com/go v0.74.0/go.mod h1:VV1xSbzvo+9QJOxLDaJfTjx5e+MePCpCWwvftOeQmWk= +cloud.google.com/go v0.78.0/go.mod h1:QjdrLG0uq+YwhjoVOLsS1t7TW8fs36kLs4XO5R5ECHg= +cloud.google.com/go v0.79.0/go.mod h1:3bzgcEeQlzbuEAYu4mrWhKqWjmpprinYgKJLgKHnbb8= +cloud.google.com/go v0.81.0/go.mod h1:mk/AM35KwGk/Nm2YSeZbxXdrNK3KZOYHmLkOqC2V6E0= +cloud.google.com/go v0.83.0/go.mod h1:Z7MJUsANfY0pYPdw0lbnivPx4/vhy/e2FEkSkF7vAVY= +cloud.google.com/go v0.84.0/go.mod h1:RazrYuxIK6Kb7YrzzhPoLmCVzl7Sup4NrbKPg8KHSUM= +cloud.google.com/go v0.87.0/go.mod h1:TpDYlFy7vuLzZMMZ+B6iRiELaY7z/gJPaqbMx6mlWcY= +cloud.google.com/go v0.90.0/go.mod h1:kRX0mNRHe0e2rC6oNakvwQqzyDmg57xJ+SZU1eT2aDQ= +cloud.google.com/go v0.93.3/go.mod h1:8utlLll2EF5XMAV15woO4lSbWQlk8rer9aLOfLh7+YI= +cloud.google.com/go v0.94.1/go.mod h1:qAlAugsXlC+JWO+Bke5vCtc9ONxjQT3drlTTnAplMW4= +cloud.google.com/go v0.97.0/go.mod h1:GF7l59pYBVlXQIBLx3a761cZ41F9bBH3JUlihCt2Udc= +cloud.google.com/go v0.98.0/go.mod h1:ua6Ush4NALrHk5QXDWnjvZHN93OuF0HfuEPq9I1X0cM= +cloud.google.com/go v0.99.0/go.mod h1:w0Xx2nLzqWJPuozYQX+hFfCSI8WioryfRDzkoI/Y2ZA= +cloud.google.com/go/bigquery v1.0.1/go.mod h1:i/xbL2UlR5RvWAURpBYZTtm/cXjCha9lbfbpx4poX+o= +cloud.google.com/go/bigquery v1.3.0/go.mod h1:PjpwJnslEMmckchkHFfq+HTD2DmtT67aNFKH1/VBDHE= +cloud.google.com/go/bigquery v1.4.0/go.mod h1:S8dzgnTigyfTmLBfrtrhyYhwRxG72rYxvftPBK2Dvzc= +cloud.google.com/go/bigquery v1.5.0/go.mod h1:snEHRnqQbz117VIFhE8bmtwIDY80NLUZUMb4Nv6dBIg= +cloud.google.com/go/bigquery v1.7.0/go.mod h1://okPTzCYNXSlb24MZs83e2Do+h+VXtc4gLoIoXIAPc= +cloud.google.com/go/bigquery v1.8.0/go.mod h1:J5hqkt3O0uAFnINi6JXValWIb1v0goeZM77hZzJN/fQ= +cloud.google.com/go/datastore v1.0.0/go.mod h1:LXYbyblFSglQ5pkeyhO+Qmw7ukd3C+pD7TKLgZqpHYE= +cloud.google.com/go/datastore v1.1.0/go.mod h1:umbIZjpQpHh4hmRpGhH4tLFup+FVzqBi1b3c64qFpCk= +cloud.google.com/go/firestore v1.6.0/go.mod h1:afJwI0vaXwAG54kI7A//lP/lSPDkQORQuMkv56TxEPU= +cloud.google.com/go/firestore v1.6.1/go.mod h1:asNXNOzBdyVQmEU+ggO8UPodTkEVFW5Qx+rwHnAz+EY= +cloud.google.com/go/pubsub v1.0.1/go.mod h1:R0Gpsv3s54REJCy4fxDixWD93lHJMoZTyQ2kNxGRt3I= +cloud.google.com/go/pubsub v1.1.0/go.mod h1:EwwdRX2sKPjnvnqCa270oGRyludottCI76h+R3AArQw= +cloud.google.com/go/pubsub v1.2.0/go.mod h1:jhfEVHT8odbXTkndysNHCcx0awwzvfOlguIAii9o8iA= +cloud.google.com/go/pubsub v1.3.1/go.mod h1:i+ucay31+CNRpDW4Lu78I4xXG+O1r/MAHgjpRVR+TSU= +cloud.google.com/go/pubsub v1.5.0/go.mod h1:ZEwJccE3z93Z2HWvstpri00jOg7oO4UZDtKhwDwqF0w= +cloud.google.com/go/spanner v1.7.0/go.mod h1:sd3K2gZ9Fd0vMPLXzeCrF6fq4i63Q7aTLW/lBIfBkIk= +cloud.google.com/go/storage v1.0.0/go.mod h1:IhtSnM/ZTZV8YYJWCY8RULGVqBDmpoyjwiyrjsg+URw= +cloud.google.com/go/storage v1.5.0/go.mod h1:tpKbwo567HUNpVclU5sGELwQWBDZ8gh0ZeosJ0Rtdos= +cloud.google.com/go/storage v1.6.0/go.mod h1:N7U0C8pVQ/+NIKOBQyamJIeKQKkZ+mxpohlUTyfDhBk= +cloud.google.com/go/storage v1.8.0/go.mod h1:Wv1Oy7z6Yz3DshWRJFhqM/UCfaWIRTdp0RXyy7KQOVs= +cloud.google.com/go/storage v1.10.0/go.mod h1:FLPqc6j+Ki4BU591ie1oL6qBQGu2Bl/tZ9ullr3+Kg0= +contrib.go.opencensus.io/exporter/stackdriver v0.13.4/go.mod h1:aXENhDJ1Y4lIg4EUaVTwzvYETVNZk10Pu26tevFKLUc= dmitri.shuralyov.com/app/changes v0.0.0-20180602232624-0a106ad413e3/go.mod h1:Yl+fi1br7+Rr3LqpNJf1/uxUdtRUV+Tnj0o93V2B9MU= +dmitri.shuralyov.com/gpu/mtl v0.0.0-20190408044501-666a987793e9/go.mod h1:H6x//7gZCb22OMCxBHrMx7a5I7Hp++hsVxbQ4BYO7hU= dmitri.shuralyov.com/html/belt v0.0.0-20180602232347-f7d459c86be0/go.mod h1:JLBrvjyP0v+ecvNYvCpyZgu5/xkfAUhi6wJj28eUfSU= dmitri.shuralyov.com/service/change v0.0.0-20181023043359-a85b471d5412/go.mod h1:a1inKt/atXimZ4Mv927x+r7UpyzRUf4emIoiiSC2TN4= dmitri.shuralyov.com/state v0.0.0-20180228185332-28bcc343414c/go.mod h1:0PRwlb0D6DFvNNtx+9ybjezNCa8XF0xaYcETyp6rHWU= git.apache.org/thrift.git v0.0.0-20180902110319-2566ecd5d999/go.mod h1:fPE2ZNJGynbRyZ4dJvy6G277gSllfV2HJqblrnkyeyg= github.com/AndreasBriese/bbloom v0.0.0-20180913140656-343706a395b7/go.mod h1:bOvUY6CB00SOBii9/FifXqc0awNKxLFCL/+pkDPuyl8= github.com/AndreasBriese/bbloom v0.0.0-20190306092124-e2d15f34fcf9/go.mod h1:bOvUY6CB00SOBii9/FifXqc0awNKxLFCL/+pkDPuyl8= -github.com/BurntSushi/toml v0.3.1 h1:WXkYYl6Yr3qBf1K79EBnL4mak0OimBfB0XUf9Vl28OQ= +github.com/AndreasBriese/bbloom v0.0.0-20190825152654-46b345b51c96/go.mod h1:bOvUY6CB00SOBii9/FifXqc0awNKxLFCL/+pkDPuyl8= +github.com/Antonboom/errname v0.1.5 h1:IM+A/gz0pDhKmlt5KSNTVAvfLMb+65RxavBXpRtCUEg= +github.com/Antonboom/errname v0.1.5/go.mod h1:DugbBstvPFQbv/5uLcRRzfrNqKE9tVdVCqWCLp6Cifo= +github.com/Antonboom/nilnil v0.1.0 h1:DLDavmg0a6G/F4Lt9t7Enrbgb3Oph6LnDE6YVsmTt74= +github.com/Antonboom/nilnil v0.1.0/go.mod h1:PhHLvRPSghY5Y7mX4TW+BHZQYo1A8flE5H20D3IPZBo= github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU= -github.com/Djarvur/go-err113 v0.0.0-20200410182137-af658d038157 h1:hY39LwQHh+1kaovmIjOrlqnXNX6tygSRfLkkK33IkZU= -github.com/Djarvur/go-err113 v0.0.0-20200410182137-af658d038157/go.mod h1:4UJr5HIiMZrwgkSPdsjy2uOQExX/WEILpIrO9UPGuXs= +github.com/BurntSushi/toml v1.0.0 h1:dtDWrepsVPfW9H/4y7dDgFc2MBUSeJhlaDtK13CxFlU= +github.com/BurntSushi/toml v1.0.0/go.mod h1:CxXYINrC8qIiEnFrOxCa7Jy5BFHlXnUU2pbicEuybxQ= +github.com/BurntSushi/xgb v0.0.0-20160522181843-27f122750802/go.mod h1:IVnqGOEym/WlBOVXweHU+Q+/VP0lqqI8lqeDx9IjBqo= +github.com/DataDog/datadog-go v3.2.0+incompatible/go.mod h1:LButxg5PwREeZtORoXG3tL4fMGNddJ+vMq1mwgfaqoQ= +github.com/Djarvur/go-err113 v0.0.0-20210108212216-aea10b59be24 h1:sHglBQTwgx+rWPdisA5ynNEsoARbiCBOyGcJM4/OzsM= +github.com/Djarvur/go-err113 v0.0.0-20210108212216-aea10b59be24/go.mod h1:4UJr5HIiMZrwgkSPdsjy2uOQExX/WEILpIrO9UPGuXs= +github.com/Knetic/govaluate v3.0.1-0.20171022003610-9aa49832a739+incompatible/go.mod h1:r7JcOSlj0wfOMncg0iLm8Leh48TZaKVeNIfJntJ2wa0= github.com/Kubuxu/go-os-helper v0.0.1/go.mod h1:N8B+I7vPCT80IcP58r50u4+gEEcsZETFUpAzWW2ep1Y= github.com/Kubuxu/gocovmerge v0.0.0-20161216165753-7ecaa51963cd h1:HNhzThEtZW714v8Eda8sWWRcu9WSzJC+oCyjRjvZgRA= github.com/Kubuxu/gocovmerge v0.0.0-20161216165753-7ecaa51963cd/go.mod h1:bqoB8kInrTeEtYAwaIXoSRqdwnjQmFhsfusnzyui6yY= +github.com/Masterminds/goutils v1.1.0/go.mod h1:8cTjp+g8YejhMuvIA5y2vz3BpJxksy863GQaJW2MFNU= +github.com/Masterminds/semver v1.4.2/go.mod h1:MB6lktGJrhw8PrUyiEoblNEGEQ+RzHPF078ddwwvV3Y= +github.com/Masterminds/semver v1.5.0 h1:H65muMkzWKEuNDnfl9d70GUjFniHKHRbFPGBuZ3QEww= +github.com/Masterminds/semver v1.5.0/go.mod h1:MB6lktGJrhw8PrUyiEoblNEGEQ+RzHPF078ddwwvV3Y= +github.com/Masterminds/sprig v2.15.0+incompatible/go.mod h1:y6hNFY5UBTIWBxnzTeuNhlNS5hqE0NB0E6fgfo2Br3o= +github.com/Masterminds/sprig v2.22.0+incompatible/go.mod h1:y6hNFY5UBTIWBxnzTeuNhlNS5hqE0NB0E6fgfo2Br3o= github.com/OneOfOne/xxhash v1.2.2/go.mod h1:HSdplMjZKSmBqAxg5vPj2TmRDmfkzw+cTzAElWljhcU= -github.com/OpenPeeDeeP/depguard v1.0.1 h1:VlW4R6jmBIv3/u1JNlawEvJMM4J+dPORPaZasQee8Us= -github.com/OpenPeeDeeP/depguard v1.0.1/go.mod h1:xsIw86fROiiwelg+jB2uM9PiKihMMmUx/1V+TNhjQvM= -github.com/StackExchange/wmi v0.0.0-20180116203802-5d049714c4a6/go.mod h1:3eOhrUMpNV+6aFIbp5/iudMxNCF27Vw2OZgy4xEx0Fg= -github.com/Stebalien/go-bitfield v0.0.1 h1:X3kbSSPUaJK60wV2hjOPZwmpljr6VGCqdq4cBLhbQBo= +github.com/OpenPeeDeeP/depguard v1.1.0 h1:pjK9nLPS1FwQYGGpPxoMYpe7qACHOhAWQMQzV71i49o= +github.com/OpenPeeDeeP/depguard v1.1.0/go.mod h1:JtAMzWkmFEzDPyAd+W0NHl1lvpQKTvT9jnRVsohBKpc= +github.com/Shopify/sarama v1.19.0/go.mod h1:FVkBWblsNy7DGZRfXLU0O9RCGt5g3g3yEuWXgklEdEo= +github.com/Shopify/toxiproxy v2.1.4+incompatible/go.mod h1:OXgGpZ6Cli1/URJOF1DMxUHB2q5Ap20/P/eIdh4G0pI= github.com/Stebalien/go-bitfield v0.0.1/go.mod h1:GNjFpasyUVkHMsfEOk8EFLJ9syQ6SI+XWrX9Wf2XH0s= +github.com/VividCortex/gohistogram v1.0.0/go.mod h1:Pf5mBqqDxYaXu3hDrrU+w6nw50o/4+TcAqDqk/vUH7g= github.com/aead/siphash v1.0.1/go.mod h1:Nywa3cDsYNNK3gaciGTWPwHt0wlpNV15vwmswBAUSII= -github.com/alangpierce/go-forceexport v0.0.0-20160317203124-8f1d6941cd75 h1:3ILjVyslFbc4jl1w5TWuvvslFD/nDfR2H8tVaMVLrEY= -github.com/alangpierce/go-forceexport v0.0.0-20160317203124-8f1d6941cd75/go.mod h1:uAXEEpARkRhCZfEvy/y0Jcc888f9tHCc1W7/UeEtreE= +github.com/afex/hystrix-go v0.0.0-20180502004556-fa1af6a1f4f5/go.mod h1:SkGFH1ia65gfNATL8TAiHDNxPzPdmEL5uirI2Uyuz6c= github.com/alecthomas/template v0.0.0-20160405071501-a0175ee3bccc/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc= +github.com/alecthomas/template v0.0.0-20190718012654-fb15b899a751/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc= github.com/alecthomas/units v0.0.0-20151022065526-2efee857e7cf/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0= +github.com/alecthomas/units v0.0.0-20190717042225-c3de453c63f4/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0= +github.com/alecthomas/units v0.0.0-20190924025748-f65c72e2690d/go.mod h1:rBZYJk541a8SKzHPHnH3zbiI+7dagKZ0cgpgrD7Fyho= +github.com/alecthomas/units v0.0.0-20210927113745-59d0afb8317a h1:E/8AP5dFtMhl5KPJz66Kt9G0n+7Sn41Fy1wv9/jHOrc= +github.com/alecthomas/units v0.0.0-20210927113745-59d0afb8317a/go.mod h1:OMCwj8VM1Kc9e19TLln2VL61YJF0x1XFtfdL4JdbSyE= +github.com/alexkohler/prealloc v1.0.0 h1:Hbq0/3fJPQhNkN0dR95AVrr6R7tou91y0uHG5pOcUuw= +github.com/alexkohler/prealloc v1.0.0/go.mod h1:VetnK3dIgFBBKmg0YnD9F9x6Icjd+9cvfHR56wJVlKE= +github.com/andybalholm/brotli v1.0.2/go.mod h1:loMXtMfwqflxFJPmdbJO0a3KNoPuLBgiu3qAvBg8x/Y= +github.com/andybalholm/brotli v1.0.3/go.mod h1:fO7iG3H7G2nSZ7m0zPUDn85XEX2GTukHGRSepvi9Eig= github.com/anmitsu/go-shlex v0.0.0-20161002113705-648efa622239/go.mod h1:2FmKhYUyUczH0OGQWaF5ceTx0UBShxjsH6f8oGKYe2c= +github.com/antihax/optional v0.0.0-20180407024304-ca021399b1a6/go.mod h1:V8iCPQYkqmusNa815XgQio277wI47sdRh1dUOLdyC6Q= +github.com/antihax/optional v1.0.0/go.mod h1:uupD/76wgC+ih3iEmQUL+0Ugr19nfwCT1kdvxnR2qWY= +github.com/aokoli/goutils v1.0.1/go.mod h1:SijmP0QR8LtwsmDs8Yii5Z/S4trXFGFC2oO5g9DP+DQ= +github.com/apache/thrift v0.12.0/go.mod h1:cp2SuWMxlEZw2r+iP2GNCdIi4C1qmUzdZFSVb+bacwQ= +github.com/apache/thrift v0.13.0/go.mod h1:cp2SuWMxlEZw2r+iP2GNCdIi4C1qmUzdZFSVb+bacwQ= +github.com/armon/circbuf v0.0.0-20150827004946-bbbad097214e/go.mod h1:3U/XgcO3hCbHZ8TKRvWD2dDTCfh9M9ya+I9JpbB7O8o= github.com/armon/consul-api v0.0.0-20180202201655-eb2c6b5be1b6/go.mod h1:grANhF5doyWs3UAsr3K4I6qtAmlQcZDesFNEHPZAzj8= -github.com/benbjohnson/clock v1.0.1/go.mod h1:bGMdMPoPVvcYyt1gHDf4J2KE153Yf9BuiUKYMaxlTDM= +github.com/armon/go-metrics v0.0.0-20180917152333-f0300d1749da/go.mod h1:Q73ZrmVTwzkszR9V5SSuryQ31EELlFMUz1kKyl939pY= +github.com/armon/go-metrics v0.3.10/go.mod h1:4O98XIr/9W0sxpJ8UaYkvjk10Iff7SnFrb4QAOwNTFc= +github.com/armon/go-radix v0.0.0-20180808171621-7fddfc383310/go.mod h1:ufUuZ+zHj4x4TnLV4JWEpy2hxWSpsRywHrMgIH9cCH8= +github.com/armon/go-radix v1.0.0/go.mod h1:ufUuZ+zHj4x4TnLV4JWEpy2hxWSpsRywHrMgIH9cCH8= +github.com/aryann/difflib v0.0.0-20170710044230-e206f873d14a/go.mod h1:DAHtR1m6lCRdSC2Tm3DSWRPvIPr6xNKyeHdqDQSQT+A= +github.com/ashanbrown/forbidigo v1.3.0 h1:VkYIwb/xxdireGAdJNZoo24O4lmnEWkactplBlWTShc= +github.com/ashanbrown/forbidigo v1.3.0/go.mod h1:vVW7PEdqEFqapJe95xHkTfB1+XvZXBFg8t0sG2FIxmI= +github.com/ashanbrown/makezero v1.1.1 h1:iCQ87C0V0vSyO+M9E/FZYbu65auqH0lnsOkf5FcB28s= +github.com/ashanbrown/makezero v1.1.1/go.mod h1:i1bJLCRSCHOcOa9Y6MyF2FTfMZMFdHvxKHxgO5Z1axI= +github.com/aws/aws-lambda-go v1.13.3/go.mod h1:4UKl9IzQMoD+QF79YdCuzCwp8VbmG4VAQwij/eHl5CU= +github.com/aws/aws-sdk-go v1.23.20/go.mod h1:KmX6BPdI08NWTb3/sm4ZGu5ShLoqVDhKgpiN924inxo= +github.com/aws/aws-sdk-go v1.25.37/go.mod h1:KmX6BPdI08NWTb3/sm4ZGu5ShLoqVDhKgpiN924inxo= +github.com/aws/aws-sdk-go v1.27.0/go.mod h1:KmX6BPdI08NWTb3/sm4ZGu5ShLoqVDhKgpiN924inxo= +github.com/aws/aws-sdk-go v1.36.30/go.mod h1:hcU610XS61/+aQV88ixoOzUoG7v3b31pl2zKMmprdro= +github.com/aws/aws-sdk-go-v2 v0.18.0/go.mod h1:JWVYvqSMppoMJC0x5wdwiImzgXTI9FuZwxzkQq9wy+g= +github.com/benbjohnson/clock v1.1.0/go.mod h1:J11/hYXuz8f4ySSvYwY0FKfm+ezbsZBKZxNJlLklBHA= +github.com/benbjohnson/clock v1.3.0 h1:ip6w0uFQkncKQ979AypyG0ER7mqUSBdKLOgAle/AT8A= +github.com/benbjohnson/clock v1.3.0/go.mod h1:J11/hYXuz8f4ySSvYwY0FKfm+ezbsZBKZxNJlLklBHA= github.com/beorn7/perks v0.0.0-20180321164747-3a771d992973/go.mod h1:Dwedo/Wpr24TaqPxmxbtue+5NUziq4I4S80YR8gNf3Q= github.com/beorn7/perks v1.0.0/go.mod h1:KWe93zE9D1o94FZ5RNwFwVgaQK1VOXiVxmqh+CedLV8= +github.com/beorn7/perks v1.0.1 h1:VlbKKnNfV8bJzeqoa4cOKqO6bYr3WgKZxO8Z16+hsOM= github.com/beorn7/perks v1.0.1/go.mod h1:G2ZrVWU2WbWT9wwq4/hrbKbnv/1ERSJQ0ibhJ6rlkpw= -github.com/bombsimon/wsl/v3 v3.0.0 h1:w9f49xQatuaeTJFaNP4SpiWSR5vfT6IstPtM62JjcqA= -github.com/bombsimon/wsl/v3 v3.0.0/go.mod h1:st10JtZYLE4D5sC7b8xV4zTKZwAQjCH/Hy2Pm1FNZIc= +github.com/bgentry/speakeasy v0.1.0/go.mod h1:+zsyZBPWlz7T6j88CTgSN5bM796AkVf0kBD4zp0CCIs= +github.com/bkielbasa/cyclop v1.2.0 h1:7Jmnh0yL2DjKfw28p86YTd/B4lRGcNuu12sKE35sM7A= +github.com/bkielbasa/cyclop v1.2.0/go.mod h1:qOI0yy6A7dYC4Zgsa72Ppm9kONl0RoIlPbzot9mhmeI= +github.com/blizzy78/varnamelen v0.6.1 h1:kttPCLzXFa+0nt++Cw9fb7GrSSM4KkyIAoX/vXsbuqA= +github.com/blizzy78/varnamelen v0.6.1/go.mod h1:zy2Eic4qWqjrxa60jG34cfL0VXcSwzUrIx68eJPb4Q8= +github.com/bombsimon/wsl/v3 v3.3.0 h1:Mka/+kRLoQJq7g2rggtgQsjuI/K5Efd87WX96EWFxjM= +github.com/bombsimon/wsl/v3 v3.3.0/go.mod h1:st10JtZYLE4D5sC7b8xV4zTKZwAQjCH/Hy2Pm1FNZIc= github.com/bradfitz/go-smtpd v0.0.0-20170404230938-deb6d6237625/go.mod h1:HYsPBTaaSFSlLx/70C2HPIMNZpVV8+vt/A+FMnYP11g= +github.com/breml/bidichk v0.2.2 h1:w7QXnpH0eCBJm55zGCTJveZEkQBt6Fs5zThIdA6qQ9Y= +github.com/breml/bidichk v0.2.2/go.mod h1:zbfeitpevDUGI7V91Uzzuwrn4Vls8MoBMrwtt78jmso= +github.com/breml/errchkjson v0.2.3 h1:97eGTmR/w0paL2SwfRPI1jaAZHaH/fXnxWTw2eEIqE0= +github.com/breml/errchkjson v0.2.3/go.mod h1:jZEATw/jF69cL1iy7//Yih8yp/mXp2CBoBr9GJwCAsY= github.com/btcsuite/btcd v0.0.0-20190213025234-306aecffea32/go.mod h1:DrZx5ec/dmnfpw9KyYoQyYo7d0KEvTkk/5M/vbZjAr8= github.com/btcsuite/btcd v0.0.0-20190523000118-16327141da8c/go.mod h1:3J08xEfcugPacsc34/LKRU2yO7YmuT8yt28J8k2+rrI= github.com/btcsuite/btcd v0.0.0-20190605094302-a0d1e3e36d50/go.mod h1:3J08xEfcugPacsc34/LKRU2yO7YmuT8yt28J8k2+rrI= github.com/btcsuite/btcd v0.0.0-20190824003749-130ea5bddde3/go.mod h1:3J08xEfcugPacsc34/LKRU2yO7YmuT8yt28J8k2+rrI= -github.com/btcsuite/btcd v0.20.1-beta h1:Ik4hyJqN8Jfyv3S4AGBOmyouMsYE3EdYODkMbQjwPGw= github.com/btcsuite/btcd v0.20.1-beta/go.mod h1:wVuoA8VJLEcwgqHBwHmzLRazpKxTv13Px/pDuV7OomQ= +github.com/btcsuite/btcd v0.21.0-beta/go.mod h1:ZSWyehm27aAuS9bvkATT+Xte3hjHZ+MRgMY/8NJ7K94= +github.com/btcsuite/btcd v0.22.0-beta h1:LTDpDKUM5EeOFBPM8IXpinEcmZ6FWfNZbE3lfrfdnWo= +github.com/btcsuite/btcd v0.22.0-beta/go.mod h1:9n5ntfhhHQBIhUvlhDvD3Qg6fRUj4jkN0VB8L8svzOA= github.com/btcsuite/btclog v0.0.0-20170628155309-84c8d2346e9f/go.mod h1:TdznJufoqS23FtqVCzL0ZqgP5MqXbb4fg/WgDys70nA= github.com/btcsuite/btcutil v0.0.0-20190207003914-4c204d697803/go.mod h1:+5NJ2+qvTyV9exUAL/rxXi3DcLg2Ts+ymUAY5y4NvMg= github.com/btcsuite/btcutil v0.0.0-20190425235716-9e5f4b9a998d/go.mod h1:+5NJ2+qvTyV9exUAL/rxXi3DcLg2Ts+ymUAY5y4NvMg= +github.com/btcsuite/btcutil v1.0.2/go.mod h1:j9HUFwoQRsZL3V4n+qG+CUnEGHOarIxfC3Le2Yhbcts= +github.com/btcsuite/btcutil v1.0.3-0.20201208143702-a53e38424cce/go.mod h1:0DVlHczLPewLcPGEIeUEzfOJhqGPQ0mJJRDBtD307+o= github.com/btcsuite/go-socks v0.0.0-20170105172521-4720035b7bfd/go.mod h1:HHNXQzUsZCxOoE+CPiyCTO6x34Zs86zZUiwtpXoGdtg= github.com/btcsuite/goleveldb v0.0.0-20160330041536-7834afc9e8cd/go.mod h1:F+uVaaLLH7j4eDXPRvw78tMflu7Ie2bzYOH4Y8rRKBY= +github.com/btcsuite/goleveldb v1.0.0/go.mod h1:QiK9vBlgftBg6rWQIj6wFzbPfRjiykIEhBH4obrXJ/I= github.com/btcsuite/snappy-go v0.0.0-20151229074030-0bdef8d06723/go.mod h1:8woku9dyThutzjeg+3xrA5iCpBRH8XEEg3lh6TiUghc= +github.com/btcsuite/snappy-go v1.0.0/go.mod h1:8woku9dyThutzjeg+3xrA5iCpBRH8XEEg3lh6TiUghc= github.com/btcsuite/websocket v0.0.0-20150119174127-31079b680792/go.mod h1:ghJtEyQwv5/p4Mg4C0fgbePVuGr935/5ddU9Z3TmDRY= github.com/btcsuite/winsvc v1.0.0/go.mod h1:jsenWakMcC0zFBFurPLEAyrnc/teJEM1O46fmI40EZs= github.com/buger/jsonparser v0.0.0-20181115193947-bf1c66bbce23/go.mod h1:bbYlZJ7hK1yFx9hf58LP0zeX7UjIGs20ufpu3evjr+s= +github.com/butuzov/ireturn v0.1.1 h1:QvrO2QF2+/Cx1WA/vETCIYBKtRjc30vesdoPUNo1EbY= +github.com/butuzov/ireturn v0.1.1/go.mod h1:Wh6Zl3IMtTpaIKbmwzqi6olnM9ptYQxxVacMsOEFPoc= +github.com/casbin/casbin/v2 v2.1.2/go.mod h1:YcPU1XXisHhLzuxH9coDNf2FbKpjGlbCg3n9yuLkIJQ= +github.com/cenkalti/backoff v2.2.1+incompatible/go.mod h1:90ReRw6GdpyfrHakVjL/QHaoyV4aDUVVkXQJJJ3NXXM= +github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU= +github.com/census-instrumentation/opencensus-proto v0.3.0/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU= +github.com/cespare/xxhash v1.1.0 h1:a6HrQnmkObjyL+Gs60czilIUGqrzKutQD6XZog3p+ko= github.com/cespare/xxhash v1.1.0/go.mod h1:XrSqR1VqqWfGrhpAt58auRo0WTKS1nRRg3ghfAqPWnc= +github.com/cespare/xxhash/v2 v2.1.1/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= +github.com/cespare/xxhash/v2 v2.1.2 h1:YRXhKfTDauu4ajMg1TPgFO5jnlC2HCbmLXMcTG5cbYE= +github.com/cespare/xxhash/v2 v2.1.2/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= +github.com/charithe/durationcheck v0.0.9 h1:mPP4ucLrf/rKZiIG/a9IPXHGlh8p4CzgpyTy6EEutYk= +github.com/charithe/durationcheck v0.0.9/go.mod h1:SSbRIBVfMjCi/kEB6K65XEA83D6prSM8ap1UCpNKtgg= +github.com/chavacava/garif v0.0.0-20210405164556-e8a0a408d6af h1:spmv8nSH9h5oCQf40jt/ufBCt9j0/58u4G+rkeMqXGI= +github.com/chavacava/garif v0.0.0-20210405164556-e8a0a408d6af/go.mod h1:Qjyv4H3//PWVzTeCezG2b9IRn6myJxJSr4TD/xo6ojU= github.com/cheekybits/genny v1.0.0 h1:uGGa4nei+j20rOSeDeP5Of12XVm7TGUd4dJA9RDitfE= github.com/cheekybits/genny v1.0.0/go.mod h1:+tQajlRqAUrPI7DOSpB0XAqZYtQakVtB7wXkRAgjxjQ= +github.com/chzyer/logex v1.1.10/go.mod h1:+Ywpsq7O8HXn0nuIou7OrIPyXbp3wmkHB+jjWRnGsAI= +github.com/chzyer/readline v0.0.0-20180603132655-2972be24d48e/go.mod h1:nSuG5e5PlCu98SY8svDHJxuZscDgtXS6KTTbou5AhLI= +github.com/chzyer/test v0.0.0-20180213035817-a1ea475d72b1/go.mod h1:Q3SI9o4m/ZMnBNeIyt5eFwwo7qiLfzFZmjNmxjkiQlU= +github.com/cilium/ebpf v0.2.0/go.mod h1:To2CFviqOWL/M0gIMsvSMlqe7em/l1ALkX1PyjrX2Qs= +github.com/cilium/ebpf v0.4.0/go.mod h1:4tRaxcgiL706VnOzHOdBlY8IEAIdxINsQBcU4xJJXRs= +github.com/circonus-labs/circonus-gometrics v2.3.1+incompatible/go.mod h1:nmEj6Dob7S7YxXgwXpfOuvO54S+tGdZdw9fuRZt25Ag= +github.com/circonus-labs/circonusllhist v0.1.3/go.mod h1:kMXHVDlOchFAehlya5ePtbp5jckzBHf4XRpQvBOLI+I= +github.com/clbanning/x2j v0.0.0-20191024224557-825249438eec/go.mod h1:jMjuTZXRI4dUb/I5gc9Hdhagfvm9+RyrPryS/auMzxE= github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw= -github.com/coreos/bbolt v1.3.2/go.mod h1:iRUV2dpdMOn7Bo10OQBFzIJO9kkE559Wcmn+qkEiiKk= +github.com/cncf/udpa/go v0.0.0-20191209042840-269d4d468f6f/go.mod h1:M8M6+tZqaGXZJjfX53e64911xZQV5JYwmTeXPW+k8Sc= +github.com/cncf/udpa/go v0.0.0-20200629203442-efcf912fb354/go.mod h1:WmhPx2Nbnhtbo57+VJT5O0JRkEi1Wbu0z5j0R8u5Hbk= +github.com/cncf/udpa/go v0.0.0-20201120205902-5459f2c99403/go.mod h1:WmhPx2Nbnhtbo57+VJT5O0JRkEi1Wbu0z5j0R8u5Hbk= +github.com/cncf/udpa/go v0.0.0-20210930031921-04548b0d99d4/go.mod h1:6pvJx4me5XPnfI9Z40ddWsdw2W/uZgQLFXToKeRcDiI= +github.com/cncf/xds/go v0.0.0-20210312221358-fbca930ec8ed/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs= +github.com/cncf/xds/go v0.0.0-20210805033703-aa0b78936158/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs= +github.com/cncf/xds/go v0.0.0-20210922020428-25de7278fc84/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs= +github.com/cncf/xds/go v0.0.0-20211001041855-01bcc9b48dfe/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs= +github.com/cncf/xds/go v0.0.0-20211011173535-cb28da3451f1/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs= +github.com/cncf/xds/go v0.0.0-20211130200136-a8f946100490/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs= +github.com/cockroachdb/datadriven v0.0.0-20190809214429-80d97fb3cbaa/go.mod h1:zn76sxSg3SzpJ0PPJaLDCu+Bu0Lg3sKTORVIj19EIF8= +github.com/codahale/hdrhistogram v0.0.0-20161010025455-3a0bb77429bd/go.mod h1:sE/e/2PUdi/liOCUjSTXgM1o87ZssimdTWN964YiIeI= +github.com/containerd/cgroups v0.0.0-20201119153540-4cbc285b3327/go.mod h1:ZJeTFisyysqgcCdecO57Dj79RfL0LNeGiFUqLYQRYLE= +github.com/containerd/cgroups v1.0.3 h1:ADZftAkglvCiD44c77s5YmMqaP2pzVCFZvBmAlBdAP4= +github.com/containerd/cgroups v1.0.3/go.mod h1:/ofk34relqNjSGyqPrmEULrO4Sc8LJhvJmWbUCUKqj8= github.com/coreos/etcd v3.3.10+incompatible/go.mod h1:uF7uidLiAD3TWHmW31ZFd/JWoc32PjwdhPthX9715RE= github.com/coreos/go-etcd v2.0.0+incompatible/go.mod h1:Jez6KQU2B/sWsbdaef3ED8NzMklzPG4d5KIOhIy30Tk= github.com/coreos/go-semver v0.2.0/go.mod h1:nnelYz7RCh+5ahJtPPxZlU+153eP4D4r3EedlOD2RNk= +github.com/coreos/go-semver v0.2.1-0.20180108230905-e214231b295a/go.mod h1:nnelYz7RCh+5ahJtPPxZlU+153eP4D4r3EedlOD2RNk= github.com/coreos/go-semver v0.3.0 h1:wkHLiw0WNATZnSG7epLsujiMCgPAc9xhjJ4tgnAxmfM= github.com/coreos/go-semver v0.3.0/go.mod h1:nnelYz7RCh+5ahJtPPxZlU+153eP4D4r3EedlOD2RNk= +github.com/coreos/go-systemd v0.0.0-20180511133405-39ca1b05acc7/go.mod h1:F5haX7vjVVG0kc13fIWeqUViNPyEJxv/OmvnBo0Yme4= github.com/coreos/go-systemd v0.0.0-20181012123002-c6f51f82210d/go.mod h1:F5haX7vjVVG0kc13fIWeqUViNPyEJxv/OmvnBo0Yme4= -github.com/coreos/go-systemd v0.0.0-20190321100706-95778dfbb74e/go.mod h1:F5haX7vjVVG0kc13fIWeqUViNPyEJxv/OmvnBo0Yme4= +github.com/coreos/go-systemd v0.0.0-20190620071333-e64a0ec8b42a h1:W8b4lQ4tFF21aspRGoBuCNV6V2fFJBF+pm1J6OY8Lys= +github.com/coreos/go-systemd v0.0.0-20190620071333-e64a0ec8b42a/go.mod h1:F5haX7vjVVG0kc13fIWeqUViNPyEJxv/OmvnBo0Yme4= +github.com/coreos/go-systemd/v22 v22.1.0/go.mod h1:xO0FLkIi5MaZafQlIrOotqXZ90ih+1atmu1JpKERPPk= +github.com/coreos/go-systemd/v22 v22.3.2 h1:D9/bQk5vlXQFZ6Kwuu6zaiXJ9oTPe68++AzAJc1DzSI= +github.com/coreos/go-systemd/v22 v22.3.2/go.mod h1:Y58oyj3AT4RCenI/lSvhwexgC+NSVTIJ3seZv2GcEnc= +github.com/coreos/pkg v0.0.0-20160727233714-3ac0863d7acf/go.mod h1:E3G3o1h8I7cfcXa63jLwjI0eiQQMgzzUDFVpN/nH/eA= github.com/coreos/pkg v0.0.0-20180928190104-399ea9e2e55f/go.mod h1:E3G3o1h8I7cfcXa63jLwjI0eiQQMgzzUDFVpN/nH/eA= +github.com/cpuguy83/go-md2man v1.0.10 h1:BSKMNlYxDvnunlTymqtgONjNnaRV1sTpcovwwjF22jk= github.com/cpuguy83/go-md2man v1.0.10/go.mod h1:SmD6nW6nTyfqj6ABTjUi3V3JVMnlJmwcJI5acqYI6dE= +github.com/cpuguy83/go-md2man/v2 v2.0.0-20190314233015-f79a8a8ca69d/go.mod h1:maD7wRr/U5Z6m/iR4s+kqSMx2CaBsrgA7czyZG/E6dU= +github.com/cpuguy83/go-md2man/v2 v2.0.0/go.mod h1:maD7wRr/U5Z6m/iR4s+kqSMx2CaBsrgA7czyZG/E6dU= +github.com/cpuguy83/go-md2man/v2 v2.0.1 h1:r/myEWzV9lfsM1tFLgDyu0atFtJ1fXn261LKYj/3DxU= +github.com/cpuguy83/go-md2man/v2 v2.0.1/go.mod h1:tgQtvFlXSQOSOSIRvRPT7W67SCa46tRHOmNcaadrF8o= github.com/crackcomm/go-gitignore v0.0.0-20170627025303-887ab5e44cc3 h1:HVTnpeuvF6Owjd5mniCL8DEXo7uYXdQEmOP4FJbV5tg= github.com/crackcomm/go-gitignore v0.0.0-20170627025303-887ab5e44cc3/go.mod h1:p1d6YEZWvFzEh4KLyvBcVSnrfNDDvK2zfK/4x2v/4pE= github.com/creack/pty v1.1.7/go.mod h1:lj5s0c3V2DBrqTV7llrYr5NG6My20zk30Fl46Y7DoTY= github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E= github.com/cskr/pubsub v1.0.2 h1:vlOzMhl6PFn60gRlTQQsIfVwaPB/B/8MziK8FhEPt/0= github.com/cskr/pubsub v1.0.2/go.mod h1:/8MzYXk/NJAz782G8RPkFzXTZVu63VotefPnR9TIRis= +github.com/daixiang0/gci v0.3.3 h1:55xJKH7Gl9Vk6oQ1cMkwrDWjAkT1D+D1G9kNmRcAIY4= +github.com/daixiang0/gci v0.3.3/go.mod h1:1Xr2bxnQbDxCqqulUOv8qpGqkgRw9RSCGGjEC2LjF8o= +github.com/davecgh/go-spew v0.0.0-20161028175848-04cdfd42973b/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/davecgh/go-spew v0.0.0-20171005155431-ecdeabc65495/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/davidlazar/go-crypto v0.0.0-20170701192655-dcfb0a7ac018/go.mod h1:rQYf4tfk5sSwFsnDg3qYaBxSjsD9S8+59vW0dKUgme4= -github.com/davidlazar/go-crypto v0.0.0-20190912175916-7055855a373f h1:BOaYiTvg8p9vBUXpklC22XSK/mifLF7lG9jtmYYi3Tc= -github.com/davidlazar/go-crypto v0.0.0-20190912175916-7055855a373f/go.mod h1:rQYf4tfk5sSwFsnDg3qYaBxSjsD9S8+59vW0dKUgme4= +github.com/davidlazar/go-crypto v0.0.0-20200604182044-b73af7476f6c h1:pFUpOrbxDR6AkioZ1ySsx5yxlDQZ8stG2b88gTPxgJU= +github.com/davidlazar/go-crypto v0.0.0-20200604182044-b73af7476f6c/go.mod h1:6UhI8N9EjYm1c2odKpFpAYeR8dsBeM7PtzQhRgxRr9U= +github.com/decred/dcrd/lru v1.0.0/go.mod h1:mxKOwFd7lFjN2GZYsiz/ecgqR6kkYAl+0pz0tEMk218= +github.com/denis-tingaikin/go-header v0.4.3 h1:tEaZKAlqql6SKCY++utLmkPLd6K8IBM20Ha7UVm+mtU= +github.com/denis-tingaikin/go-header v0.4.3/go.mod h1:0wOCWuN71D5qIgE2nz9KrKmuYBAC2Mra5RassOIQ2/c= github.com/dgraph-io/badger v1.5.5-0.20190226225317-8115aed38f8f/go.mod h1:VZxzAIRPHRVNRKRo6AXrX9BJegn6il06VMTZVJYCIjQ= github.com/dgraph-io/badger v1.6.0-rc1/go.mod h1:zwt7syl517jmP8s94KqSxTlM6IMsdhYy6psNgSztDR4= github.com/dgraph-io/badger v1.6.0/go.mod h1:zwt7syl517jmP8s94KqSxTlM6IMsdhYy6psNgSztDR4= github.com/dgraph-io/badger v1.6.1/go.mod h1:FRmFw3uxvcpa8zG3Rxs0th+hCLIuaQg8HlNV5bjgnuU= +github.com/dgraph-io/badger v1.6.2/go.mod h1:JW2yswe3V058sS0kZ2h/AXeDSqFjxnZcRrVH//y2UQE= github.com/dgraph-io/ristretto v0.0.2/go.mod h1:KPxhHT9ZxKefz+PCeOGsrHpl1qZ7i70dGTu2u+Ahh6E= github.com/dgrijalva/jwt-go v3.2.0+incompatible/go.mod h1:E3ru+11k8xSBh+hMPgOLZmtrrCbhqsmaPHjLKYnJCaQ= github.com/dgryski/go-farm v0.0.0-20190104051053-3adb47b1fb0f/go.mod h1:SqUrOPUnsFjfmXRMNPybcSiG0BgUW2AuFH8PAnS2iTw= github.com/dgryski/go-farm v0.0.0-20190423205320-6a90982ecee2/go.mod h1:SqUrOPUnsFjfmXRMNPybcSiG0BgUW2AuFH8PAnS2iTw= -github.com/dgryski/go-sip13 v0.0.0-20181026042036-e10d5fee7954/go.mod h1:vAd38F8PWV+bWy6jNmig1y/TA+kYO4g3RSRF0IAv0no= +github.com/docker/go-units v0.4.0 h1:3uh0PgVws3nIA0Q+MwDC8yjEPf9zjRfZZWXZYDct3Tw= +github.com/docker/go-units v0.4.0/go.mod h1:fgPhTUdO+D/Jk86RDLlptpiXQzgHJF7gydDDbaIK4Dk= +github.com/dustin/go-humanize v0.0.0-20171111073723-bb3d318650d4/go.mod h1:HtrtbFcZ19U5GC7JDqmcUSB87Iq5E25KnS6fMYU6eOk= github.com/dustin/go-humanize v1.0.0 h1:VSnTsYCnlFHaM2/igO1h6X3HA71jcobQuxemgkq4zYo= github.com/dustin/go-humanize v1.0.0/go.mod h1:HtrtbFcZ19U5GC7JDqmcUSB87Iq5E25KnS6fMYU6eOk= +github.com/eapache/go-resiliency v1.1.0/go.mod h1:kFI+JgMyC7bLPUVY133qvEBtVayf5mFgVsvEsIPBvNs= +github.com/eapache/go-xerial-snappy v0.0.0-20180814174437-776d5712da21/go.mod h1:+020luEh2TKB4/GOp8oxxtq0Daoen/Cii55CzbTV6DU= +github.com/eapache/queue v1.1.0/go.mod h1:6eCeP0CKFpHLu8blIFXhExK/dRa7WDZfr6jVFPTqq+I= +github.com/edsrzf/mmap-go v1.0.0/go.mod h1:YO35OhQPt3KJa3ryjFM5Bs14WD66h8eGKpfaBNrHW5M= +github.com/elastic/gosigar v0.12.0/go.mod h1:iXRIGg2tLnu7LBdpqzyQfGDEidKCfWcCMS0WKyPWoMs= +github.com/elastic/gosigar v0.14.2 h1:Dg80n8cr90OZ7x+bAax/QjoW/XqTI11RmA79ZwIm9/4= +github.com/elastic/gosigar v0.14.2/go.mod h1:iXRIGg2tLnu7LBdpqzyQfGDEidKCfWcCMS0WKyPWoMs= +github.com/envoyproxy/go-control-plane v0.6.9/go.mod h1:SBwIajubJHhxtWwsL9s8ss4safvEdbitLhGGK48rN6g= +github.com/envoyproxy/go-control-plane v0.9.0/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4= +github.com/envoyproxy/go-control-plane v0.9.1-0.20191026205805-5f8ba28d4473/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4= +github.com/envoyproxy/go-control-plane v0.9.4/go.mod h1:6rpuAdCZL397s3pYoYcLgu1mIlRU8Am5FuJP05cCM98= +github.com/envoyproxy/go-control-plane v0.9.7/go.mod h1:cwu0lG7PUMfa9snN8LXBig5ynNVH9qI8YYLbd1fK2po= +github.com/envoyproxy/go-control-plane v0.9.9-0.20201210154907-fd9021fe5dad/go.mod h1:cXg6YxExXjJnVBQHBLXeUAgxn2UodCpnH306RInaBQk= +github.com/envoyproxy/go-control-plane v0.9.9-0.20210217033140-668b12f5399d/go.mod h1:cXg6YxExXjJnVBQHBLXeUAgxn2UodCpnH306RInaBQk= +github.com/envoyproxy/go-control-plane v0.9.9-0.20210512163311-63b5d3c536b0/go.mod h1:hliV/p42l8fGbc6Y9bQ70uLwIvmJyVE5k4iMKlh8wCQ= +github.com/envoyproxy/go-control-plane v0.9.10-0.20210907150352-cf90f659a021/go.mod h1:AFq3mo9L8Lqqiid3OhADV3RfLJnjiw63cSpi+fDTRC0= +github.com/envoyproxy/go-control-plane v0.10.1/go.mod h1:AY7fTTXNdv/aJ2O5jwpxAPOWUZ7hQAEvzN5Pf27BkQQ= +github.com/envoyproxy/protoc-gen-validate v0.0.14/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c= +github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c= +github.com/envoyproxy/protoc-gen-validate v0.6.2/go.mod h1:2t7qjJNvHPx8IjnBOzl9E9/baC+qXE/TeeyBRzgJDws= +github.com/esimonov/ifshort v1.0.4 h1:6SID4yGWfRae/M7hkVDVVyppy8q/v9OuxNdmjLQStBA= +github.com/esimonov/ifshort v1.0.4/go.mod h1:Pe8zjlRrJ80+q2CxHLfEOfTwxCZ4O+MuhcHcfgNWTk0= +github.com/ettle/strcase v0.1.1 h1:htFueZyVeE1XNnMEfbqp5r67qAN/4r6ya1ysq8Q+Zcw= +github.com/ettle/strcase v0.1.1/go.mod h1:hzDLsPC7/lwKyBOywSHEP89nt2pDgdy+No1NBA9o9VY= github.com/facebookgo/atomicfile v0.0.0-20151019160806-2de1f203e7d5 h1:BBso6MBKW8ncyZLv37o+KNyy0HrrHgfnOaGQC2qvN+A= github.com/facebookgo/atomicfile v0.0.0-20151019160806-2de1f203e7d5/go.mod h1:JpoxHjuQauoxiFMl1ie8Xc/7TfLuMZ5eOCONd1sUBHg= github.com/fatih/color v1.6.0/go.mod h1:Zm6kSWBoL9eyXnKyktHP6abPY2pDugNf5KwzbycvMj4= -github.com/fatih/color v1.7.0 h1:DkWD4oS2D8LGGgTQ6IvwJJXSL5Vp2ffcQg58nFV38Ys= github.com/fatih/color v1.7.0/go.mod h1:Zm6kSWBoL9eyXnKyktHP6abPY2pDugNf5KwzbycvMj4= +github.com/fatih/color v1.9.0/go.mod h1:eQcE1qtQxscV5RaZvpXrrb8Drkc3/DdQ+uUYCNjL+zU= +github.com/fatih/color v1.10.0/go.mod h1:ELkj/draVOlAH/xkhN6mQ50Qd0MPOk5AAr3maGEBuJM= +github.com/fatih/color v1.13.0 h1:8LOYc1KYPPmyKMuN8QV2DNRWNbLo6LZ0iLs8+mlH53w= +github.com/fatih/color v1.13.0/go.mod h1:kLAiJbzzSOZDVNGyDpeOxJ47H46qBXwg5ILebYFFOfk= +github.com/fatih/structtag v1.2.0 h1:/OdNE99OxoI/PqaW/SuSK9uxxT3f/tcSZgon/ssNSx4= +github.com/fatih/structtag v1.2.0/go.mod h1:mBJUNpUnHmRKrKlQQlmCrh5PuhftFbNv8Ys4/aAZl94= github.com/flynn/go-shlex v0.0.0-20150515145356-3f9db97f8568/go.mod h1:xEzjJPgXI435gkrCt3MPfRiAkVrwSbHsst4LCFVfpJc= +github.com/flynn/noise v1.0.0 h1:DlTHqmzmvcEiKj+4RYo/imoswx/4r6iBlCMfVtrMXpQ= +github.com/flynn/noise v1.0.0/go.mod h1:xbMo+0i6+IGbYdJhF31t2eR1BIU0CYc12+BNAKwUTag= github.com/francoispqt/gojay v1.2.13 h1:d2m3sFjloqoIUQU3TsHBgj6qg/BVGlTBeHDUmyJnXKk= github.com/francoispqt/gojay v1.2.13/go.mod h1:ehT5mTG4ua4581f1++1WLG0vPdaA9HaiDsoyrBGkyDY= -github.com/fsnotify/fsnotify v1.4.7 h1:IXs+QLmnXW2CcXuY+8Mzv/fWEsPGWxqefPtCP5CnV9I= +github.com/franela/goblin v0.0.0-20200105215937-c9ffbefa60db/go.mod h1:7dvUGVsVBjqR7JHJk0brhHOZYGmfBYOrK0ZhYMEtBr4= +github.com/franela/goreq v0.0.0-20171204163338-bcd34c9993f8/go.mod h1:ZhphrRTfi2rbfLwlschooIH4+wKKDR4Pdxhh+TRoA20= +github.com/frankban/quicktest v1.11.3/go.mod h1:wRf/ReqHper53s+kmmSZizM8NamnL3IM0I9ntUbOk+k= +github.com/frankban/quicktest v1.14.2 h1:SPb1KFFmM+ybpEjPUhCCkZOM5xlovT5UbrMvWnXyBns= +github.com/frankban/quicktest v1.14.2/go.mod h1:mgiwOwqx65TmIk1wJ6Q7wvnVMocbUorkibMOrVTHZps= github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo= +github.com/fsnotify/fsnotify v1.4.9/go.mod h1:znqG4EE+3YCdAaPaxE2ZRY/06pZUdp0tY4IgpuI1SZQ= +github.com/fsnotify/fsnotify v1.5.1 h1:mZcQUHVQUQWoPXXtuf9yuEXKudkV2sx1E06UadKWpgI= +github.com/fsnotify/fsnotify v1.5.1/go.mod h1:T3375wBYaZdLLcVNkcVbzGHY7f1l/uK5T5Ai1i3InKU= +github.com/fullstorydev/grpcurl v1.6.0/go.mod h1:ZQ+ayqbKMJNhzLmbpCiurTVlaK2M/3nqZCxaQ2Ze/sM= +github.com/fzipp/gocyclo v0.4.0 h1:IykTnjwh2YLyYkGa0y92iTTEQcnyAz0r9zOo15EbJ7k= +github.com/fzipp/gocyclo v0.4.0/go.mod h1:rXPyn8fnlpa0R2csP/31uerbiVBugk5whMdlyaLkLoA= github.com/ghodss/yaml v1.0.0/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04= github.com/gliderlabs/ssh v0.1.1/go.mod h1:U7qILu1NlMHj9FlMhZLlkCdDnU1DBEAqr0aevW3Awn0= github.com/go-check/check v0.0.0-20180628173108-788fd7840127/go.mod h1:9ES+weclKsC9YodN5RgxqK/VD9HM9JsCSh7rNhMZE98= -github.com/go-critic/go-critic v0.4.1 h1:4DTQfT1wWwLg/hzxwD9bkdhDQrdJtxe6DUTadPlrIeE= -github.com/go-critic/go-critic v0.4.1/go.mod h1:7/14rZGnZbY6E38VEGk2kVhoq6itzc1E68facVDK23g= +github.com/go-critic/go-critic v0.6.2 h1:L5SDut1N4ZfsWZY0sH4DCrsHLHnhuuWak2wa165t9gs= +github.com/go-critic/go-critic v0.6.2/go.mod h1:td1s27kfmLpe5G/DPjlnFI7o1UCzePptwU7Az0V5iCM= github.com/go-errors/errors v1.0.1/go.mod h1:f4zRHt4oKfwPJE5k8C9vpYG+aDHdBFUsgrm6/TyX73Q= +github.com/go-gl/glfw v0.0.0-20190409004039-e6da0acd62b1/go.mod h1:vR7hzQXu2zJy9AVAgeJqvqgH9Q5CA+iKCZ2gyEVpxRU= +github.com/go-gl/glfw/v3.3/glfw v0.0.0-20191125211704-12ad95a8df72/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8= +github.com/go-gl/glfw/v3.3/glfw v0.0.0-20200222043503-6f7a984d4dc4/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8= github.com/go-kit/kit v0.8.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as= -github.com/go-lintpack/lintpack v0.5.2 h1:DI5mA3+eKdWeJ40nU4d6Wc26qmdG8RCi/btYq0TuRN0= -github.com/go-lintpack/lintpack v0.5.2/go.mod h1:NwZuYi2nUHho8XEIZ6SIxihrnPoqBTDqfpXvXAN0sXM= +github.com/go-kit/kit v0.9.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as= +github.com/go-kit/kit v0.10.0/go.mod h1:xUsJbQ/Fp4kEt7AFgCuvyX4a71u8h9jB8tj/ORgOZ7o= +github.com/go-kit/log v0.1.0/go.mod h1:zbhenjAZHb184qTLMA9ZjW7ThYL0H2mk7Q6pNt4vbaY= +github.com/go-kit/log v0.2.0/go.mod h1:NwTd00d/i8cPZ3xOwwiv2PO5MOcx78fFErGNcVmBjv0= github.com/go-logfmt/logfmt v0.3.0/go.mod h1:Qt1PoO58o5twSAckw1HlFXLmHsOX5/0LbT9GBnD5lWE= github.com/go-logfmt/logfmt v0.4.0/go.mod h1:3RMwSq7FuexP4Kalkev3ejPJsZTpXXBr9+V4qmtdjCk= -github.com/go-ole/go-ole v1.2.1/go.mod h1:7FAglXiTm7HKlQRDeOQ6ZNUHidzCWXuZWq/1dTyBNF8= +github.com/go-logfmt/logfmt v0.5.0/go.mod h1:wCYkCAKZfumFQihp8CzCvQ3paCTfi41vtzG1KdI/P7A= +github.com/go-logfmt/logfmt v0.5.1/go.mod h1:WYhtIu8zTZfxdn5+rREduYbwxfcBr/Vr6KEVveWlfTs= +github.com/go-ole/go-ole v1.2.6/go.mod h1:pprOEPIfldk/42T2oK7lQ4v4JSDwmV0As9GaiUsvbm0= +github.com/go-redis/redis v6.15.8+incompatible/go.mod h1:NAIEuMOZ/fxfXJIrKDQDz8wamY7mA7PouImQ2Jvg6kA= github.com/go-sql-driver/mysql v1.4.0/go.mod h1:zAC/RDZ24gD3HViQzih4MyKcchzm+sOG5ZlKdlhCg5w= +github.com/go-sql-driver/mysql v1.5.0/go.mod h1:DCzpHaOWr8IXmIStZouvnhqoel9Qv2LBy8hT2VhHyBg= github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY= +github.com/go-task/slim-sprig v0.0.0-20210107165309-348f09dbbbc0 h1:p104kn46Q8WdvHunIJ9dAyjPVtrBPhSr3KT2yUst43I= +github.com/go-task/slim-sprig v0.0.0-20210107165309-348f09dbbbc0/go.mod h1:fyg7847qk6SyHyPtNmDHnmrv/HOrqktSC+C9fM+CJOE= github.com/go-toolsmith/astcast v1.0.0 h1:JojxlmI6STnFVG9yOImLeGREv8W2ocNUM+iOhR6jE7g= github.com/go-toolsmith/astcast v1.0.0/go.mod h1:mt2OdQTeAQcY4DQgPSArJjHCcOwlX+Wl/kwN+LbLGQ4= github.com/go-toolsmith/astcopy v1.0.0 h1:OMgl1b1MEpjFQ1m5ztEO06rz5CUd3oBv9RF7+DyvdG8= github.com/go-toolsmith/astcopy v1.0.0/go.mod h1:vrgyG+5Bxrnz4MZWPF+pI4R8h3qKRjjyvV/DSez4WVQ= -github.com/go-toolsmith/astequal v0.0.0-20180903214952-dcb477bfacd6/go.mod h1:H+xSiq0+LtiDC11+h1G32h7Of5O3CYFJ99GVbS5lDKY= -github.com/go-toolsmith/astequal v1.0.0 h1:4zxD8j3JRFNyLN46lodQuqz3xdKSrur7U/sr0SDS/gQ= github.com/go-toolsmith/astequal v1.0.0/go.mod h1:H+xSiq0+LtiDC11+h1G32h7Of5O3CYFJ99GVbS5lDKY= -github.com/go-toolsmith/astfmt v0.0.0-20180903215011-8f8ee99c3086/go.mod h1:mP93XdblcopXwlyN4X4uodxXQhldPGZbcEJIimQHrkg= +github.com/go-toolsmith/astequal v1.0.1 h1:JbSszi42Jiqu36Gnf363HWS9MTEAz67vTQLponh3Moc= +github.com/go-toolsmith/astequal v1.0.1/go.mod h1:4oGA3EZXTVItV/ipGiOx7NWkY5veFfcsOJVS2YxltLw= github.com/go-toolsmith/astfmt v1.0.0 h1:A0vDDXt+vsvLEdbMFJAUBI/uTbRw1ffOPnxsILnFL6k= github.com/go-toolsmith/astfmt v1.0.0/go.mod h1:cnWmsOAuq4jJY6Ct5YWlVLmcmLMn1JUPuQIHCY7CJDw= -github.com/go-toolsmith/astinfo v0.0.0-20180906194353-9809ff7efb21/go.mod h1:dDStQCHtmZpYOmjRP/8gHHnCCch3Zz3oEgCdZVdtweU= -github.com/go-toolsmith/astp v0.0.0-20180903215135-0af7e3c24f30/go.mod h1:SV2ur98SGypH1UjcPpCatrV5hPazG6+IfNHbkDXBRrk= github.com/go-toolsmith/astp v1.0.0 h1:alXE75TXgcmupDsMK1fRAy0YUzLzqPVvBKoyWV+KPXg= github.com/go-toolsmith/astp v1.0.0/go.mod h1:RSyrtpVlfTFGDYRbrjyWP1pYu//tSFcvdYrA8meBmLI= -github.com/go-toolsmith/pkgload v0.0.0-20181119091011-e9e65178eee8/go.mod h1:WoMrjiy4zvdS+Bg6z9jZH82QXwkcgCBX6nOfnmdaHks= -github.com/go-toolsmith/pkgload v1.0.0 h1:4DFWWMXVfbcN5So1sBNW9+yeiMqLFGl1wFLTL5R0Tgg= -github.com/go-toolsmith/pkgload v1.0.0/go.mod h1:5eFArkbO80v7Z0kdngIxsRXRMTaX4Ilcwuh3clNrQJc= +github.com/go-toolsmith/pkgload v1.0.2-0.20220101231613-e814995d17c5 h1:eD9POs68PHkwrx7hAB78z1cb6PfGq/jyWn3wJywsH1o= +github.com/go-toolsmith/pkgload v1.0.2-0.20220101231613-e814995d17c5/go.mod h1:3NAwwmD4uY/yggRxoEjk/S00MIV3A+H7rrE3i87eYxM= github.com/go-toolsmith/strparse v1.0.0 h1:Vcw78DnpCAKlM20kSbAyO4mPfJn/lyYA4BJUDxe2Jb4= github.com/go-toolsmith/strparse v1.0.0/go.mod h1:YI2nUKP9YGZnL/L1/DLFBfixrcjslWct4wyljWhSRy8= -github.com/go-toolsmith/typep v1.0.0 h1:zKymWyA1TRYvqYrYDrfEMZULyrhcnGY3x7LDKU2XQaA= -github.com/go-toolsmith/typep v1.0.0/go.mod h1:JSQCQMUPdRlMZFswiq3TGpNp1GMktqkR2Ns5AIQkATU= +github.com/go-toolsmith/typep v1.0.2 h1:8xdsa1+FSIH/RhEkgnD1j2CJOy5mNllW1Q9tRiYwvlk= +github.com/go-toolsmith/typep v1.0.2/go.mod h1:JSQCQMUPdRlMZFswiq3TGpNp1GMktqkR2Ns5AIQkATU= +github.com/go-xmlfmt/xmlfmt v0.0.0-20191208150333-d5b6f63a941b h1:khEcpUM4yFcxg4/FHQWkvVRmgijNXRfzkIDHh23ggEo= github.com/go-xmlfmt/xmlfmt v0.0.0-20191208150333-d5b6f63a941b/go.mod h1:aUCEOzzezBEjDBbFBoSiya/gduyIiWYRP6CnSFIV8AM= github.com/gobwas/glob v0.2.3 h1:A4xDbljILXROh+kObIiy5kIaPYD8e96x1tgBhUI5J+Y= github.com/gobwas/glob v0.2.3/go.mod h1:d3Ez4x06l9bZtSvzIay5+Yzi0fmZzPgnTbPcKjJAkT8= -github.com/gofrs/flock v0.0.0-20190320160742-5135e617513b h1:ekuhfTjngPhisSjOJ0QWKpPQE8/rbknHaes6WVJj5Hw= -github.com/gofrs/flock v0.0.0-20190320160742-5135e617513b/go.mod h1:F1TvTiK9OcQqauNUHlbJvyl9Qa1QvF/gOUDKA14jxHU= +github.com/godbus/dbus/v5 v5.0.3/go.mod h1:xhWf0FNVPg57R7Z0UbKHbJfkEywrmjJnf7w5xrFpKfA= +github.com/godbus/dbus/v5 v5.0.4/go.mod h1:xhWf0FNVPg57R7Z0UbKHbJfkEywrmjJnf7w5xrFpKfA= +github.com/godbus/dbus/v5 v5.1.0 h1:4KLkAxT3aOY8Li4FRJe/KvhoNFFxo0m6fNuFUO8QJUk= +github.com/godbus/dbus/v5 v5.1.0/go.mod h1:xhWf0FNVPg57R7Z0UbKHbJfkEywrmjJnf7w5xrFpKfA= +github.com/gofrs/flock v0.8.1 h1:+gYjHKf32LDeiEEFhQaotPbLuUXjY5ZqxKgXy7n59aw= +github.com/gofrs/flock v0.8.1/go.mod h1:F1TvTiK9OcQqauNUHlbJvyl9Qa1QvF/gOUDKA14jxHU= +github.com/gogo/googleapis v1.1.0/go.mod h1:gf4bu3Q80BeJ6H1S1vYPm8/ELATdvryBaNFGgqEef3s= github.com/gogo/protobuf v1.1.1/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ= +github.com/gogo/protobuf v1.2.0/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ= github.com/gogo/protobuf v1.2.1/go.mod h1:hp+jE20tsWTFYpLwKvXlhS1hjn+gTNwPg2I6zVXpSg4= github.com/gogo/protobuf v1.3.0/go.mod h1:SlYgWuQ5SjCEi6WLHjHCa1yvBfUnHcTbrrZtXPKa29o= -github.com/gogo/protobuf v1.3.1 h1:DqDEcV5aeaTmdFBePNpYsp3FlcVH/2ISVVM9Qf8PSls= github.com/gogo/protobuf v1.3.1/go.mod h1:SlYgWuQ5SjCEi6WLHjHCa1yvBfUnHcTbrrZtXPKa29o= +github.com/gogo/protobuf v1.3.2 h1:Ov1cvc58UF3b5XjBnZv7+opcTcQFZebYjWzi34vdm4Q= +github.com/gogo/protobuf v1.3.2/go.mod h1:P1XiOD3dCwIKUDQYPy72D8LYyHL2YPYrpS2s69NZV8Q= github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q= -github.com/golang/groupcache v0.0.0-20190129154638-5b532d6fd5ef/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= -github.com/golang/groupcache v0.0.0-20190702054246-869f871628b6 h1:ZgQEtGgCBiWRM39fZuwSd1LwSqqSW0hOdXCYYDX0R3I= +github.com/golang/groupcache v0.0.0-20160516000752-02826c3e7903/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= github.com/golang/groupcache v0.0.0-20190702054246-869f871628b6/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= +github.com/golang/groupcache v0.0.0-20191027212112-611e8accdfc9/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= +github.com/golang/groupcache v0.0.0-20191227052852-215e87163ea7/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= +github.com/golang/groupcache v0.0.0-20200121045136-8c9f03a8e57e/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= +github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= github.com/golang/lint v0.0.0-20180702182130-06c8688daad7/go.mod h1:tluoj9z5200jBnyusfRPU2LqT6J+DAorxEvtC7LHB+E= github.com/golang/mock v1.1.1/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A= github.com/golang/mock v1.2.0/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A= -github.com/golang/mock v1.4.0 h1:Rd1kQnQu0Hq3qvJppYSG0HtP+f5LPPUiDswTLiEegLg= +github.com/golang/mock v1.3.1/go.mod h1:sBzyDLLjw3U8JLTeZvSv8jJB+tU5PVekmnlKIyFUx0Y= github.com/golang/mock v1.4.0/go.mod h1:UOMv5ysSaYNkG+OFQykRIcU/QvvxJf3p21QfJ2Bt3cw= +github.com/golang/mock v1.4.1/go.mod h1:UOMv5ysSaYNkG+OFQykRIcU/QvvxJf3p21QfJ2Bt3cw= +github.com/golang/mock v1.4.3/go.mod h1:UOMv5ysSaYNkG+OFQykRIcU/QvvxJf3p21QfJ2Bt3cw= +github.com/golang/mock v1.4.4/go.mod h1:l3mdAwkq5BuhzHwde/uurv3sEJeZMXNpwsxVWU71h+4= +github.com/golang/mock v1.5.0/go.mod h1:CWnOUgYIOo4TcNZ0wHX3YZCqsaM1I1Jvs6v3mP3KVu8= +github.com/golang/mock v1.6.0 h1:ErTB+efbowRARo13NNdxyJji2egdxLGQhRaY+DUumQc= +github.com/golang/mock v1.6.0/go.mod h1:p6yTPP+5HYm5mzsMV8JkE6ZKdX+/wYM6Hr+LicevLPs= +github.com/golang/protobuf v1.1.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= github.com/golang/protobuf v1.3.0/go.mod h1:Qd/q+1AKNOZr9uGQzbzCmRO6sUih6GTPZv6a1/R87v0= github.com/golang/protobuf v1.3.1/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= -github.com/golang/protobuf v1.3.2 h1:6nsPYzhq5kReh6QImI3k5qWzO4PEbvbIW2cwSfR/6xs= github.com/golang/protobuf v1.3.2/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= +github.com/golang/protobuf v1.3.3/go.mod h1:vzj43D7+SQXF/4pzW/hwtAqwc6iTitCiVSaWz5lYuqw= +github.com/golang/protobuf v1.3.4/go.mod h1:vzj43D7+SQXF/4pzW/hwtAqwc6iTitCiVSaWz5lYuqw= +github.com/golang/protobuf v1.3.5/go.mod h1:6O5/vntMXwX2lRkT1hjjk0nAC1IDOTvTlVgjlRvqsdk= +github.com/golang/protobuf v1.4.0-rc.1/go.mod h1:ceaxUfeHdC40wWswd/P6IGgMaK3YpKi5j83Wpe3EHw8= +github.com/golang/protobuf v1.4.0-rc.1.0.20200221234624-67d41d38c208/go.mod h1:xKAWHe0F5eneWXFV3EuXVDTCmh+JuBKY0li0aMyXATA= +github.com/golang/protobuf v1.4.0-rc.2/go.mod h1:LlEzMj4AhA7rCAGe4KMBDvJI+AwstrUpVNzEA03Pprs= +github.com/golang/protobuf v1.4.0-rc.4.0.20200313231945-b860323f09d0/go.mod h1:WU3c8KckQ9AFe+yFwt9sWVRKCVIyN9cPHBJSNnbL67w= +github.com/golang/protobuf v1.4.0/go.mod h1:jodUvKwWbYaEsadDk5Fwe5c77LiNKVO9IDvqG2KuDX0= +github.com/golang/protobuf v1.4.1/go.mod h1:U8fpvMrcmy5pZrNK1lt4xCsGvpyWQ/VVv6QDs8UjoX8= +github.com/golang/protobuf v1.4.2/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI= +github.com/golang/protobuf v1.4.3/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI= +github.com/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaSAoJOfIk= +github.com/golang/protobuf v1.5.1/go.mod h1:DopwsBzvsk0Fs44TXzsVbJyPhcCPeIwnvohx4u74HPM= +github.com/golang/protobuf v1.5.2 h1:ROPKBNFfQgOUMifHyP+KYbvpjbdoFNs+aK7DXlji0Tw= +github.com/golang/protobuf v1.5.2/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY= github.com/golang/snappy v0.0.0-20180518054509-2e65f85255db/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q= +github.com/golang/snappy v0.0.3/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q= github.com/golangci/check v0.0.0-20180506172741-cfe4005ccda2 h1:23T5iq8rbUYlhpt5DB4XJkc6BU31uODLD1o1gKvZmD0= github.com/golangci/check v0.0.0-20180506172741-cfe4005ccda2/go.mod h1:k9Qvh+8juN+UKMCS/3jFtGICgW8O96FVaZsaxdzDkR4= github.com/golangci/dupl v0.0.0-20180902072040-3e9179ac440a h1:w8hkcTqaFpzKqonE9uMCefW1WDie15eSP/4MssdenaM= github.com/golangci/dupl v0.0.0-20180902072040-3e9179ac440a/go.mod h1:ryS0uhF+x9jgbj/N71xsEqODy9BN81/GonCZiOzirOk= -github.com/golangci/errcheck v0.0.0-20181223084120-ef45e06d44b6 h1:YYWNAGTKWhKpcLLt7aSj/odlKrSrelQwlovBpDuf19w= -github.com/golangci/errcheck v0.0.0-20181223084120-ef45e06d44b6/go.mod h1:DbHgvLiFKX1Sh2T1w8Q/h4NAI8MHIpzCdnBUDTXU3I0= github.com/golangci/go-misc v0.0.0-20180628070357-927a3d87b613 h1:9kfjN3AdxcbsZBf8NjltjWihK2QfBBBZuv91cMFfDHw= github.com/golangci/go-misc v0.0.0-20180628070357-927a3d87b613/go.mod h1:SyvUF2NxV+sN8upjjeVYr5W7tyxaT1JVtvhKhOn2ii8= -github.com/golangci/goconst v0.0.0-20180610141641-041c5f2b40f3 h1:pe9JHs3cHHDQgOFXJJdYkK6fLz2PWyYtP4hthoCMvs8= -github.com/golangci/goconst v0.0.0-20180610141641-041c5f2b40f3/go.mod h1:JXrF4TWy4tXYn62/9x8Wm/K/dm06p8tCKwFRDPZG/1o= -github.com/golangci/gocyclo v0.0.0-20180528134321-2becd97e67ee h1:J2XAy40+7yz70uaOiMbNnluTg7gyQhtGqLQncQh+4J8= -github.com/golangci/gocyclo v0.0.0-20180528134321-2becd97e67ee/go.mod h1:ozx7R9SIwqmqf5pRP90DhR2Oay2UIjGuKheCBCNwAYU= github.com/golangci/gofmt v0.0.0-20190930125516-244bba706f1a h1:iR3fYXUjHCR97qWS8ch1y9zPNsgXThGwjKPrYfqMPks= github.com/golangci/gofmt v0.0.0-20190930125516-244bba706f1a/go.mod h1:9qCChq59u/eW8im404Q2WWTrnBUQKjpNYKMbU4M7EFU= -github.com/golangci/golangci-lint v1.26.0 h1:CLLGRSA9BLMiNvsWPXHioYAdfIx9tkgdVWyA6bIdYCo= -github.com/golangci/golangci-lint v1.26.0/go.mod h1:tefbO6RcigFzvTnDC+Y51kntVGgkuCAVsC+mnfbPruc= -github.com/golangci/ineffassign v0.0.0-20190609212857-42439a7714cc h1:gLLhTLMk2/SutryVJ6D4VZCU3CUqr8YloG7FPIBWFpI= -github.com/golangci/ineffassign v0.0.0-20190609212857-42439a7714cc/go.mod h1:e5tpTHCfVze+7EpLEozzMB3eafxo2KT5veNg1k6byQU= +github.com/golangci/golangci-lint v1.45.2 h1:9I3PzkvscJkFAQpTQi5Ga0V4qWdJERajX1UZ7QqkW+I= +github.com/golangci/golangci-lint v1.45.2/go.mod h1:f20dpzMmUTRp+oYnX0OGjV1Au3Jm2JeI9yLqHq1/xsI= github.com/golangci/lint-1 v0.0.0-20191013205115-297bf364a8e0 h1:MfyDlzVjl1hoaPzPD4Gpb/QgoRfSBR0jdhwGyAWwMSA= github.com/golangci/lint-1 v0.0.0-20191013205115-297bf364a8e0/go.mod h1:66R6K6P6VWk9I95jvqGxkqJxVWGFy9XlDwLwVz1RCFg= github.com/golangci/maligned v0.0.0-20180506175553-b1d89398deca h1:kNY3/svz5T29MYHubXix4aDDuE3RWHkPvopM/EDv/MA= github.com/golangci/maligned v0.0.0-20180506175553-b1d89398deca/go.mod h1:tvlJhZqDe4LMs4ZHD0oMUlt9G2LWuDGoisJTBzLMV9o= -github.com/golangci/misspell v0.0.0-20180809174111-950f5d19e770 h1:EL/O5HGrF7Jaq0yNhBLucz9hTuRzj2LdwGBOaENgxIk= -github.com/golangci/misspell v0.0.0-20180809174111-950f5d19e770/go.mod h1:dEbvlSfYbMQDtrpRMQU675gSDLDNa8sCPPChZ7PhiVA= -github.com/golangci/prealloc v0.0.0-20180630174525-215b22d4de21 h1:leSNB7iYzLYSSx3J/s5sVf4Drkc68W2wm4Ixh/mr0us= -github.com/golangci/prealloc v0.0.0-20180630174525-215b22d4de21/go.mod h1:tf5+bzsHdTM0bsB7+8mt0GUMvjCgwLpTapNZHU8AajI= -github.com/golangci/revgrep v0.0.0-20180526074752-d9c87f5ffaf0 h1:HVfrLniijszjS1aiNg8JbBMO2+E1WIQ+j/gL4SQqGPg= -github.com/golangci/revgrep v0.0.0-20180526074752-d9c87f5ffaf0/go.mod h1:qOQCunEYvmd/TLamH+7LlVccLvUH5kZNhbCgTHoBbp4= +github.com/golangci/misspell v0.3.5 h1:pLzmVdl3VxTOncgzHcvLOKirdvcx/TydsClUQXTehjo= +github.com/golangci/misspell v0.3.5/go.mod h1:dEbvlSfYbMQDtrpRMQU675gSDLDNa8sCPPChZ7PhiVA= +github.com/golangci/revgrep v0.0.0-20210930125155-c22e5001d4f2 h1:SgM7GDZTxtTTQPU84heOxy34iG5Du7F2jcoZnvp+fXI= +github.com/golangci/revgrep v0.0.0-20210930125155-c22e5001d4f2/go.mod h1:LK+zW4MpyytAWQRz0M4xnzEk50lSvqDQKfx304apFkY= github.com/golangci/unconvert v0.0.0-20180507085042-28b1c447d1f4 h1:zwtduBRr5SSWhqsYNgcuWO2kFlpdOZbP0+yRjmvPGys= github.com/golangci/unconvert v0.0.0-20180507085042-28b1c447d1f4/go.mod h1:Izgrg8RkN3rCIMLGE9CyYmU9pY2Jer6DgANEnZ/L/cQ= github.com/google/btree v0.0.0-20180813153112-4030bb1f1f0c/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ= github.com/google/btree v1.0.0/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ= +github.com/google/certificate-transparency-go v1.0.21/go.mod h1:QeJfpSbVSfYc7RgB3gJFj9cbuQMMchQxrWXz8Ruopmg= +github.com/google/certificate-transparency-go v1.1.1/go.mod h1:FDKqPvSXawb2ecErVRrD+nfy23RCzyl7eqVCEmlT1Zs= github.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5aqRK0M= github.com/google/go-cmp v0.3.0/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= -github.com/google/go-cmp v0.4.0 h1:xsAVV57WRhGj6kEIi8ReJzQlHHqcBYCElAvkovg3B/4= +github.com/google/go-cmp v0.3.1/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= github.com/google/go-cmp v0.4.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= +github.com/google/go-cmp v0.4.1/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= +github.com/google/go-cmp v0.5.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= +github.com/google/go-cmp v0.5.1/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= +github.com/google/go-cmp v0.5.2/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= +github.com/google/go-cmp v0.5.3/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= +github.com/google/go-cmp v0.5.4/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= +github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= +github.com/google/go-cmp v0.5.6/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= +github.com/google/go-cmp v0.5.7 h1:81/ik6ipDQS2aGcBfIN5dHDB36BwrStyeAQquSYCV4o= +github.com/google/go-cmp v0.5.7/go.mod h1:n+brtR0CgQNWTVd5ZUFpTBC8YFBDLK/h/bpaJ8/DtOE= github.com/google/go-github v17.0.0+incompatible/go.mod h1:zLgOLi98H3fifZn+44m+umXrS52loVEgC2AApnigrVQ= github.com/google/go-querystring v1.0.0/go.mod h1:odCYkC5MyYFN7vkCjXpyrEuKhc/BUO6wN/zVPAxq5ck= github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= -github.com/google/gopacket v1.1.17 h1:rMrlX2ZY2UbvT+sdz3+6J+pp2z+msCq9MxTU6ymxbBY= github.com/google/gopacket v1.1.17/go.mod h1:UdDNZ1OO62aGYVnPhxT1U6aI7ukYtA/kB8vaU0diBUM= +github.com/google/gopacket v1.1.19 h1:ves8RnFZPGiFnTS0uPQStjwru6uO6h+nlr9j6fL7kF8= +github.com/google/gopacket v1.1.19/go.mod h1:iJ8V8n6KS+z2U1A8pUwu8bW5SyEMkXJB8Yo/Vo+TKTo= github.com/google/martian v2.1.0+incompatible/go.mod h1:9I4somxYTbIHy5NJKHRl3wXiIaQGbYVAs8BPL6v8lEs= +github.com/google/martian/v3 v3.0.0/go.mod h1:y5Zk1BBys9G+gd6Jrk0W3cC1+ELVxBWuIGO+w/tUAp0= +github.com/google/martian/v3 v3.1.0/go.mod h1:y5Zk1BBys9G+gd6Jrk0W3cC1+ELVxBWuIGO+w/tUAp0= +github.com/google/martian/v3 v3.2.1/go.mod h1:oBOf6HBosgwRXnUGWUB05QECsc6uvmMiJ3+6W4l/CUk= github.com/google/pprof v0.0.0-20181206194817-3ea8567a2e57/go.mod h1:zfwlbNMJ+OItoe0UupaVj+oy1omPYYDuagoSzA8v9mc= +github.com/google/pprof v0.0.0-20190515194954-54271f7e092f/go.mod h1:zfwlbNMJ+OItoe0UupaVj+oy1omPYYDuagoSzA8v9mc= +github.com/google/pprof v0.0.0-20191218002539-d4f498aebedc/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM= +github.com/google/pprof v0.0.0-20200212024743-f11f1df84d12/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM= +github.com/google/pprof v0.0.0-20200229191704-1ebb73c60ed3/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM= +github.com/google/pprof v0.0.0-20200430221834-fc25d7d30c6d/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM= +github.com/google/pprof v0.0.0-20200507031123-427632fa3b1c/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM= +github.com/google/pprof v0.0.0-20200708004538-1a94d8640e99/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM= +github.com/google/pprof v0.0.0-20201023163331-3e6fc7fc9c4c/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE= +github.com/google/pprof v0.0.0-20201203190320-1bf35d6f28c2/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE= +github.com/google/pprof v0.0.0-20210122040257-d980be63207e/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE= +github.com/google/pprof v0.0.0-20210226084205-cbba55b83ad5/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE= +github.com/google/pprof v0.0.0-20210407192527-94a9f03dee38/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE= +github.com/google/pprof v0.0.0-20210601050228-01bbb1931b22/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE= +github.com/google/pprof v0.0.0-20210609004039-a478d1d731e9/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE= +github.com/google/pprof v0.0.0-20210720184732-4bb14d4b1be1/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE= github.com/google/renameio v0.1.0/go.mod h1:KWCgfxg9yswjAJkECMjeO8J8rahYeXnNhOm40UhjYkI= +github.com/google/trillian v1.3.11/go.mod h1:0tPraVHrSDkA3BO6vKX67zgLXs6SsOAbHEivX+9mPgw= +github.com/google/uuid v0.0.0-20161128191214-064e2069ce9c/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= github.com/google/uuid v1.0.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= -github.com/google/uuid v1.1.1 h1:Gkbcsh/GbpXz7lPftLA3P6TYMwjCLYm83jiFQZF/3gY= github.com/google/uuid v1.1.1/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= +github.com/google/uuid v1.1.2/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= +github.com/google/uuid v1.2.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= +github.com/google/uuid v1.3.0 h1:t6JiXgmwXMjEs8VusXIJk2BXHsn+wx8BZdTaoZ5fu7I= +github.com/google/uuid v1.3.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= github.com/googleapis/gax-go v2.0.0+incompatible/go.mod h1:SFVmujtThgffbyetf+mdk2eWhX2bMyUtNHzFKcPA9HY= github.com/googleapis/gax-go/v2 v2.0.3/go.mod h1:LLvjysVCY1JZeum8Z6l8qUty8fiNwE08qbEPm1M08qg= +github.com/googleapis/gax-go/v2 v2.0.4/go.mod h1:0Wqv26UfaUD9n4G6kQubkQ+KchISgw+vpHVxEJEs9eg= +github.com/googleapis/gax-go/v2 v2.0.5/go.mod h1:DWXyrwAJ9X0FpwwEdw+IPEYBICEFu5mhpdKc/us6bOk= +github.com/googleapis/gax-go/v2 v2.1.0/go.mod h1:Q3nei7sK6ybPYH7twZdmQpAd1MKb7pfu6SK+H1/DsU0= +github.com/googleapis/gax-go/v2 v2.1.1/go.mod h1:hddJymUZASv3XPyGkUpKj8pPO47Rmb0eJc8R6ouapiM= +github.com/gookit/color v1.5.0/go.mod h1:43aQb+Zerm/BWh2GnrgOQm7ffz7tvQXEKV6BFMl7wAo= github.com/gopherjs/gopherjs v0.0.0-20181017120253-0766667cb4d1/go.mod h1:wJfORRmW1u3UXTncJ5qlYoELFm8eSnnEO6hX4iZ3EWY= +github.com/gopherjs/gopherjs v0.0.0-20190430165422-3e4dfb77656c h1:7lF+Vz0LqiRidnzC1Oq86fpX1q/iEv2KJdrCtttYjT4= github.com/gopherjs/gopherjs v0.0.0-20190430165422-3e4dfb77656c/go.mod h1:wJfORRmW1u3UXTncJ5qlYoELFm8eSnnEO6hX4iZ3EWY= -github.com/gopherjs/gopherjs v0.0.0-20190812055157-5d271430af9f h1:KMlcu9X58lhTA/KrfX8Bi1LQSO4pzoVjTiL3h4Jk+Zk= -github.com/gopherjs/gopherjs v0.0.0-20190812055157-5d271430af9f/go.mod h1:wJfORRmW1u3UXTncJ5qlYoELFm8eSnnEO6hX4iZ3EWY= +github.com/gordonklaus/ineffassign v0.0.0-20200309095847-7953dde2c7bf/go.mod h1:cuNKsD1zp2v6XfE/orVX2QE1LC+i254ceGcVeDT3pTU= +github.com/gordonklaus/ineffassign v0.0.0-20210914165742-4cc7213b9bc8 h1:PVRE9d4AQKmbelZ7emNig1+NT27DUmKZn5qXxfio54U= +github.com/gordonklaus/ineffassign v0.0.0-20210914165742-4cc7213b9bc8/go.mod h1:Qcp2HIAYhR7mNUVSIxZww3Guk4it82ghYcEXIAk+QT0= +github.com/gorhill/cronexpr v0.0.0-20180427100037-88b0669f7d75/go.mod h1:g2644b03hfBX9Ov0ZBDgXXens4rxSxmqFBbhvKv2yVA= +github.com/gorilla/context v1.1.1/go.mod h1:kBGZzfjB9CEq2AlWe17Uuf7NDRt0dE0s8S51q0aT7Yg= +github.com/gorilla/mux v1.6.2/go.mod h1:1lud6UwP+6orDFRuTfBEV8e9/aOM/c4fVVCaMa2zaAs= +github.com/gorilla/mux v1.7.3/go.mod h1:1lud6UwP+6orDFRuTfBEV8e9/aOM/c4fVVCaMa2zaAs= +github.com/gorilla/mux v1.8.0/go.mod h1:DVbg23sWSpFRCP0SfiEN6jmj59UnW/n46BH5rLB71So= +github.com/gorilla/websocket v0.0.0-20170926233335-4201258b820c/go.mod h1:E7qHFY5m1UJ88s3WnNqhKjPHQ0heANvMoAMk2YaljkQ= github.com/gorilla/websocket v1.4.0/go.mod h1:E7qHFY5m1UJ88s3WnNqhKjPHQ0heANvMoAMk2YaljkQ= github.com/gorilla/websocket v1.4.1/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE= -github.com/gorilla/websocket v1.4.2 h1:+/TMaTYc4QFitKJxsQ7Yye35DkWvkdLcvGKqM+x0Ufc= github.com/gorilla/websocket v1.4.2/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE= -github.com/gostaticanalysis/analysisutil v0.0.0-20190318220348-4088753ea4d3 h1:JVnpOZS+qxli+rgVl98ILOXVNbW+kb5wcxeGx8ShUIw= +github.com/gorilla/websocket v1.5.0 h1:PPwGk2jz7EePpoHN/+ClbZu8SPxiqlu12wZP/3sWmnc= +github.com/gorilla/websocket v1.5.0/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE= github.com/gostaticanalysis/analysisutil v0.0.0-20190318220348-4088753ea4d3/go.mod h1:eEOZF4jCKGi+aprrirO9e7WKB3beBRtWgqGunKl6pKE= +github.com/gostaticanalysis/analysisutil v0.0.3/go.mod h1:eEOZF4jCKGi+aprrirO9e7WKB3beBRtWgqGunKl6pKE= +github.com/gostaticanalysis/analysisutil v0.1.0/go.mod h1:dMhHRU9KTiDcuLGdy87/2gTR8WruwYZrKdRq9m1O6uw= +github.com/gostaticanalysis/analysisutil v0.4.1/go.mod h1:18U/DLpRgIUd459wGxVHE0fRgmo1UgHDcbw7F5idXu0= +github.com/gostaticanalysis/analysisutil v0.7.1 h1:ZMCjoue3DtDWQ5WyU16YbjbQEQ3VuzwxALrpYd+HeKk= +github.com/gostaticanalysis/analysisutil v0.7.1/go.mod h1:v21E3hY37WKMGSnbsw2S/ojApNWb6C1//mXO48CXbVc= +github.com/gostaticanalysis/comment v1.3.0/go.mod h1:xMicKDx7XRXYdVwY9f9wQpDJVnqWxw9wCauCMKp+IBI= +github.com/gostaticanalysis/comment v1.4.1/go.mod h1:ih6ZxzTHLdadaiSnF5WY3dxUoXfXAlTaRzuaNDlSado= +github.com/gostaticanalysis/comment v1.4.2 h1:hlnx5+S2fY9Zo9ePo4AhgYsYHbM2+eAv8m/s1JiCd6Q= +github.com/gostaticanalysis/comment v1.4.2/go.mod h1:KLUTGDv6HOCotCH8h2erHKmpci2ZoR8VPu34YA2uzdM= +github.com/gostaticanalysis/forcetypeassert v0.1.0 h1:6eUflI3DiGusXGK6X7cCcIgVCpZ2CiZ1Q7jl6ZxNV70= +github.com/gostaticanalysis/forcetypeassert v0.1.0/go.mod h1:qZEedyP/sY1lTGV1uJ3VhWZ2mqag3IkWsDHVbplHXak= +github.com/gostaticanalysis/nilerr v0.1.1 h1:ThE+hJP0fEp4zWLkWHWcRyI2Od0p7DlgYG3Uqrmrcpk= +github.com/gostaticanalysis/nilerr v0.1.1/go.mod h1:wZYb6YI5YAxxq0i1+VJbY0s2YONW0HU0GPE3+5PWN4A= +github.com/gostaticanalysis/testutil v0.3.1-0.20210208050101-bfb5c8eec0e4/go.mod h1:D+FIZ+7OahH3ePw/izIEeH5I06eKs1IKI4Xr64/Am3M= +github.com/gostaticanalysis/testutil v0.4.0 h1:nhdCmubdmDF6VEatUNjgUZBJKWRqugoISdUv3PPQgHY= +github.com/gostaticanalysis/testutil v0.4.0/go.mod h1:bLIoPefWXrRi/ssLFWX1dx7Repi5x3CuviD3dgAZaBU= github.com/gregjones/httpcache v0.0.0-20180305231024-9cad4c3443a7/go.mod h1:FecbI9+v66THATjSRHfNgh1IVFe/9kFxbXtjV0ctIMA= -github.com/grpc-ecosystem/go-grpc-middleware v1.0.0/go.mod h1:FiyG127CGDf3tlThmgyCl78X/SZQqEOJBCDaAfeWzPs= +github.com/gregjones/httpcache v0.0.0-20190611155906-901d90724c79/go.mod h1:FecbI9+v66THATjSRHfNgh1IVFe/9kFxbXtjV0ctIMA= +github.com/grpc-ecosystem/go-grpc-middleware v1.0.1-0.20190118093823-f849b5445de4/go.mod h1:FiyG127CGDf3tlThmgyCl78X/SZQqEOJBCDaAfeWzPs= +github.com/grpc-ecosystem/go-grpc-middleware v1.2.2/go.mod h1:EaizFBKfUKtMIF5iaDEhniwNedqGo9FuLFzppDr3uwI= github.com/grpc-ecosystem/go-grpc-prometheus v1.2.0/go.mod h1:8NvIoxWQoOIhqOTXgfV/d3M/q6VIi02HzZEHgUlZvzk= github.com/grpc-ecosystem/grpc-gateway v1.5.0/go.mod h1:RSKVYQBd5MCa4OVpNdGskqpgL2+G+NZTnrVHpWWfpdw= -github.com/grpc-ecosystem/grpc-gateway v1.9.0/go.mod h1:vNeuVxBJEsws4ogUvrchl83t/GYV9WGTSLVdBhOQFDY= +github.com/grpc-ecosystem/grpc-gateway v1.9.5/go.mod h1:vNeuVxBJEsws4ogUvrchl83t/GYV9WGTSLVdBhOQFDY= +github.com/grpc-ecosystem/grpc-gateway v1.12.1/go.mod h1:8XEsbTttt/W+VvjtQhLACqCisSPWTxCZ7sBRjU6iH9c= +github.com/grpc-ecosystem/grpc-gateway v1.16.0/go.mod h1:BDjrQk3hbvj6Nolgz8mAMFbcEtjT1g+wF4CSlocrBnw= github.com/gxed/go-shellwords v1.0.3 h1:2TP32H4TAklZUdz84oj95BJhVnIrRasyx2j1cqH5K38= github.com/gxed/go-shellwords v1.0.3/go.mod h1:N7paucT91ByIjmVJHhvoarjoQnmsi3Jd3vH7VqgtMxQ= github.com/gxed/hashland/keccakpg v0.0.1/go.mod h1:kRzw3HkwxFU1mpmPP8v1WyQzwdGfmKFJ6tItnhQ67kU= github.com/gxed/hashland/murmur3 v0.0.1/go.mod h1:KjXop02n4/ckmZSnY2+HKcLud/tcmvhST0bie/0lS48= +github.com/hannahhoward/cbor-gen-for v0.0.0-20200817222906-ea96cece81f1/go.mod h1:jvfsLIxk0fY/2BKSQ1xf2406AKA5dwMmKKv0ADcOfN8= github.com/hannahhoward/go-pubsub v0.0.0-20200423002714-8d62886cc36e h1:3YKHER4nmd7b5qy5t0GWDTwSn4OyRgfAXSmo6VnryBY= github.com/hannahhoward/go-pubsub v0.0.0-20200423002714-8d62886cc36e/go.mod h1:I8h3MITA53gN9OnWGCgaMa0JWVRdXthWw4M3CPM54OY= +github.com/hashicorp/consul/api v1.3.0/go.mod h1:MmDNSzIMUjNpY/mQ398R4bk2FnqQLoPndWW5VkKPlCE= +github.com/hashicorp/consul/api v1.10.1/go.mod h1:XjsvQN+RJGWI2TWy1/kqaE16HrR2J/FWgkYjdZQsX9M= +github.com/hashicorp/consul/api v1.11.0/go.mod h1:XjsvQN+RJGWI2TWy1/kqaE16HrR2J/FWgkYjdZQsX9M= +github.com/hashicorp/consul/api v1.12.0/go.mod h1:6pVBMo0ebnYdt2S3H87XhekM/HHrUoTD2XXb/VrZVy0= +github.com/hashicorp/consul/sdk v0.3.0/go.mod h1:VKf9jXwCTEY1QZP2MOLRhb5i/I/ssyNV1vwHyQBF0x8= +github.com/hashicorp/consul/sdk v0.8.0/go.mod h1:GBvyrGALthsZObzUGsfgHZQDXjg4lOjagTIwIR1vPms= +github.com/hashicorp/errwrap v1.0.0 h1:hLrqtEDnRye3+sgx6z4qVLNuviH3MR5aQ0ykNJa/UYA= github.com/hashicorp/errwrap v1.0.0/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4= +github.com/hashicorp/go-cleanhttp v0.5.0/go.mod h1:JpRdi6/HCYpAwUzNwuwqhbovhLtngrth3wmdIIUrZ80= +github.com/hashicorp/go-cleanhttp v0.5.1/go.mod h1:JpRdi6/HCYpAwUzNwuwqhbovhLtngrth3wmdIIUrZ80= +github.com/hashicorp/go-cleanhttp v0.5.2/go.mod h1:kO/YDlP8L1346E6Sodw+PrpBSV4/SoxCXGY6BqNFT48= +github.com/hashicorp/go-hclog v0.12.0/go.mod h1:whpDNt7SSdeAju8AWKIWsul05p54N/39EeqMAyrmvFQ= +github.com/hashicorp/go-hclog v1.0.0/go.mod h1:whpDNt7SSdeAju8AWKIWsul05p54N/39EeqMAyrmvFQ= +github.com/hashicorp/go-immutable-radix v1.0.0/go.mod h1:0y9vanUI8NX6FsYoO3zeMjhV/C5i9g4Q3DwcSNZ4P60= +github.com/hashicorp/go-immutable-radix v1.3.1/go.mod h1:0y9vanUI8NX6FsYoO3zeMjhV/C5i9g4Q3DwcSNZ4P60= +github.com/hashicorp/go-msgpack v0.5.3/go.mod h1:ahLV/dePpqEmjfWmKiqvPkv/twdG7iPBM1vqhUKIvfM= github.com/hashicorp/go-multierror v1.0.0/go.mod h1:dHtQlpGsu+cZNNAkkCN/P3hoUDHhCYQXV3UM06sGGrk= +github.com/hashicorp/go-multierror v1.1.0/go.mod h1:spPvp8C1qA32ftKqdAHm4hHTbPw+vmowP0z+KUhOZdA= +github.com/hashicorp/go-multierror v1.1.1 h1:H5DkEtf6CXdFp0N0Em5UCwQpXMWke8IA0+lD48awMYo= +github.com/hashicorp/go-multierror v1.1.1/go.mod h1:iw975J/qwKPdAO1clOe2L8331t/9/fmwbPZ6JB6eMoM= +github.com/hashicorp/go-retryablehttp v0.5.3/go.mod h1:9B5zBasrRhHXnJnui7y6sL7es7NDiJgTc6Er0maI1Xs= +github.com/hashicorp/go-rootcerts v1.0.0/go.mod h1:K6zTfqpRlCUIjkwsN4Z+hiSfzSTQa6eBIzfwKfwNnHU= +github.com/hashicorp/go-rootcerts v1.0.2/go.mod h1:pqUvnprVnM5bf7AOirdbb01K4ccR319Vf4pU3K5EGc8= +github.com/hashicorp/go-sockaddr v1.0.0/go.mod h1:7Xibr9yA9JjQq1JpNB2Vw7kxv8xerXegt+ozgdvDeDU= +github.com/hashicorp/go-syslog v1.0.0/go.mod h1:qPfqrKkXGihmCqbJM2mZgkZGvKG1dFdvsLplgctolz4= +github.com/hashicorp/go-uuid v1.0.0/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro= +github.com/hashicorp/go-uuid v1.0.1/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro= +github.com/hashicorp/go-version v1.2.0/go.mod h1:fltr4n8CU8Ke44wwGCBoEymUuxUHl09ZGVZPK5anwXA= +github.com/hashicorp/go-version v1.2.1/go.mod h1:fltr4n8CU8Ke44wwGCBoEymUuxUHl09ZGVZPK5anwXA= +github.com/hashicorp/go-version v1.4.0 h1:aAQzgqIrRKRa7w75CKpbBxYsmUoPjzVm1W59ca1L0J4= +github.com/hashicorp/go-version v1.4.0/go.mod h1:fltr4n8CU8Ke44wwGCBoEymUuxUHl09ZGVZPK5anwXA= +github.com/hashicorp/go.net v0.0.1/go.mod h1:hjKkEWcCURg++eb33jQU7oqQcI9XDCnUzHA0oac0k90= github.com/hashicorp/golang-lru v0.5.0/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8= github.com/hashicorp/golang-lru v0.5.1/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8= github.com/hashicorp/golang-lru v0.5.3/go.mod h1:iADmTwqILo4mZ8BN3D2Q6+9jd8WM5uGBxy+E8yxSoD4= @@ -238,33 +583,64 @@ github.com/hashicorp/golang-lru v0.5.4 h1:YDjusn29QI/Das2iO9M0BHnIbxPeyuCHsjMW+l github.com/hashicorp/golang-lru v0.5.4/go.mod h1:iADmTwqILo4mZ8BN3D2Q6+9jd8WM5uGBxy+E8yxSoD4= github.com/hashicorp/hcl v1.0.0 h1:0Anlzjpi4vEasTeNFn2mLJgTSwt0+6sfsiTG8qcWGx4= github.com/hashicorp/hcl v1.0.0/go.mod h1:E5yfLk+7swimpb2L/Alb/PJmXilQ/rhwaUYs4T20WEQ= -github.com/hpcloud/tail v1.0.0 h1:nfCOvKYfkgYP8hkirhJocXT2+zOD8yUNjXaWfTlyFKI= +github.com/hashicorp/logutils v1.0.0/go.mod h1:QIAnNjmIWmVIIkWDTG1z5v++HQmx9WQRO+LraFDTW64= +github.com/hashicorp/mdns v1.0.0/go.mod h1:tL+uN++7HEJ6SQLQ2/p+z2pH24WQKWjBPkE0mNTz8vQ= +github.com/hashicorp/mdns v1.0.1/go.mod h1:4gW7WsVCke5TE7EPeYliwHlRUyBtfCwuFwuMg2DmyNY= +github.com/hashicorp/mdns v1.0.4/go.mod h1:mtBihi+LeNXGtG8L9dX59gAEa12BDtBQSp4v/YAJqrc= +github.com/hashicorp/memberlist v0.1.3/go.mod h1:ajVTdAv/9Im8oMAAj5G31PhhMCZJV2pPBoIllUwCN7I= +github.com/hashicorp/memberlist v0.2.2/go.mod h1:MS2lj3INKhZjWNqd3N0m3J+Jxf3DAOnAH9VT3Sh9MUE= +github.com/hashicorp/memberlist v0.3.0/go.mod h1:MS2lj3INKhZjWNqd3N0m3J+Jxf3DAOnAH9VT3Sh9MUE= +github.com/hashicorp/serf v0.8.2/go.mod h1:6hOLApaqBFA1NXqRQAsxw9QxuDEvNxSQRwA/JwenrHc= +github.com/hashicorp/serf v0.9.5/go.mod h1:UWDWwZeL5cuWDJdl0C6wrvrUwEqtQ4ZKBKKENpqIUyk= +github.com/hashicorp/serf v0.9.6/go.mod h1:TXZNMjZQijwlDvp+r0b63xZ45H7JmCmgg4gpTwn9UV4= +github.com/hexops/gotextdiff v1.0.3 h1:gitA9+qJrrTCsiCl7+kh75nPqQt1cx4ZkudSTLoUqJM= +github.com/hexops/gotextdiff v1.0.3/go.mod h1:pSWU5MAI3yDq+fZBTazCSJysOMbxWL1BSow5/V2vxeg= github.com/hpcloud/tail v1.0.0/go.mod h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpOxQnU= -github.com/huin/goupnp v1.0.0 h1:wg75sLpL6DZqwHQN6E1Cfk6mtfzS45z8OV+ic+DtHRo= +github.com/huandu/xstrings v1.0.0/go.mod h1:4qWG/gcEcfX4z/mBDHJ++3ReCw9ibxbsNJbcucJdbSo= +github.com/huandu/xstrings v1.2.0/go.mod h1:DvyZB1rfVYsBIigL8HwpZgxHwXozlTgGqn63UyNX5k4= +github.com/hudl/fargo v1.3.0/go.mod h1:y3CKSmjA+wD2gak7sUSXTAoopbhU08POFhmITJgmKTg= github.com/huin/goupnp v1.0.0/go.mod h1:n9v9KO1tAxYH82qOn+UTIFQDmx5n1Zxd/ClZDMX7Bnc= +github.com/huin/goupnp v1.0.2/go.mod h1:0dxJBVBHqTMjIUMkESDTNgOOx/Mw5wYIfyFmdzSamkM= +github.com/huin/goupnp v1.0.3 h1:N8No57ls+MnjlB+JPiCVSOyy/ot7MJTqlo7rn+NYSqQ= +github.com/huin/goupnp v1.0.3/go.mod h1:ZxNlw5WqJj6wSsRK5+YfflQGXYfccj5VgQsMNixHM7Y= github.com/huin/goutil v0.0.0-20170803182201-1ca381bf3150/go.mod h1:PpLOETDnJ0o3iZrZfqZzyLl6l7F3c6L1oWn7OICBi6o= +github.com/iancoleman/strcase v0.2.0/go.mod h1:iwCmte+B7n89clKwxIoIXy/HfoL7AsD47ZCWhYzw7ho= +github.com/ianlancetaylor/demangle v0.0.0-20181102032728-5e5cf60278f6/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc= +github.com/ianlancetaylor/demangle v0.0.0-20200824232613-28f6c0f3b639/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc= +github.com/imdario/mergo v0.3.4/go.mod h1:2EnlNZ0deacrJVfApfmtdGgDfMuh/nq6Ok1EcJh5FfA= +github.com/imdario/mergo v0.3.8/go.mod h1:2EnlNZ0deacrJVfApfmtdGgDfMuh/nq6Ok1EcJh5FfA= github.com/inconshreveable/mousetrap v1.0.0 h1:Z8tu5sraLXCXIcARxBp/8cbvlwVa7Z1NHg9XEKhtSvM= github.com/inconshreveable/mousetrap v1.0.0/go.mod h1:PxqpIevigyE2G7u3NXJIT2ANytuPF1OarO4DADm73n8= +github.com/influxdata/influxdb1-client v0.0.0-20191209144304-8bf82d3c094d/go.mod h1:qj24IKcXYK6Iy9ceXlo3Tc+vtHo9lIhSX5JddghvEPo= github.com/ipfs/bbloom v0.0.1/go.mod h1:oqo8CVWsJFMOZqTglBG4wydCE4IQA/G2/SEofB0rjUI= github.com/ipfs/bbloom v0.0.4 h1:Gi+8EGJ2y5qiD5FbsbpX/TMNcJw8gSqr7eyjHa4Fhvs= github.com/ipfs/bbloom v0.0.4/go.mod h1:cS9YprKXpoZ9lT0n/Mw/a6/aFV6DTjTLYHeA+gyqMG0= +github.com/ipfs/go-bitfield v1.0.0 h1:y/XHm2GEmD9wKngheWNNCNL0pzrWXZwCdQGv1ikXknQ= +github.com/ipfs/go-bitfield v1.0.0/go.mod h1:N/UiujQy+K+ceU1EF5EkVd1TNqevLrCQMIcAEPrdtus= +github.com/ipfs/go-bitswap v0.0.9/go.mod h1:kAPf5qgn2W2DrgAcscZ3HrM9qh4pH+X8Fkk3UPrwvis= github.com/ipfs/go-bitswap v0.1.0/go.mod h1:FFJEf18E9izuCqUtHxbWEvq+reg7o4CW5wSAE1wsxj0= github.com/ipfs/go-bitswap v0.1.2/go.mod h1:qxSWS4NXGs7jQ6zQvoPY3+NmOfHHG47mhkiLzBpJQIs= -github.com/ipfs/go-bitswap v0.1.8 h1:38X1mKXkiU6Nzw4TOSWD8eTVY5eX3slQunv3QEWfXKg= -github.com/ipfs/go-bitswap v0.1.8/go.mod h1:TOWoxllhccevbWFUR2N7B1MTSVVge1s6XSMiCSA4MzM= +github.com/ipfs/go-bitswap v0.5.1/go.mod h1:P+ckC87ri1xFLvk74NlXdP0Kj9RmWAh4+H78sC6Qopo= +github.com/ipfs/go-bitswap v0.6.0 h1:f2rc6GZtoSFhEIzQmddgGiel9xntj02Dg0ZNf2hSC+w= +github.com/ipfs/go-bitswap v0.6.0/go.mod h1:Hj3ZXdOC5wBJvENtdqsixmzzRukqd8EHLxZLZc3mzRA= github.com/ipfs/go-block-format v0.0.1/go.mod h1:DK/YYcsSUIVAFNwo/KZCdIIbpN0ROH/baNLgayt4pFc= -github.com/ipfs/go-block-format v0.0.2 h1:qPDvcP19izTjU8rgo6p7gTXZlkMkF5bz5G3fqIsSCPE= github.com/ipfs/go-block-format v0.0.2/go.mod h1:AWR46JfpcObNfg3ok2JHDUfdiHRgWhJgCQF+KIgOPJY= +github.com/ipfs/go-block-format v0.0.3 h1:r8t66QstRp/pd/or4dpnbVfXT5Gt7lOqRvC+/dDTpMc= +github.com/ipfs/go-block-format v0.0.3/go.mod h1:4LmD4ZUw0mhO+JSKdpWwrzATiEfM7WWgQ8H5l6P8MVk= +github.com/ipfs/go-blockservice v0.0.7/go.mod h1:EOfb9k/Y878ZTRY/CH0x5+ATtaipfbRhbvNSdgc/7So= github.com/ipfs/go-blockservice v0.1.0/go.mod h1:hzmMScl1kXHg3M2BjTymbVPjv627N7sYcvYaKbop39M= -github.com/ipfs/go-blockservice v0.1.3 h1:9XgsPMwwWJSC9uVr2pMDsW2qFTBSkxpGMhmna8mIjPM= -github.com/ipfs/go-blockservice v0.1.3/go.mod h1:OTZhFpkgY48kNzbgyvcexW9cHrpjBYIjSR0KoDOFOLU= +github.com/ipfs/go-blockservice v0.2.1/go.mod h1:k6SiwmgyYgs4M/qt+ww6amPeUH9EISLRBnvUurKJhi8= +github.com/ipfs/go-blockservice v0.3.0 h1:cDgcZ+0P0Ih3sl8+qjFr2sVaMdysg/YZpLj5WJ8kiiw= +github.com/ipfs/go-blockservice v0.3.0/go.mod h1:P5ppi8IHDC7O+pA0AlGTF09jruB2h+oP3wVVaZl8sfk= github.com/ipfs/go-cid v0.0.1/go.mod h1:GHWU/WuQdMPmIosc4Yn1bcCT7dSeX4lBafM7iqUPQvM= github.com/ipfs/go-cid v0.0.2/go.mod h1:GHWU/WuQdMPmIosc4Yn1bcCT7dSeX4lBafM7iqUPQvM= github.com/ipfs/go-cid v0.0.3/go.mod h1:GHWU/WuQdMPmIosc4Yn1bcCT7dSeX4lBafM7iqUPQvM= github.com/ipfs/go-cid v0.0.4/go.mod h1:4LLaPOQwmk5z9LBgQnpkivrx8BJjUyGwTXCd5Xfj6+M= github.com/ipfs/go-cid v0.0.5/go.mod h1:plgt+Y5MnOey4vO4UlUazGqdbEXuFYitED67FexhXog= -github.com/ipfs/go-cid v0.0.6 h1:go0y+GcDOGeJIV01FeBsta4FHngoA4Wz7KMeLkXAhMs= github.com/ipfs/go-cid v0.0.6/go.mod h1:6Ux9z5e+HpkQdckYoX1PG/6xqKspzlEIR5SDmgqgC/I= +github.com/ipfs/go-cid v0.0.7/go.mod h1:6Ux9z5e+HpkQdckYoX1PG/6xqKspzlEIR5SDmgqgC/I= +github.com/ipfs/go-cid v0.1.0 h1:YN33LQulcRHjfom/i25yoOZR4Telp1Hr/2RU3d0PnC0= +github.com/ipfs/go-cid v0.1.0/go.mod h1:rH5/Xv83Rfy8Rw6xG+id3DYAMUVmem1MowoKwdXmN2o= github.com/ipfs/go-cidutil v0.0.2 h1:CNOboQf1t7Qp0nuNh8QMmhJs0+Q//bRL1axtCnIB1Yo= github.com/ipfs/go-cidutil v0.0.2/go.mod h1:ewllrvrxG6AMYStla3GD7Cqn+XYSLqjK0vc+086tB6s= github.com/ipfs/go-datastore v0.0.1/go.mod h1:d4KVXhMt913cLBEI/PXAy6ko+W7e9AhyAKBGh803qeE= @@ -274,42 +650,51 @@ github.com/ipfs/go-datastore v0.1.1/go.mod h1:w38XXW9kVFNp57Zj5knbKWM2T+KOZCGDRV github.com/ipfs/go-datastore v0.3.1/go.mod h1:w38XXW9kVFNp57Zj5knbKWM2T+KOZCGDRVNdgPHtbHw= github.com/ipfs/go-datastore v0.4.0/go.mod h1:SX/xMIKoCszPqp+z9JhPYCmoOoXTvaa13XEbGtsFUhA= github.com/ipfs/go-datastore v0.4.1/go.mod h1:SX/xMIKoCszPqp+z9JhPYCmoOoXTvaa13XEbGtsFUhA= -github.com/ipfs/go-datastore v0.4.4 h1:rjvQ9+muFaJ+QZ7dN5B1MSDNQ0JVZKkkES/rMZmA8X8= github.com/ipfs/go-datastore v0.4.4/go.mod h1:SX/xMIKoCszPqp+z9JhPYCmoOoXTvaa13XEbGtsFUhA= +github.com/ipfs/go-datastore v0.4.5/go.mod h1:eXTcaaiN6uOlVCLS9GjJUJtlvJfM3xk23w3fyfrmmJs= +github.com/ipfs/go-datastore v0.5.0/go.mod h1:9zhEApYMTl17C8YDp7JmU7sQZi2/wqiYh73hakZ90Bk= +github.com/ipfs/go-datastore v0.5.1 h1:WkRhLuISI+XPD0uk3OskB0fYFSyqK8Ob5ZYew9Qa1nQ= +github.com/ipfs/go-datastore v0.5.1/go.mod h1:9zhEApYMTl17C8YDp7JmU7sQZi2/wqiYh73hakZ90Bk= github.com/ipfs/go-detect-race v0.0.1 h1:qX/xay2W3E4Q1U7d9lNs1sU9nvguX0a7319XbyQ6cOk= github.com/ipfs/go-detect-race v0.0.1/go.mod h1:8BNT7shDZPo99Q74BpGMK+4D8Mn4j46UU0LZ723meps= github.com/ipfs/go-ds-badger v0.0.2/go.mod h1:Y3QpeSFWQf6MopLTiZD+VT6IC1yZqaGmjvRcKeSGij8= github.com/ipfs/go-ds-badger v0.0.5/go.mod h1:g5AuuCGmr7efyzQhLL8MzwqcauPojGPUaHzfGTzuE3s= github.com/ipfs/go-ds-badger v0.2.1/go.mod h1:Tx7l3aTph3FMFrRS838dcSJh+jjA7cX9DrGVwx/NOwE= github.com/ipfs/go-ds-badger v0.2.3/go.mod h1:pEYw0rgg3FIrywKKnL+Snr+w/LjJZVMTBRn4FS6UHUk= +github.com/ipfs/go-ds-badger v0.3.0/go.mod h1:1ke6mXNqeV8K3y5Ak2bAA0osoTfmxUdupVCGm4QUIek= github.com/ipfs/go-ds-leveldb v0.0.1/go.mod h1:feO8V3kubwsEF22n0YRQCffeb79OOYIykR4L04tMOYc= github.com/ipfs/go-ds-leveldb v0.4.1/go.mod h1:jpbku/YqBSsBc1qgME8BkWS4AxzF2cEu1Ii2r79Hh9s= github.com/ipfs/go-ds-leveldb v0.4.2/go.mod h1:jpbku/YqBSsBc1qgME8BkWS4AxzF2cEu1Ii2r79Hh9s= -github.com/ipfs/go-graphsync v0.1.1 h1:bFDAYS0Z48yd8ROPI6f/zIVmJxaDLA6m8cVuJPKC5fE= -github.com/ipfs/go-graphsync v0.1.1/go.mod h1:jMXfqIEDFukLPZHqDPp8tJMbHO9Rmeb9CEGevngQbmE= +github.com/ipfs/go-ds-leveldb v0.5.0/go.mod h1:d3XG9RUDzQ6V4SHi8+Xgj9j1XuEk1z82lquxrVbml/Q= +github.com/ipfs/go-graphsync v0.11.0 h1:PiiD5CnoC3xEHMW8d6uBGqGcoTwiMB5d9CORIEyF6iA= +github.com/ipfs/go-graphsync v0.11.0/go.mod h1:wC+c8vGVjAHthsVIl8LKr37cUra2GOaMYcQNNmMxDqE= github.com/ipfs/go-ipfs-blockstore v0.0.1/go.mod h1:d3WClOmRQKFnJ0Jz/jj/zmksX0ma1gROTlovZKBmN08= github.com/ipfs/go-ipfs-blockstore v0.1.0/go.mod h1:5aD0AvHPi7mZc6Ci1WCAhiBQu2IsfTduLl+422H6Rqw= -github.com/ipfs/go-ipfs-blockstore v0.1.4/go.mod h1:Jxm3XMVjh6R17WvxFEiyKBLUGr86HgIYJW/D/MwqeYQ= -github.com/ipfs/go-ipfs-blockstore v1.0.0 h1:pmFp5sFYsYVvMOp9X01AK3s85usVcLvkBTRsN6SnfUA= -github.com/ipfs/go-ipfs-blockstore v1.0.0/go.mod h1:knLVdhVU9L7CC4T+T4nvGdeUIPAXlnd9zmXfp+9MIjU= +github.com/ipfs/go-ipfs-blockstore v0.2.1/go.mod h1:jGesd8EtCM3/zPgx+qr0/feTXGUeRai6adgwC+Q+JvE= +github.com/ipfs/go-ipfs-blockstore v1.2.0 h1:n3WTeJ4LdICWs/0VSfjHrlqpPpl6MZ+ySd3j8qz0ykw= +github.com/ipfs/go-ipfs-blockstore v1.2.0/go.mod h1:eh8eTFLiINYNSNawfZOC7HOxNTxpB1PFuA5E1m/7exE= github.com/ipfs/go-ipfs-blocksutil v0.0.1 h1:Eh/H4pc1hsvhzsQoMEP3Bke/aW5P5rVM1IWFJMcGIPQ= github.com/ipfs/go-ipfs-blocksutil v0.0.1/go.mod h1:Yq4M86uIOmxmGPUHv/uI7uKqZNtLb449gwKqXjIsnRk= github.com/ipfs/go-ipfs-chunker v0.0.1/go.mod h1:tWewYK0we3+rMbOh7pPFGDyypCtvGcBFymgY4rSDLAw= github.com/ipfs/go-ipfs-chunker v0.0.5 h1:ojCf7HV/m+uS2vhUGWcogIIxiO5ubl5O57Q7NapWLY8= github.com/ipfs/go-ipfs-chunker v0.0.5/go.mod h1:jhgdF8vxRHycr00k13FM8Y0E+6BoalYeobXmUyTreP8= -github.com/ipfs/go-ipfs-config v0.5.3 h1:3GpI/xR9FoJNTjU6YvCMRbYyEi0dBVY5UtlUTcNRlSA= github.com/ipfs/go-ipfs-config v0.5.3/go.mod h1:nSLCFtlaL+2rbl3F+9D4gQZQbT1LjRKx7TJg/IHz6oM= +github.com/ipfs/go-ipfs-config v0.19.0 h1:OuKIL+BkOZgJ+hb4Wg/9ynCtE/BaZBWcGy8hgdMepAo= +github.com/ipfs/go-ipfs-config v0.19.0/go.mod h1:wz2lKzOjgJeYJa6zx8W9VT7mz+iSd0laBMqS/9wmX6A= github.com/ipfs/go-ipfs-delay v0.0.0-20181109222059-70721b86a9a8/go.mod h1:8SP1YXK1M1kXuc4KJZINY3TQQ03J2rwBG9QfXmbRPrw= github.com/ipfs/go-ipfs-delay v0.0.1 h1:r/UXYyRcddO6thwOnhiznIAiSvxMECGgtv35Xs1IeRQ= github.com/ipfs/go-ipfs-delay v0.0.1/go.mod h1:8SP1YXK1M1kXuc4KJZINY3TQQ03J2rwBG9QfXmbRPrw= github.com/ipfs/go-ipfs-ds-help v0.0.1/go.mod h1:gtP9xRaZXqIQRh1HRpp595KbBEdgqWFxefeVKOV8sxo= github.com/ipfs/go-ipfs-ds-help v0.1.1/go.mod h1:SbBafGJuGsPI/QL3j9Fc5YPLeAu+SzOkI0gFwAg+mOs= -github.com/ipfs/go-ipfs-ds-help v1.0.0 h1:bEQ8hMGs80h0sR8O4tfDgV6B01aaF9qeTrujrTLYV3g= -github.com/ipfs/go-ipfs-ds-help v1.0.0/go.mod h1:ujAbkeIgkKAWtxxNkoZHWLCyk5JpPoKnGyCcsoF6ueE= -github.com/ipfs/go-ipfs-exchange-interface v0.0.1 h1:LJXIo9W7CAmugqI+uofioIpRb6rY30GUu7G6LUfpMvM= +github.com/ipfs/go-ipfs-ds-help v1.1.0 h1:yLE2w9RAsl31LtfMt91tRZcrx+e61O5mDxFRR994w4Q= +github.com/ipfs/go-ipfs-ds-help v1.1.0/go.mod h1:YR5+6EaebOhfcqVCyqemItCLthrpVNot+rsOU/5IatU= github.com/ipfs/go-ipfs-exchange-interface v0.0.1/go.mod h1:c8MwfHjtQjPoDyiy9cFquVtVHkO9b9Ob3FG91qJnWCM= -github.com/ipfs/go-ipfs-exchange-offline v0.0.1 h1:P56jYKZF7lDDOLx5SotVh5KFxoY6C81I1NSHW1FxGew= +github.com/ipfs/go-ipfs-exchange-interface v0.1.0 h1:TiMekCrOGQuWYtZO3mf4YJXDIdNgnKWZ9IE3fGlnWfo= +github.com/ipfs/go-ipfs-exchange-interface v0.1.0/go.mod h1:ych7WPlyHqFvCi/uQI48zLZuAWVP5iTQPXEfVaw5WEI= github.com/ipfs/go-ipfs-exchange-offline v0.0.1/go.mod h1:WhHSFCVYX36H/anEKQboAzpUws3x7UeEGkzQc3iNkM0= +github.com/ipfs/go-ipfs-exchange-offline v0.1.1/go.mod h1:vTiBRIbzSwDD0OWm+i3xeT0mO7jG2cbJYatp3HPk5XY= +github.com/ipfs/go-ipfs-exchange-offline v0.2.0 h1:2PF4o4A7W656rC0RxuhUace997FTcDTcIQ6NoEtyjAI= +github.com/ipfs/go-ipfs-exchange-offline v0.2.0/go.mod h1:HjwBeW0dvZvfOMwDP0TSKXIHf2s+ksdP4E3MLDRtLKY= github.com/ipfs/go-ipfs-files v0.0.3/go.mod h1:INEFm0LL2LWXBhNJ2PMIIb2w45hpXgPjNoE7yA8Y1d4= github.com/ipfs/go-ipfs-files v0.0.8 h1:8o0oFJkJ8UkO/ABl8T6ac6tKF3+NIpj67aAB6ZpusRg= github.com/ipfs/go-ipfs-files v0.0.8/go.mod h1:wiN/jSG8FKyk7N0WyctKSvq3ljIa2NNTiZB55kpTdOs= @@ -318,60 +703,81 @@ github.com/ipfs/go-ipfs-posinfo v0.0.1/go.mod h1:SwyeVP+jCwiDu0C313l/8jg6ZxM0qqt github.com/ipfs/go-ipfs-pq v0.0.1/go.mod h1:LWIqQpqfRG3fNc5XsnIhz/wQ2XXGyugQwls7BgUmUfY= github.com/ipfs/go-ipfs-pq v0.0.2 h1:e1vOOW6MuOwG2lqxcLA+wEn93i/9laCY8sXAw76jFOY= github.com/ipfs/go-ipfs-pq v0.0.2/go.mod h1:LWIqQpqfRG3fNc5XsnIhz/wQ2XXGyugQwls7BgUmUfY= -github.com/ipfs/go-ipfs-routing v0.1.0 h1:gAJTT1cEeeLj6/DlLX6t+NxD9fQe2ymTO6qWRDI/HQQ= +github.com/ipfs/go-ipfs-routing v0.0.1/go.mod h1:k76lf20iKFxQTjcJokbPM9iBXVXVZhcOwc360N4nuKs= github.com/ipfs/go-ipfs-routing v0.1.0/go.mod h1:hYoUkJLyAUKhF58tysKpids8RNDPO42BVMgK5dNsoqY= +github.com/ipfs/go-ipfs-routing v0.2.1 h1:E+whHWhJkdN9YeoHZNj5itzc+OR292AJ2uE9FFiW0BY= +github.com/ipfs/go-ipfs-routing v0.2.1/go.mod h1:xiNNiwgjmLqPS1cimvAw6EyB9rkVDbiocA4yY+wRNLM= github.com/ipfs/go-ipfs-util v0.0.1/go.mod h1:spsl5z8KUnrve+73pOhSVZND1SIxPW5RyBCNzQxlJBc= github.com/ipfs/go-ipfs-util v0.0.2 h1:59Sswnk1MFaiq+VcaknX7aYEyGyGDAA73ilhEK2POp8= github.com/ipfs/go-ipfs-util v0.0.2/go.mod h1:CbPtkWJzjLdEcezDns2XYaehFVNXG9zrdrtMecczcsQ= github.com/ipfs/go-ipld-cbor v0.0.2/go.mod h1:wTBtrQZA3SoFKMVkp6cn6HMRteIB1VsmHA0AQFOn7Nc= github.com/ipfs/go-ipld-cbor v0.0.3/go.mod h1:wTBtrQZA3SoFKMVkp6cn6HMRteIB1VsmHA0AQFOn7Nc= -github.com/ipfs/go-ipld-cbor v0.0.4 h1:Aw3KPOKXjvrm6VjwJvFf1F1ekR/BH3jdof3Bk7OTiSA= github.com/ipfs/go-ipld-cbor v0.0.4/go.mod h1:BkCduEx3XBCO6t2Sfo5BaHzuok7hbhdMm9Oh8B2Ftq4= +github.com/ipfs/go-ipld-cbor v0.0.5 h1:ovz4CHKogtG2KB/h1zUp5U0c/IzZrL435rCh5+K/5G8= +github.com/ipfs/go-ipld-cbor v0.0.5/go.mod h1:BkCduEx3XBCO6t2Sfo5BaHzuok7hbhdMm9Oh8B2Ftq4= github.com/ipfs/go-ipld-format v0.0.1/go.mod h1:kyJtbkDALmFHv3QR6et67i35QzO3S0dCDnkOJhcZkms= github.com/ipfs/go-ipld-format v0.0.2/go.mod h1:4B6+FM2u9OJ9zCV+kSbgFAZlOrv1Hqbf0INGQgiKf9k= -github.com/ipfs/go-ipld-format v0.2.0 h1:xGlJKkArkmBvowr+GMCX0FEZtkro71K1AwiKnL37mwA= github.com/ipfs/go-ipld-format v0.2.0/go.mod h1:3l3C1uKoadTPbeNfrDi+xMInYKlx2Cvg1BuydPSdzQs= +github.com/ipfs/go-ipld-format v0.3.0/go.mod h1:co/SdBE8h99968X0hViiw1MNlh6fvxxnHpvVLnH7jSM= +github.com/ipfs/go-ipld-format v0.4.0 h1:yqJSaJftjmjc9jEOFYlpkwOLVKv68OD27jFLlSghBlQ= +github.com/ipfs/go-ipld-format v0.4.0/go.mod h1:co/SdBE8h99968X0hViiw1MNlh6fvxxnHpvVLnH7jSM= +github.com/ipfs/go-ipld-legacy v0.1.0 h1:wxkkc4k8cnvIGIjPO0waJCe7SHEyFgl+yQdafdjGrpA= +github.com/ipfs/go-ipld-legacy v0.1.0/go.mod h1:86f5P/srAmh9GcIcWQR9lfFLZPrIyyXQeVlOWeeWEuI= github.com/ipfs/go-log v0.0.1/go.mod h1:kL1d2/hzSpI0thNYjiKfjanbVNU+IIGA/WnNESY9leM= github.com/ipfs/go-log v1.0.2/go.mod h1:1MNjMxe0u6xvJZgeqbJ8vdo2TKaGwZ1a0Bpza+sr2Sk= github.com/ipfs/go-log v1.0.3/go.mod h1:OsLySYkwIbiSUR/yBTdv1qPtcE4FW3WPWk/ewz9Ru+A= -github.com/ipfs/go-log v1.0.4 h1:6nLQdX4W8P9yZZFH7mO+X/PzjN8Laozm/lMJ6esdgzY= github.com/ipfs/go-log v1.0.4/go.mod h1:oDCg2FkjogeFOhqqb+N39l2RpTNPL6F/StPkB3kPgcs= +github.com/ipfs/go-log v1.0.5 h1:2dOuUCB1Z7uoczMWgAyDck5JLb72zHzrMnGnCNNbvY8= +github.com/ipfs/go-log v1.0.5/go.mod h1:j0b8ZoR+7+R99LD9jZ6+AJsrzkPbSXbZfGakb5JPtIo= github.com/ipfs/go-log/v2 v2.0.2/go.mod h1:O7P1lJt27vWHhOwQmcFEvlmo49ry2VY2+JfBWFaa9+0= github.com/ipfs/go-log/v2 v2.0.3/go.mod h1:O7P1lJt27vWHhOwQmcFEvlmo49ry2VY2+JfBWFaa9+0= -github.com/ipfs/go-log/v2 v2.0.5 h1:fL4YI+1g5V/b1Yxr1qAiXTMg1H8z9vx/VmJxBuQMHvU= github.com/ipfs/go-log/v2 v2.0.5/go.mod h1:eZs4Xt4ZUJQFM3DlanGhy7TkwwawCZcSByscwkWG+dw= +github.com/ipfs/go-log/v2 v2.1.1/go.mod h1:2v2nsGfZsvvAJz13SyFzf9ObaqwHiHxsPLEHntrv9KM= +github.com/ipfs/go-log/v2 v2.1.3/go.mod h1:/8d0SH3Su5Ooc31QlL1WysJhvyOTDCjcCZ9Axpmri6g= +github.com/ipfs/go-log/v2 v2.3.0/go.mod h1:QqGoj30OTpnKaG/LKTGTxoP2mmQtjVMEnK72gynbe/g= +github.com/ipfs/go-log/v2 v2.5.0/go.mod h1:prSpmC1Gpllc9UYWxDiZDreBYw7zp4Iqp1kOLU9U5UI= +github.com/ipfs/go-log/v2 v2.5.1 h1:1XdUzF7048prq4aBjDQQ4SL5RxftpRGdXhNRwKSAlcY= +github.com/ipfs/go-log/v2 v2.5.1/go.mod h1:prSpmC1Gpllc9UYWxDiZDreBYw7zp4Iqp1kOLU9U5UI= +github.com/ipfs/go-merkledag v0.0.6/go.mod h1:QYPdnlvkOg7GnQRofu9XZimC5ZW5Wi3bKys/4GQQfto= github.com/ipfs/go-merkledag v0.2.3/go.mod h1:SQiXrtSts3KGNmgOzMICy5c0POOpUNQLvB3ClKnBAlk= -github.com/ipfs/go-merkledag v0.3.1/go.mod h1:fvkZNNZixVW6cKSZ/JfLlON5OlgTXNdRLz0p6QG/I2M= -github.com/ipfs/go-merkledag v0.3.2 h1:MRqj40QkrWkvPswXs4EfSslhZ4RVPRbxwX11js0t1xY= github.com/ipfs/go-merkledag v0.3.2/go.mod h1:fvkZNNZixVW6cKSZ/JfLlON5OlgTXNdRLz0p6QG/I2M= +github.com/ipfs/go-merkledag v0.5.1/go.mod h1:cLMZXx8J08idkp5+id62iVftUQV+HlYJ3PIhDfZsjA4= +github.com/ipfs/go-merkledag v0.6.0 h1:oV5WT2321tS4YQVOPgIrWHvJ0lJobRTerU+i9nmUCuA= +github.com/ipfs/go-merkledag v0.6.0/go.mod h1:9HSEwRd5sV+lbykiYP+2NC/3o6MZbKNaa4hfNcH5iH0= github.com/ipfs/go-metrics-interface v0.0.1 h1:j+cpbjYvu4R8zbleSs36gvB7jR+wsL2fGD6n0jO4kdg= github.com/ipfs/go-metrics-interface v0.0.1/go.mod h1:6s6euYU4zowdslK0GKHmqaIZ3j/b/tL7HTWtJ4VPgWY= +github.com/ipfs/go-path v0.0.7/go.mod h1:6KTKmeRnBXgqrTvzFrPV3CamxcgvXX/4z79tfAd2Sno= +github.com/ipfs/go-peertaskqueue v0.0.4/go.mod h1:03H8fhyeMfKNFWqzYEVyMbcPUeYrqP1MX6Kd+aN+rMQ= github.com/ipfs/go-peertaskqueue v0.1.0/go.mod h1:Jmk3IyCcfl1W3jTW3YpghSwSEC6IJ3Vzz/jUmWw8Z0U= -github.com/ipfs/go-peertaskqueue v0.1.1/go.mod h1:Jmk3IyCcfl1W3jTW3YpghSwSEC6IJ3Vzz/jUmWw8Z0U= -github.com/ipfs/go-peertaskqueue v0.2.0 h1:2cSr7exUGKYyDeUyQ7P/nHPs9P7Ht/B+ROrpN1EJOjc= -github.com/ipfs/go-peertaskqueue v0.2.0/go.mod h1:5/eNrBEbtSKWCG+kQK8K8fGNixoYUnr+P7jivavs9lY= +github.com/ipfs/go-peertaskqueue v0.7.0 h1:VyO6G4sbzX80K58N60cCaHsSsypbUNs1GjO5seGNsQ0= +github.com/ipfs/go-peertaskqueue v0.7.0/go.mod h1:M/akTIE/z1jGNXMU7kFB4TeSEFvj68ow0Rrb04donIU= github.com/ipfs/go-todocounter v0.0.1/go.mod h1:l5aErvQc8qKE2r7NDMjmq5UNAvuZy0rC8BHOplkWvZ4= -github.com/ipfs/go-unixfs v0.2.4 h1:6NwppOXefWIyysZ4LR/qUBPvXd5//8J3jiMdvpbw6Lo= github.com/ipfs/go-unixfs v0.2.4/go.mod h1:SUdisfUjNoSDzzhGVxvCL9QO/nKdwXdr+gbMUdqcbYw= +github.com/ipfs/go-unixfs v0.3.1 h1:LrfED0OGfG98ZEegO4/xiprx2O+yS+krCMQSp7zLVv8= +github.com/ipfs/go-unixfs v0.3.1/go.mod h1:h4qfQYzghiIc8ZNFKiLMFWOTzrWIAtzYQ59W/pCFf1o= github.com/ipfs/go-verifcid v0.0.1 h1:m2HI7zIuR5TFyQ1b79Da5N9dnnCP1vcu2QqawmWlK2E= github.com/ipfs/go-verifcid v0.0.1/go.mod h1:5Hrva5KBeIog4A+UpqlaIU+DEstipcJYQQZc0g37pY0= -github.com/ipfs/hang-fds v0.0.2 h1:ffZPd+OFbKpfjNAoBCI+G7okTQKd7oS1jCEDm2Kzm4c= -github.com/ipfs/hang-fds v0.0.2/go.mod h1:Ajpp/qR2orKbv5LsZmotGRASTcH38MwcIG5vTlZ9y8k= +github.com/ipfs/hang-fds v0.1.0 h1:deBiFlWHsVGzJ0ZMaqscEqRM1r2O1rFZ59UiQXb1Xko= +github.com/ipfs/hang-fds v0.1.0/go.mod h1:29VLWOn3ftAgNNgXg/al7b11UzuQ+w7AwtCGcTaWkbM= +github.com/ipfs/interface-go-ipfs-core v0.4.0 h1:+mUiamyHIwedqP8ZgbCIwpy40oX7QcXUbo4CZOeJVJg= +github.com/ipfs/interface-go-ipfs-core v0.4.0/go.mod h1:UJBcU6iNennuI05amq3FQ7g0JHUkibHFAfhfUIy927o= github.com/ipfs/iptb v1.4.0 h1:YFYTrCkLMRwk/35IMyC6+yjoQSHTEcNcefBStLJzgvo= github.com/ipfs/iptb v1.4.0/go.mod h1:1rzHpCYtNp87/+hTxG5TfCVn/yMY3dKnLn8tBiMfdmg= github.com/ipfs/iptb-plugins v0.3.0 h1:C1rpq1o5lUZtaAOkLIox5akh6ba4uk/3RwWc6ttVxw0= github.com/ipfs/iptb-plugins v0.3.0/go.mod h1:5QtOvckeIw4bY86gSH4fgh3p3gCSMn3FmIKr4gaBncA= -github.com/ipld/go-ipld-prime v0.0.2-0.20200428162820-8b59dc292b8e/go.mod h1:uVIwe/u0H4VdKv3kaN1ck7uCb6yD9cFLS9/ELyXbsw8= -github.com/ipld/go-ipld-prime v0.0.4-0.20200503082126-7e0619f3a984 h1:IZS2f6O/JchRZ9B/hVOClRqJW3a0bJFovhfhCUj/a8o= -github.com/ipld/go-ipld-prime v0.0.4-0.20200503082126-7e0619f3a984/go.mod h1:uVIwe/u0H4VdKv3kaN1ck7uCb6yD9cFLS9/ELyXbsw8= -github.com/ipld/go-ipld-prime-proto v0.0.0-20200428191222-c1ffdadc01e1 h1:K1Ysr7kgIlo7YQkPqdkA6H7BVdIugvuAz7OQUTJxLdE= -github.com/ipld/go-ipld-prime-proto v0.0.0-20200428191222-c1ffdadc01e1/go.mod h1:OAV6xBmuTLsPZ+epzKkPB1e25FHk/vCtyatkdHcArLs= +github.com/ipld/go-codec-dagpb v1.3.0/go.mod h1:ga4JTU3abYApDC3pZ00BC2RSvC3qfBb9MSJkMLSwnhA= +github.com/ipld/go-codec-dagpb v1.4.0 h1:VqADPIFng8G4vz5EQytmmcx/2gEgOHfBuw/kIuCgDAY= +github.com/ipld/go-codec-dagpb v1.4.0/go.mod h1:ErNNglIi5KMur/MfFE/svtgQthzVvf+43MrzLbpcIZY= +github.com/ipld/go-ipld-prime v0.9.1-0.20210324083106-dc342a9917db/go.mod h1:KvBLMr4PX1gWptgkzRjVZCrLmSGcZCb/jioOQwCqZN8= +github.com/ipld/go-ipld-prime v0.11.0/go.mod h1:+WIAkokurHmZ/KwzDOMUuoeJgaRQktHtEaLglS3ZeV8= +github.com/ipld/go-ipld-prime v0.12.3/go.mod h1:PaeLYq8k6dJLmDUSLrzkEpoGV4PEfe/1OtFN/eALOc8= +github.com/ipld/go-ipld-prime v0.16.0 h1:RS5hhjB/mcpeEPJvfyj0qbOj/QL+/j05heZ0qa97dVo= +github.com/ipld/go-ipld-prime v0.16.0/go.mod h1:axSCuOCBPqrH+gvXr2w9uAOulJqBPhHPT2PjoiiU1qA= github.com/jackpal/gateway v1.0.5/go.mod h1:lTpwd4ACLXmpyiCTRtfiNyVnUmqT9RivzCDQetPfnjA= github.com/jackpal/go-nat-pmp v1.0.1/go.mod h1:QPH045xvCAeXUZOxsnwmrtiCoxIr9eob+4orBN1SBKc= github.com/jackpal/go-nat-pmp v1.0.2 h1:KzKSgb7qkJvOUTqYl9/Hg/me3pWgBmERKrTGD7BdWus= github.com/jackpal/go-nat-pmp v1.0.2/go.mod h1:QPH045xvCAeXUZOxsnwmrtiCoxIr9eob+4orBN1SBKc= github.com/jbenet/go-cienv v0.0.0-20150120210510-1bb1476777ec/go.mod h1:rGaEvXB4uRSZMmzKNLoXvTu1sfx+1kv/DojUlPrSZGs= -github.com/jbenet/go-cienv v0.1.0 h1:Vc/s0QbQtoxX8MwwSLWWh+xNNZvM3Lw7NsTcHrvvhMc= github.com/jbenet/go-cienv v0.1.0/go.mod h1:TqNnHUmJgXau0nCzC7kXWeotg3J9W34CUv5Djy1+FlA= github.com/jbenet/go-random v0.0.0-20190219211222-123a90aedc0c h1:uUx61FiAa1GI6ZmVd2wf2vULeQZIKG66eybjNXKYCz4= github.com/jbenet/go-random v0.0.0-20190219211222-123a90aedc0c/go.mod h1:sdx1xVM9UuLw1tXnhJWN3piypTUO3vCIHYmG15KE/dU= @@ -387,56 +793,112 @@ github.com/jbenet/goprocess v0.1.4/go.mod h1:5yspPrukOVuOLORacaBi858NqyClJPQxYZl github.com/jellevandenhooff/dkim v0.0.0-20150330215556-f50fe3d243e1/go.mod h1:E0B/fFc00Y+Rasa88328GlI/XbtyysCtTHZS8h7IrBU= github.com/jessevdk/go-flags v0.0.0-20141203071132-1679536dcc89/go.mod h1:4FA24M0QyGHXBuZZK/XkWh8h0e1EYbRYJSGM75WSRxI= github.com/jessevdk/go-flags v1.4.0/go.mod h1:4FA24M0QyGHXBuZZK/XkWh8h0e1EYbRYJSGM75WSRxI= -github.com/jingyugao/rowserrcheck v0.0.0-20191204022205-72ab7603b68a h1:GmsqmapfzSJkm28dhRoHz2tLRbJmqhU86IPgBtN3mmk= -github.com/jingyugao/rowserrcheck v0.0.0-20191204022205-72ab7603b68a/go.mod h1:xRskid8CManxVta/ALEhJha/pweKBaVG6fWgc0yH25s= -github.com/jirfag/go-printf-func-name v0.0.0-20191110105641-45db9963cdd3 h1:jNYPNLe3d8smommaoQlK7LOA5ESyUJJ+Wf79ZtA7Vp4= -github.com/jirfag/go-printf-func-name v0.0.0-20191110105641-45db9963cdd3/go.mod h1:HEWGJkRDzjJY2sqdDwxccsGicWEf9BQOZsq2tV+xzM0= -github.com/jmoiron/sqlx v1.2.1-0.20190826204134-d7d95172beb5/go.mod h1:1FEQNm3xlJgrMD+FBdI9+xvCksHtbpVBBw5dYhBSsks= -github.com/jonboulle/clockwork v0.1.0 h1:VKV+ZcuP6l3yW9doeqz6ziZGgcynBVQO+obU0+0hcPo= +github.com/jgautheron/goconst v1.5.1 h1:HxVbL1MhydKs8R8n/HE5NPvzfaYmQJA3o879lE4+WcM= +github.com/jgautheron/goconst v1.5.1/go.mod h1:aAosetZ5zaeC/2EfMeRswtxUFBpe2Hr7HzkgX4fanO4= +github.com/jhump/protoreflect v1.6.1/go.mod h1:RZQ/lnuN+zqeRVpQigTwO6o0AJUkxbnSnpuG7toUTG4= +github.com/jingyugao/rowserrcheck v1.1.1 h1:zibz55j/MJtLsjP1OF4bSdgXxwL1b+Vn7Tjzq7gFzUs= +github.com/jingyugao/rowserrcheck v1.1.1/go.mod h1:4yvlZSDb3IyDTUZJUmpZfm2Hwok+Dtp+nu2qOq+er9c= +github.com/jirfag/go-printf-func-name v0.0.0-20200119135958-7558a9eaa5af h1:KA9BjwUk7KlCh6S9EAGWBt1oExIUv9WyNCiRz5amv48= +github.com/jirfag/go-printf-func-name v0.0.0-20200119135958-7558a9eaa5af/go.mod h1:HEWGJkRDzjJY2sqdDwxccsGicWEf9BQOZsq2tV+xzM0= +github.com/jmespath/go-jmespath v0.0.0-20180206201540-c2b33e8439af/go.mod h1:Nht3zPeWKUH0NzdCt2Blrr5ys8VGpn0CEB0cQHVjt7k= +github.com/jmespath/go-jmespath v0.4.0/go.mod h1:T8mJZnbsbmF+m6zOOFylbeCJqk5+pHWvzYPziyZiYoo= +github.com/jmespath/go-jmespath/internal/testify v1.5.1/go.mod h1:L3OGu8Wl2/fWfCI6z80xFu9LTZmf1ZRjMHUOPmWr69U= +github.com/jmoiron/sqlx v1.2.0/go.mod h1:1FEQNm3xlJgrMD+FBdI9+xvCksHtbpVBBw5dYhBSsks= github.com/jonboulle/clockwork v0.1.0/go.mod h1:Ii8DK3G1RaLaWxj9trq07+26W01tbo22gdxWY5EU2bo= +github.com/jonboulle/clockwork v0.2.0 h1:J2SLSdy7HgElq8ekSl2Mxh6vrRNFxqbXGenYH2I02Vs= +github.com/jonboulle/clockwork v0.2.0/go.mod h1:Pkfl5aHPm1nk2H9h0bjmnJD/BcgbGXUBGnn1kMkgxc8= +github.com/josharian/txtarfs v0.0.0-20210218200122-0702f000015a/go.mod h1:izVPOvVRsHiKkeGCT6tYBNWyDVuzj9wAaBb5R9qamfw= +github.com/jpillora/backoff v1.0.0/go.mod h1:J/6gKK9jxlEcS3zixgDgUAsiuZ7yrSoa/FX5e0EB2j4= github.com/jrick/logrotate v1.0.0/go.mod h1:LNinyqDIJnpAur+b8yyulnQw/wDuN1+BYKlTRt3OuAQ= github.com/json-iterator/go v1.1.6/go.mod h1:+SdeFBvtyEkXs7REEP0seUULqWtbJapLOCVDaaPEHmU= github.com/json-iterator/go v1.1.7/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4= +github.com/json-iterator/go v1.1.8/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4= +github.com/json-iterator/go v1.1.9/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4= +github.com/json-iterator/go v1.1.10/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4= +github.com/json-iterator/go v1.1.11/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4= +github.com/json-iterator/go v1.1.12/go.mod h1:e30LSqwooZae/UwlEbR2852Gd8hjQvJoHmT4TnhNGBo= github.com/jstemmer/go-junit-report v0.0.0-20190106144839-af01ea7f8024/go.mod h1:6v2b51hI/fHJwM22ozAgKL4VKDeJcHhJFhtBdhmNjmU= +github.com/jstemmer/go-junit-report v0.9.1/go.mod h1:Brl9GWCQeLvo8nXZwPNNblvFj/XSXhF0NWZEnDohbsk= github.com/jtolds/gls v4.2.1+incompatible/go.mod h1:QJZ7F/aHp+rZTRtaJ1ow/lLfFfVYBRgL+9YlvaHOwJU= github.com/jtolds/gls v4.20.0+incompatible h1:xdiiI2gbIgH/gLH7ADydsJ1uDOEzR8yvV7C0MuV77Wo= github.com/jtolds/gls v4.20.0+incompatible/go.mod h1:QJZ7F/aHp+rZTRtaJ1ow/lLfFfVYBRgL+9YlvaHOwJU= +github.com/juju/ratelimit v1.0.1/go.mod h1:qapgC/Gy+xNh9UxzV13HGGl/6UXNN+ct+vwSgWNm/qk= github.com/julienschmidt/httprouter v1.2.0/go.mod h1:SYymIcj16QtmaHHD7aYtjjsJG7VTCxuUUipMqKk8s4w= +github.com/julienschmidt/httprouter v1.3.0/go.mod h1:JR6WtHb+2LUe8TCKY3cZOxFyyO8IZAc4RVcycCCAKdM= +github.com/julz/importas v0.1.0 h1:F78HnrsjY3cR7j0etXy5+TU1Zuy7Xt08X/1aJnH5xXY= +github.com/julz/importas v0.1.0/go.mod h1:oSFU2R4XK/P7kNBrnL/FEQlDGN1/6WoxXEjSSXO0DV0= +github.com/k0kubun/colorstring v0.0.0-20150214042306-9440f1994b88/go.mod h1:3w7q1U84EfirKl04SVQ/s7nPm1ZPhiXd34z40TNz36k= github.com/kami-zh/go-capturer v0.0.0-20171211120116-e492ea43421d/go.mod h1:P2viExyCEfeWGU259JnaQ34Inuec4R38JCyBx2edgD0= github.com/kisielk/errcheck v1.1.0/go.mod h1:EZBBE59ingxPouuu3KfxchcWSUPOHkagtvWXihfKN4Q= github.com/kisielk/errcheck v1.2.0/go.mod h1:/BMXB+zMLi60iA8Vv6Ksmxu/1UDYcXs4uQLJ+jE2L00= +github.com/kisielk/errcheck v1.5.0/go.mod h1:pFxgyoBC7bSaBwPgfKdkLd5X25qrDl4LWUI2bnpBCr8= +github.com/kisielk/errcheck v1.6.0 h1:YTDO4pNy7AUN/021p+JGHycQyYNIyMoenM1YDVK6RlY= +github.com/kisielk/errcheck v1.6.0/go.mod h1:pFxgyoBC7bSaBwPgfKdkLd5X25qrDl4LWUI2bnpBCr8= github.com/kisielk/gotool v1.0.0 h1:AV2c/EiW3KqPNT9ZKl07ehoAGi4C5/01Cfbblndcapg= github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck= github.com/kkdai/bstream v0.0.0-20161212061736-f391b8402d23/go.mod h1:J+Gs4SYgM6CZQHDETBtE9HaSEkGmuNXF86RwHhHUvq4= -github.com/klauspost/compress v1.4.0/go.mod h1:RyIbtBH6LamlWaDj8nUwkbUhJ87Yi3uG0guNDohfE1A= -github.com/klauspost/compress v1.4.1/go.mod h1:RyIbtBH6LamlWaDj8nUwkbUhJ87Yi3uG0guNDohfE1A= -github.com/klauspost/cpuid v0.0.0-20180405133222-e7e905edc00e/go.mod h1:Pj4uuM528wm8OyEC2QMXAi2YiTZ96dNQPGgoMS4s3ek= -github.com/klauspost/cpuid v1.2.0/go.mod h1:Pj4uuM528wm8OyEC2QMXAi2YiTZ96dNQPGgoMS4s3ek= -github.com/konsorten/go-windows-terminal-sequences v1.0.1 h1:mweAR1A6xJ3oS2pRaGiHgQ4OO8tzTaLawm8vnODuwDk= +github.com/klauspost/compress v1.11.7/go.mod h1:aoV0uJVorq1K+umq18yTdKaF57EivdYsUV+/s2qKfXs= +github.com/klauspost/compress v1.13.4/go.mod h1:8dP1Hq4DHOhN9w426knH3Rhby4rFm6D8eO+e+Dq5Gzg= +github.com/klauspost/compress v1.13.5/go.mod h1:/3/Vjq9QcHkK5uEr5lBEmyoZ1iFhe47etQ6QUkpK6sk= +github.com/klauspost/compress v1.13.6/go.mod h1:/3/Vjq9QcHkK5uEr5lBEmyoZ1iFhe47etQ6QUkpK6sk= +github.com/klauspost/compress v1.15.1 h1:y9FcTHGyrebwfP0ZZqFiaxTaiDnUrGkJkI+f583BL1A= +github.com/klauspost/compress v1.15.1/go.mod h1:/3/Vjq9QcHkK5uEr5lBEmyoZ1iFhe47etQ6QUkpK6sk= +github.com/klauspost/cpuid/v2 v2.0.4/go.mod h1:FInQzS24/EEf25PyTYn52gqo7WaD8xa0213Md/qVLRg= +github.com/klauspost/cpuid/v2 v2.0.9/go.mod h1:FInQzS24/EEf25PyTYn52gqo7WaD8xa0213Md/qVLRg= +github.com/klauspost/cpuid/v2 v2.0.12 h1:p9dKCg8i4gmOxtv35DvrYoWqYzQrvEVdjQ762Y0OqZE= +github.com/klauspost/cpuid/v2 v2.0.12/go.mod h1:g2LTdtYhdyuGPqyWyv7qRAmj1WBqxuObKfj5c0PQa7c= github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= +github.com/konsorten/go-windows-terminal-sequences v1.0.2/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= +github.com/konsorten/go-windows-terminal-sequences v1.0.3/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= github.com/koron/go-ssdp v0.0.0-20180514024734-4a0ed625a78b/go.mod h1:5Ky9EC2xfoUKUor0Hjgi2BJhCSXJfMOFlmyYrVKGQMk= -github.com/koron/go-ssdp v0.0.0-20191105050749-2e1c40ed0b5d h1:68u9r4wEvL3gYg2jvAOgROwZ3H+Y3hIDk4tbbmIjcYQ= github.com/koron/go-ssdp v0.0.0-20191105050749-2e1c40ed0b5d/go.mod h1:5Ky9EC2xfoUKUor0Hjgi2BJhCSXJfMOFlmyYrVKGQMk= +github.com/koron/go-ssdp v0.0.2 h1:fL3wAoyT6hXHQlORyXUW4Q23kkQpJRgEAYcZB5BR71o= +github.com/koron/go-ssdp v0.0.2/go.mod h1:XoLfkAiA2KeZsYh4DbHxD7h3nR2AZNqVQOa+LJuqPYs= +github.com/kr/fs v0.1.0/go.mod h1:FFnZGqtBN9Gxj7eW1uZ42v5BccTP0vu6NEaFoC2HwRg= github.com/kr/logfmt v0.0.0-20140226030751-b84e30acd515/go.mod h1:+0opPa2QZZtGFBFZlji/RkVcI2GknAs/DXo4wKdlNEc= github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo= github.com/kr/pretty v0.2.0/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfnI= +github.com/kr/pretty v0.2.1/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfnI= +github.com/kr/pretty v0.3.0 h1:WgNl7dwNpEZ6jJ9k1snq4pZsg7DOEN8hP9Xw0Tsjwk0= +github.com/kr/pretty v0.3.0/go.mod h1:640gp4NfQd8pI5XOwp5fnNeVWj67G7CFk/SaSQn7NBk= github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= github.com/kr/pty v1.1.3/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= -github.com/kr/pty v1.1.8/go.mod h1:O1sed60cT9XZ5uDucP5qwvh+TE3NnUj51EiZO/lmSfw= github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY= github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE= +github.com/kulti/thelper v0.5.1 h1:Uf4CUekH0OvzQTFPrWkstJvXgm6pnNEtQu3HiqEkpB0= +github.com/kulti/thelper v0.5.1/go.mod h1:vMu2Cizjy/grP+jmsvOFDx1kYP6+PD1lqg4Yu5exl2U= +github.com/kunwardeep/paralleltest v1.0.3 h1:UdKIkImEAXjR1chUWLn+PNXqWUGs//7tzMeWuP7NhmI= +github.com/kunwardeep/paralleltest v1.0.3/go.mod h1:vLydzomDFpk7yu5UX02RmP0H8QfRPOV/oFhWN85Mjb4= +github.com/kylelemons/godebug v1.1.0/go.mod h1:9/0rRGxNHcop5bhtWyNeEfOS8JIWk580+fNqagV/RAw= +github.com/kyoh86/exportloopref v0.1.8 h1:5Ry/at+eFdkX9Vsdw3qU4YkvGtzuVfzT4X7S77LoN/M= +github.com/kyoh86/exportloopref v0.1.8/go.mod h1:1tUcJeiioIs7VWe5gcOObrux3lb66+sBqGZrRkMwPgg= +github.com/ldez/gomoddirectives v0.2.2 h1:p9/sXuNFArS2RLc+UpYZSI4KQwGMEDWC/LbtF5OPFVg= +github.com/ldez/gomoddirectives v0.2.2/go.mod h1:cpgBogWITnCfRq2qGoDkKMEVSaarhdBr6g8G04uz6d0= +github.com/ldez/tagliatelle v0.3.1 h1:3BqVVlReVUZwafJUwQ+oxbx2BEX2vUG4Yu/NOfMiKiM= +github.com/ldez/tagliatelle v0.3.1/go.mod h1:8s6WJQwEYHbKZDsp/LjArytKOG8qaMrKQQ3mFukHs88= +github.com/leonklingele/grouper v1.1.0 h1:tC2y/ygPbMFSBOs3DcyaEMKnnwH7eYKzohOtRrf0SAg= +github.com/leonklingele/grouper v1.1.0/go.mod h1:uk3I3uDfi9B6PeUjsCKi6ndcf63Uy7snXgR4yDYQVDY= +github.com/letsencrypt/pkcs11key/v4 v4.0.0/go.mod h1:EFUvBDay26dErnNb70Nd0/VW3tJiIbETBPTl9ATXQag= github.com/lib/pq v1.0.0/go.mod h1:5WUZQaWbwv1U+lTReE5YruASi9Al49XbQIvNi/34Woo= -github.com/lib/pq v1.2.0/go.mod h1:5WUZQaWbwv1U+lTReE5YruASi9Al49XbQIvNi/34Woo= +github.com/lib/pq v1.8.0/go.mod h1:AlVN5x4E4T544tWzH6hKfbfQvm3HdbOxrmggDNAPY9o= +github.com/lib/pq v1.9.0/go.mod h1:AlVN5x4E4T544tWzH6hKfbfQvm3HdbOxrmggDNAPY9o= +github.com/lib/pq v1.10.4/go.mod h1:AlVN5x4E4T544tWzH6hKfbfQvm3HdbOxrmggDNAPY9o= github.com/libp2p/go-addr-util v0.0.1/go.mod h1:4ac6O7n9rIAKB1dnd+s8IbbMXkt+oBpzX4/+RACcnlQ= -github.com/libp2p/go-addr-util v0.0.2 h1:7cWK5cdA5x72jX0g8iLrQWm5TRJZ6CzGdPEhWj7plWU= github.com/libp2p/go-addr-util v0.0.2/go.mod h1:Ecd6Fb3yIuLzq4bD7VcywcVSBtefcAwnUISBM3WG15E= +github.com/libp2p/go-addr-util v0.1.0/go.mod h1:6I3ZYuFr2O/9D+SoyM0zEw0EF3YkldtTX406BpdQMqw= github.com/libp2p/go-buffer-pool v0.0.1/go.mod h1:xtyIz9PMobb13WaxR6Zo1Pd1zXJKYg0a8KiIvDp3TzQ= github.com/libp2p/go-buffer-pool v0.0.2 h1:QNK2iAFa8gjAe1SPz6mHSMuCcjs+X1wlHzeOSqcmlfs= github.com/libp2p/go-buffer-pool v0.0.2/go.mod h1:MvaB6xw5vOrDl8rYZGLFdKAuk/hRoRZd1Vi32+RXyFM= +github.com/libp2p/go-cidranger v1.1.0 h1:ewPN8EZ0dd1LSnrtuwd4709PXVcITVeuwbag38yPW7c= +github.com/libp2p/go-cidranger v1.1.0/go.mod h1:KWZTfSr+r9qEo9OkI9/SIEeAtw+NNoU0dXIXt15Okic= +github.com/libp2p/go-conn-security v0.0.1/go.mod h1:bGmu51N0KU9IEjX7kl2PQjgZa40JQWnayTvNMgD/vyk= +github.com/libp2p/go-conn-security-multistream v0.0.2/go.mod h1:nc9vud7inQ+d6SO0I/6dSWrdMnHnzZNHeyUQqrAJulE= github.com/libp2p/go-conn-security-multistream v0.1.0/go.mod h1:aw6eD7LOsHEX7+2hJkDxw1MteijaVcI+/eP2/x3J1xc= -github.com/libp2p/go-conn-security-multistream v0.2.0 h1:uNiDjS58vrvJTg9jO6bySd1rMKejieG7v45ekqHbZ1M= github.com/libp2p/go-conn-security-multistream v0.2.0/go.mod h1:hZN4MjlNetKD3Rq5Jb/P5ohUnFLNzEAR4DLSzpn2QLU= +github.com/libp2p/go-conn-security-multistream v0.2.1/go.mod h1:cR1d8gA0Hr59Fj6NhaTpFhJZrjSYuNmhpT2r25zYR70= +github.com/libp2p/go-conn-security-multistream v0.3.0 h1:9UCIKlBL1hC9u7nkMXpD1nkc/T53PKMAn3/k9ivBAVc= +github.com/libp2p/go-conn-security-multistream v0.3.0/go.mod h1:EEP47t4fw/bTelVmEzIDqSe69hO/ip52xBEhZMLWAHM= github.com/libp2p/go-eventbus v0.0.2/go.mod h1:Hr/yGlwxA/stuLnpMiu82lpNKpvRy3EaJxPu40XYOwk= github.com/libp2p/go-eventbus v0.1.0/go.mod h1:vROgu5cs5T7cv7POWlWxBaVLxfSegC5UGQf8A2eEmx4= github.com/libp2p/go-eventbus v0.2.1 h1:VanAdErQnpTioN2TowqNcOijf6YwhuODe4pPKSDpxGc= @@ -444,40 +906,48 @@ github.com/libp2p/go-eventbus v0.2.1/go.mod h1:jc2S4SoEVPP48H9Wpzm5aiGwUCBMfGhVh github.com/libp2p/go-flow-metrics v0.0.1/go.mod h1:Iv1GH0sG8DtYN3SVJ2eG221wMiNpZxBdp967ls1g+k8= github.com/libp2p/go-flow-metrics v0.0.3 h1:8tAs/hSdNvUiLgtlSy3mxwxWP4I9y/jlkPFT7epKdeM= github.com/libp2p/go-flow-metrics v0.0.3/go.mod h1:HeoSNUrOJVK1jEpDqVEiUOIXqhbnS27omG0uWU5slZs= +github.com/libp2p/go-libp2p v0.0.30/go.mod h1:XWT8FGHlhptAv1+3V/+J5mEpzyui/5bvFsNuWYs611A= github.com/libp2p/go-libp2p v0.1.0/go.mod h1:6D/2OBauqLUoqcADOJpn9WbKqvaM07tDw68qHM0BxUM= github.com/libp2p/go-libp2p v0.1.1/go.mod h1:I00BRo1UuUSdpuc8Q2mN7yDF/oTUTRAX6JWpTiK9Rp8= github.com/libp2p/go-libp2p v0.3.1/go.mod h1:e6bwxbdYH1HqWTz8faTChKGR0BjPc8p+6SyP8GTTR7Y= github.com/libp2p/go-libp2p v0.4.0/go.mod h1:9EsEIf9p2UDuwtPd0DwJsAl0qXVxgAnuDGRvHbfATfI= -github.com/libp2p/go-libp2p v0.6.0/go.mod h1:mfKWI7Soz3ABX+XEBR61lGbg+ewyMtJHVt043oWeqwg= github.com/libp2p/go-libp2p v0.6.1/go.mod h1:CTFnWXogryAHjXAKEbOf1OWY+VeAP3lDMZkfEI5sT54= github.com/libp2p/go-libp2p v0.7.0/go.mod h1:hZJf8txWeCduQRDC/WSqBGMxaTHCOYHt2xSU1ivxn0k= github.com/libp2p/go-libp2p v0.7.4/go.mod h1:oXsBlTLF1q7pxr+9w6lqzS1ILpyHsaBPniVO7zIHGMw= -github.com/libp2p/go-libp2p v0.8.3/go.mod h1:EsH1A+8yoWK+L4iKcbPYu6MPluZ+CHWI9El8cTaefiM= -github.com/libp2p/go-libp2p v0.9.6 h1:sDiuVhuLpWQOjSFmxOJEXVM9RHKIUTKgi8ArSS9nBtE= -github.com/libp2p/go-libp2p v0.9.6/go.mod h1:EA24aHpFs3BscMWvO286AiaKs3a7efQdLo+tbZ2tUSk= +github.com/libp2p/go-libp2p v0.8.1/go.mod h1:QRNH9pwdbEBpx5DTJYg+qxcVaDMAz3Ee/qDKwXujH5o= +github.com/libp2p/go-libp2p v0.14.3/go.mod h1:d12V4PdKbpL0T1/gsUNN8DfgMuRPDX8bS2QxCZlwRH0= +github.com/libp2p/go-libp2p v0.16.0/go.mod h1:ump42BsirwAWxKzsCiFnTtN1Yc+DuPu76fyMX364/O4= +github.com/libp2p/go-libp2p v0.19.0 h1:zosskMbaobL7UDCVLEe1m5CGs1TaFNFoN/M5XLiKg0U= +github.com/libp2p/go-libp2p v0.19.0/go.mod h1:Ki9jJXLO2YqrTIFxofV7Twyd3INWPT97+r8hGt7XPjI= +github.com/libp2p/go-libp2p-asn-util v0.1.0/go.mod h1:wu+AnM9Ii2KgO5jMmS1rz9dvzTdj8BXqsPR9HR0XB7I= +github.com/libp2p/go-libp2p-asn-util v0.2.0 h1:rg3+Os8jbnO5DxkC7K/Utdi+DkY3q/d1/1q+8WeNAsw= +github.com/libp2p/go-libp2p-asn-util v0.2.0/go.mod h1:WoaWxbHKBymSN41hWSq/lGKJEca7TNm58+gGJi2WsLI= +github.com/libp2p/go-libp2p-autonat v0.0.6/go.mod h1:uZneLdOkZHro35xIhpbtTzLlgYturpu4J5+0cZK3MqE= github.com/libp2p/go-libp2p-autonat v0.1.0/go.mod h1:1tLf2yXxiE/oKGtDwPYWTSYG3PtvYlJmg7NeVtPRqH8= github.com/libp2p/go-libp2p-autonat v0.1.1/go.mod h1:OXqkeGOY2xJVWKAGV2inNF5aKN/djNA3fdpCWloIudE= github.com/libp2p/go-libp2p-autonat v0.2.0/go.mod h1:DX+9teU4pEEoZUqR1PiMlqliONQdNbfzE1C718tcViI= github.com/libp2p/go-libp2p-autonat v0.2.1/go.mod h1:MWtAhV5Ko1l6QBsHQNSuM6b1sRkXrpk0/LqCr+vCVxI= github.com/libp2p/go-libp2p-autonat v0.2.2/go.mod h1:HsM62HkqZmHR2k1xgX34WuWDzk/nBwNHoeyyT4IWV6A= -github.com/libp2p/go-libp2p-autonat v0.2.3 h1:w46bKK3KTOUWDe5mDYMRjJu1uryqBp8HCNDp/TWMqKw= -github.com/libp2p/go-libp2p-autonat v0.2.3/go.mod h1:2U6bNWCNsAG9LEbwccBDQbjzQ8Krdjge1jLTE9rdoMM= +github.com/libp2p/go-libp2p-autonat v0.4.2/go.mod h1:YxaJlpr81FhdOv3W3BTconZPfhaYivRdf53g+S2wobk= +github.com/libp2p/go-libp2p-autonat v0.6.0/go.mod h1:bFC6kY8jwzNNWoqc8iGE57vsfwyJ/lP4O4DOV1e0B2o= github.com/libp2p/go-libp2p-autonat-svc v0.1.0/go.mod h1:fqi8Obl/z3R4PFVLm8xFtZ6PBL9MlV/xumymRFkKq5A= +github.com/libp2p/go-libp2p-blankhost v0.0.1/go.mod h1:Ibpbw/7cPPYwFb7PACIWdvxxv0t0XCCI10t7czjAjTc= github.com/libp2p/go-libp2p-blankhost v0.1.1/go.mod h1:pf2fvdLJPsC1FsVrNP3DUUvMzUts2dsLLBEpo1vW1ro= github.com/libp2p/go-libp2p-blankhost v0.1.3/go.mod h1:KML1//wiKR8vuuJO0y3LUd1uLv+tlkGTAr3jC0S5cLg= github.com/libp2p/go-libp2p-blankhost v0.1.4/go.mod h1:oJF0saYsAXQCSfDq254GMNmLNz6ZTHTOvtF4ZydUvwU= -github.com/libp2p/go-libp2p-blankhost v0.1.6 h1:CkPp1/zaCrCnBo0AdsQA0O1VkUYoUOtyHOnoa8gKIcE= -github.com/libp2p/go-libp2p-blankhost v0.1.6/go.mod h1:jONCAJqEP+Z8T6EQviGL4JsQcLx1LgTGtVqFNY8EMfQ= +github.com/libp2p/go-libp2p-blankhost v0.2.0/go.mod h1:eduNKXGTioTuQAUcZ5epXi9vMl+t4d8ugUBRQ4SqaNQ= +github.com/libp2p/go-libp2p-blankhost v0.3.0 h1:kTnLArltMabZlzY63pgGDA4kkUcLkBFSM98zBssn/IY= +github.com/libp2p/go-libp2p-blankhost v0.3.0/go.mod h1:urPC+7U01nCGgJ3ZsV8jdwTp6Ji9ID0dMTvq+aJ+nZU= +github.com/libp2p/go-libp2p-circuit v0.0.9/go.mod h1:uU+IBvEQzCu953/ps7bYzC/D/R0Ho2A9LfKVVCatlqU= github.com/libp2p/go-libp2p-circuit v0.1.0/go.mod h1:Ahq4cY3V9VJcHcn1SBXjr78AbFkZeIRmfunbA7pmFh8= github.com/libp2p/go-libp2p-circuit v0.1.1/go.mod h1:Ahq4cY3V9VJcHcn1SBXjr78AbFkZeIRmfunbA7pmFh8= github.com/libp2p/go-libp2p-circuit v0.1.3/go.mod h1:Xqh2TjSy8DD5iV2cCOMzdynd6h8OTBGoV1AWbWor3qM= github.com/libp2p/go-libp2p-circuit v0.1.4/go.mod h1:CY67BrEjKNDhdTk8UgBX1Y/H5c3xkAcs3gnksxY7osU= github.com/libp2p/go-libp2p-circuit v0.2.1/go.mod h1:BXPwYDN5A8z4OEY9sOfr2DUQMLQvKt/6oku45YUmjIo= -github.com/libp2p/go-libp2p-circuit v0.2.2/go.mod h1:nkG3iE01tR3FoQ2nMm06IUrCpCyJp1Eo4A1xYdpjfs4= -github.com/libp2p/go-libp2p-circuit v0.2.3 h1:3Uw1fPHWrp1tgIhBz0vSOxRUmnKL8L/NGUyEd5WfSGM= -github.com/libp2p/go-libp2p-circuit v0.2.3/go.mod h1:nkG3iE01tR3FoQ2nMm06IUrCpCyJp1Eo4A1xYdpjfs4= +github.com/libp2p/go-libp2p-circuit v0.4.0/go.mod h1:t/ktoFIUzM6uLQ+o1G6NuBl2ANhBKN9Bc8jRIk31MoA= +github.com/libp2p/go-libp2p-circuit v0.6.0 h1:rw/HlhmUB3OktS/Ygz6+2XABOmHKzZpPUuMNUMosj8w= +github.com/libp2p/go-libp2p-circuit v0.6.0/go.mod h1:kB8hY+zCpMeScyvFrKrGicRdid6vNXbunKE4rXATZ0M= github.com/libp2p/go-libp2p-connmgr v0.1.1/go.mod h1:wZxh8veAmU5qdrfJ0ZBLcU8oJe9L82ciVP/fl1VHjXk= -github.com/libp2p/go-libp2p-connmgr v0.2.3/go.mod h1:Gqjg29zI8CwXX21zRxy6gOg8VYu3zVerJRt2KyktzH4= github.com/libp2p/go-libp2p-core v0.0.1/go.mod h1:g/VxnTZ/1ygHxH3dKok7Vno1VfpvGcGip57wjTU4fco= github.com/libp2p/go-libp2p-core v0.0.2/go.mod h1:9dAcntw/n46XycV4RnlBq3BpgrmyUi9LuoTNdPrbUco= github.com/libp2p/go-libp2p-core v0.0.3/go.mod h1:j+YQMNz9WNSkNezXOsahp9kwZBKBvxLpKD316QWSJXE= @@ -497,195 +967,401 @@ github.com/libp2p/go-libp2p-core v0.5.3/go.mod h1:uN7L2D4EvPCvzSH5SrhR72UWbnSGpt github.com/libp2p/go-libp2p-core v0.5.4/go.mod h1:uN7L2D4EvPCvzSH5SrhR72UWbnSGpt5/a35Sm4upn4Y= github.com/libp2p/go-libp2p-core v0.5.5/go.mod h1:vj3awlOr9+GMZJFH9s4mpt9RHHgGqeHCopzbYKZdRjM= github.com/libp2p/go-libp2p-core v0.5.6/go.mod h1:txwbVEhHEXikXn9gfC7/UDDw7rkxuX0bJvM49Ykaswo= -github.com/libp2p/go-libp2p-core v0.5.7 h1:QK3xRwFxqd0Xd9bSZL+8yZ8ncZZbl6Zngd/+Y+A6sgQ= github.com/libp2p/go-libp2p-core v0.5.7/go.mod h1:txwbVEhHEXikXn9gfC7/UDDw7rkxuX0bJvM49Ykaswo= +github.com/libp2p/go-libp2p-core v0.6.0/go.mod h1:txwbVEhHEXikXn9gfC7/UDDw7rkxuX0bJvM49Ykaswo= +github.com/libp2p/go-libp2p-core v0.6.1/go.mod h1:FfewUH/YpvWbEB+ZY9AQRQ4TAD8sJBt/G1rVvhz5XT8= +github.com/libp2p/go-libp2p-core v0.7.0/go.mod h1:FfewUH/YpvWbEB+ZY9AQRQ4TAD8sJBt/G1rVvhz5XT8= +github.com/libp2p/go-libp2p-core v0.8.0/go.mod h1:FfewUH/YpvWbEB+ZY9AQRQ4TAD8sJBt/G1rVvhz5XT8= +github.com/libp2p/go-libp2p-core v0.8.1/go.mod h1:FfewUH/YpvWbEB+ZY9AQRQ4TAD8sJBt/G1rVvhz5XT8= +github.com/libp2p/go-libp2p-core v0.8.2/go.mod h1:FfewUH/YpvWbEB+ZY9AQRQ4TAD8sJBt/G1rVvhz5XT8= +github.com/libp2p/go-libp2p-core v0.8.5/go.mod h1:FfewUH/YpvWbEB+ZY9AQRQ4TAD8sJBt/G1rVvhz5XT8= +github.com/libp2p/go-libp2p-core v0.8.6/go.mod h1:dgHr0l0hIKfWpGpqAMbpo19pen9wJfdCGv51mTmdpmM= +github.com/libp2p/go-libp2p-core v0.9.0/go.mod h1:ESsbz31oC3C1AvMJoGx26RTuCkNhmkSRCqZ0kQtJ2/8= +github.com/libp2p/go-libp2p-core v0.10.0/go.mod h1:ECdxehoYosLYHgDDFa2N4yE8Y7aQRAMf0sX9mf2sbGg= +github.com/libp2p/go-libp2p-core v0.11.0/go.mod h1:ECdxehoYosLYHgDDFa2N4yE8Y7aQRAMf0sX9mf2sbGg= +github.com/libp2p/go-libp2p-core v0.12.0/go.mod h1:ECdxehoYosLYHgDDFa2N4yE8Y7aQRAMf0sX9mf2sbGg= +github.com/libp2p/go-libp2p-core v0.14.0/go.mod h1:tLasfcVdTXnixsLB0QYaT1syJOhsbrhG7q6pGrHtBg8= +github.com/libp2p/go-libp2p-core v0.15.1 h1:0RY+Mi/ARK9DgG1g9xVQLb8dDaaU8tCePMtGALEfBnM= +github.com/libp2p/go-libp2p-core v0.15.1/go.mod h1:agSaboYM4hzB1cWekgVReqV5M4g5M+2eNNejV+1EEhs= +github.com/libp2p/go-libp2p-crypto v0.0.1/go.mod h1:yJkNyDmO341d5wwXxDUGO0LykUVT72ImHNUqh5D/dBE= +github.com/libp2p/go-libp2p-crypto v0.0.2/go.mod h1:eETI5OUfBnvARGOHrJz2eWNyTUxEGZnBxMcbUjfIj4I= github.com/libp2p/go-libp2p-crypto v0.1.0/go.mod h1:sPUokVISZiy+nNuTTH/TY+leRSxnFj/2GLjtOTW90hI= github.com/libp2p/go-libp2p-daemon v0.2.2/go.mod h1:kyrpsLB2JeNYR2rvXSVWyY0iZuRIMhqzWR3im9BV6NQ= +github.com/libp2p/go-libp2p-discovery v0.0.5/go.mod h1:YtF20GUxjgoKZ4zmXj8j3Nb2TUSBHFlOCetzYdbZL5I= github.com/libp2p/go-libp2p-discovery v0.1.0/go.mod h1:4F/x+aldVHjHDHuX85x1zWoFTGElt8HnoDzwkFZm29g= github.com/libp2p/go-libp2p-discovery v0.2.0/go.mod h1:s4VGaxYMbw4+4+tsoQTqh7wfxg97AEdo4GYBt6BadWg= github.com/libp2p/go-libp2p-discovery v0.3.0/go.mod h1:o03drFnz9BVAZdzC/QUQ+NeQOu38Fu7LJGEOK2gQltw= -github.com/libp2p/go-libp2p-discovery v0.4.0 h1:dK78UhopBk48mlHtRCzbdLm3q/81g77FahEBTjcqQT8= -github.com/libp2p/go-libp2p-discovery v0.4.0/go.mod h1:bZ0aJSrFc/eX2llP0ryhb1kpgkPyTo23SJ5b7UQCMh4= +github.com/libp2p/go-libp2p-discovery v0.5.0/go.mod h1:+srtPIU9gDaBNu//UHvcdliKBIcr4SfDcm0/PfPJLug= +github.com/libp2p/go-libp2p-discovery v0.6.0/go.mod h1:/u1voHt0tKIe5oIA1RHBKQLVCWPna2dXmPNHc2zR9S8= +github.com/libp2p/go-libp2p-host v0.0.1/go.mod h1:qWd+H1yuU0m5CwzAkvbSjqKairayEHdR5MMl7Cwa7Go= +github.com/libp2p/go-libp2p-host v0.0.3/go.mod h1:Y/qPyA6C8j2coYyos1dfRm0I8+nvd4TGrDGt4tA7JR8= +github.com/libp2p/go-libp2p-interface-connmgr v0.0.1/go.mod h1:GarlRLH0LdeWcLnYM/SaBykKFl9U5JFnbBGruAk/D5k= +github.com/libp2p/go-libp2p-interface-connmgr v0.0.4/go.mod h1:GarlRLH0LdeWcLnYM/SaBykKFl9U5JFnbBGruAk/D5k= +github.com/libp2p/go-libp2p-interface-connmgr v0.0.5/go.mod h1:GarlRLH0LdeWcLnYM/SaBykKFl9U5JFnbBGruAk/D5k= +github.com/libp2p/go-libp2p-interface-pnet v0.0.1/go.mod h1:el9jHpQAXK5dnTpKA4yfCNBZXvrzdOU75zz+C6ryp3k= github.com/libp2p/go-libp2p-kad-dht v0.2.1/go.mod h1:k7ONOlup7HKzQ68dE6lSnp07cdxdkmnRa+6B4Fh9/w0= github.com/libp2p/go-libp2p-kbucket v0.2.1/go.mod h1:/Rtu8tqbJ4WQ2KTCOMJhggMukOLNLNPY1EtEWWLxUvc= +github.com/libp2p/go-libp2p-loggables v0.0.1/go.mod h1:lDipDlBNYbpyqyPX/KcoO+eq0sJYEVR2JgOexcivchg= github.com/libp2p/go-libp2p-loggables v0.1.0 h1:h3w8QFfCt2UJl/0/NW4K829HX/0S4KD31PQ7m8UXXO8= github.com/libp2p/go-libp2p-loggables v0.1.0/go.mod h1:EyumB2Y6PrYjr55Q3/tiJ/o3xoDasoRYM7nOzEpoa90= +github.com/libp2p/go-libp2p-metrics v0.0.1/go.mod h1:jQJ95SXXA/K1VZi13h52WZMa9ja78zjyy5rspMsC/08= +github.com/libp2p/go-libp2p-mplex v0.1.1/go.mod h1:KUQWpGkCzfV7UIpi8SKsAVxyBgz1c9R5EvxgnwLsb/I= github.com/libp2p/go-libp2p-mplex v0.2.0/go.mod h1:Ejl9IyjvXJ0T9iqUTE1jpYATQ9NM3g+OtR+EMMODbKo= github.com/libp2p/go-libp2p-mplex v0.2.1/go.mod h1:SC99Rxs8Vuzrf/6WhmH41kNn13TiYdAWNYHrwImKLnE= github.com/libp2p/go-libp2p-mplex v0.2.2/go.mod h1:74S9eum0tVQdAfFiKxAyKzNdSuLqw5oadDq7+L/FELo= -github.com/libp2p/go-libp2p-mplex v0.2.3 h1:2zijwaJvpdesST2MXpI5w9wWFRgYtMcpRX7rrw0jmOo= github.com/libp2p/go-libp2p-mplex v0.2.3/go.mod h1:CK3p2+9qH9x+7ER/gWWDYJ3QW5ZxWDkm+dVvjfuG3ek= +github.com/libp2p/go-libp2p-mplex v0.4.0/go.mod h1:yCyWJE2sc6TBTnFpjvLuEJgTSw/u+MamvzILKdX7asw= +github.com/libp2p/go-libp2p-mplex v0.4.1/go.mod h1:cmy+3GfqfM1PceHTLL7zQzAAYaryDu6iPSC+CIb094g= +github.com/libp2p/go-libp2p-mplex v0.5.0/go.mod h1:eLImPJLkj3iG5t5lq68w3Vm5NAQ5BcKwrrb2VmOYb3M= +github.com/libp2p/go-libp2p-mplex v0.7.0 h1:ONTTvHIUaFCwyPO4FRkpe4OFQJq1bDkWQLbhWiD1A44= +github.com/libp2p/go-libp2p-mplex v0.7.0/go.mod h1:SeeXUXh7ZkfxnmsepnFgMPEhfEyACujuTM9k1TkErpc= github.com/libp2p/go-libp2p-nat v0.0.4/go.mod h1:N9Js/zVtAXqaeT99cXgTV9e75KpnWCvVOiGzlcHmBbY= github.com/libp2p/go-libp2p-nat v0.0.5/go.mod h1:1qubaE5bTZMJE+E/uu2URroMbzdubFz1ChgiN79yKPE= -github.com/libp2p/go-libp2p-nat v0.0.6 h1:wMWis3kYynCbHoyKLPBEMu4YRLltbm8Mk08HGSfvTkU= github.com/libp2p/go-libp2p-nat v0.0.6/go.mod h1:iV59LVhB3IkFvS6S6sauVTSOrNEANnINbI/fkaLimiw= +github.com/libp2p/go-libp2p-nat v0.1.0 h1:vigUi2MEN+fwghe5ijpScxtbbDz+L/6y8XwlzYOJgSY= +github.com/libp2p/go-libp2p-nat v0.1.0/go.mod h1:DQzAG+QbDYjN1/C3B6vXucLtz3u9rEonLVPtZVzQqks= +github.com/libp2p/go-libp2p-net v0.0.1/go.mod h1:Yt3zgmlsHOgUWSXmt5V/Jpz9upuJBE8EgNU9DrCcR8c= +github.com/libp2p/go-libp2p-net v0.0.2/go.mod h1:Yt3zgmlsHOgUWSXmt5V/Jpz9upuJBE8EgNU9DrCcR8c= +github.com/libp2p/go-libp2p-netutil v0.0.1/go.mod h1:GdusFvujWZI9Vt0X5BKqwWWmZFxecf9Gt03cKxm2f/Q= github.com/libp2p/go-libp2p-netutil v0.1.0 h1:zscYDNVEcGxyUpMd0JReUZTrpMfia8PmLKcKF72EAMQ= github.com/libp2p/go-libp2p-netutil v0.1.0/go.mod h1:3Qv/aDqtMLTUyQeundkKsA+YCThNdbQD54k3TqjpbFU= +github.com/libp2p/go-libp2p-noise v0.2.0/go.mod h1:IEbYhBBzGyvdLBoxxULL/SGbJARhUeqlO8lVSREYu2Q= +github.com/libp2p/go-libp2p-noise v0.3.0/go.mod h1:JNjHbociDJKHD64KTkzGnzqJ0FEV5gHJa6AB00kbCNQ= +github.com/libp2p/go-libp2p-noise v0.4.0 h1:khcMsGhHNdGqKE5LDLrnHwZvdGVMsrnD4GTkTWkwmLU= +github.com/libp2p/go-libp2p-noise v0.4.0/go.mod h1:BzzY5pyzCYSyJbQy9oD8z5oP2idsafjt4/X42h9DjZU= +github.com/libp2p/go-libp2p-peer v0.0.1/go.mod h1:nXQvOBbwVqoP+T5Y5nCjeH4sP9IX/J0AMzcDUVruVoo= +github.com/libp2p/go-libp2p-peer v0.1.1/go.mod h1:jkF12jGB4Gk/IOo+yomm+7oLWxF278F7UnrYUQ1Q8es= github.com/libp2p/go-libp2p-peer v0.2.0/go.mod h1:RCffaCvUyW2CJmG2gAWVqwePwW7JMgxjsHm7+J5kjWY= +github.com/libp2p/go-libp2p-peerstore v0.0.1/go.mod h1:RabLyPVJLuNQ+GFyoEkfi8H4Ti6k/HtZJ7YKgtSq+20= +github.com/libp2p/go-libp2p-peerstore v0.0.6/go.mod h1:RabLyPVJLuNQ+GFyoEkfi8H4Ti6k/HtZJ7YKgtSq+20= github.com/libp2p/go-libp2p-peerstore v0.1.0/go.mod h1:2CeHkQsr8svp4fZ+Oi9ykN1HBb6u0MOvdJ7YIsmcwtY= github.com/libp2p/go-libp2p-peerstore v0.1.3/go.mod h1:BJ9sHlm59/80oSkpWgr1MyY1ciXAXV397W6h1GH/uKI= github.com/libp2p/go-libp2p-peerstore v0.2.0/go.mod h1:N2l3eVIeAitSg3Pi2ipSrJYnqhVnMNQZo9nkSCuAbnQ= github.com/libp2p/go-libp2p-peerstore v0.2.1/go.mod h1:NQxhNjWxf1d4w6PihR8btWIRjwRLBr4TYKfNgrUkOPA= github.com/libp2p/go-libp2p-peerstore v0.2.2/go.mod h1:NQxhNjWxf1d4w6PihR8btWIRjwRLBr4TYKfNgrUkOPA= -github.com/libp2p/go-libp2p-peerstore v0.2.3/go.mod h1:K8ljLdFn590GMttg/luh4caB/3g0vKuY01psze0upRw= -github.com/libp2p/go-libp2p-peerstore v0.2.4/go.mod h1:ss/TWTgHZTMpsU/oKVVPQCGuDHItOpf2W8RxAi50P2s= -github.com/libp2p/go-libp2p-peerstore v0.2.6 h1:2ACefBX23iMdJU9Ke+dcXt3w86MIryes9v7In4+Qq3U= github.com/libp2p/go-libp2p-peerstore v0.2.6/go.mod h1:ss/TWTgHZTMpsU/oKVVPQCGuDHItOpf2W8RxAi50P2s= +github.com/libp2p/go-libp2p-peerstore v0.2.7/go.mod h1:ss/TWTgHZTMpsU/oKVVPQCGuDHItOpf2W8RxAi50P2s= +github.com/libp2p/go-libp2p-peerstore v0.4.0/go.mod h1:rDJUFyzEWPpXpEwywkcTYYzDHlwza8riYMaUzaN6hX0= +github.com/libp2p/go-libp2p-peerstore v0.6.0 h1:HJminhQSGISBIRb93N6WK3t6Fa8OOTnHd/VBjL4mY5A= +github.com/libp2p/go-libp2p-peerstore v0.6.0/go.mod h1:DGEmKdXrcYpK9Jha3sS7MhqYdInxJy84bIPtSu65bKc= github.com/libp2p/go-libp2p-pnet v0.2.0 h1:J6htxttBipJujEjz1y0a5+eYoiPcFHhSYHH6na5f0/k= github.com/libp2p/go-libp2p-pnet v0.2.0/go.mod h1:Qqvq6JH/oMZGwqs3N1Fqhv8NVhrdYcO0BW4wssv21LA= +github.com/libp2p/go-libp2p-protocol v0.0.1/go.mod h1:Af9n4PiruirSDjHycM1QuiMi/1VZNHYcK8cLgFJLZ4s= +github.com/libp2p/go-libp2p-protocol v0.1.0/go.mod h1:KQPHpAabB57XQxGrXCNvbL6UEXfQqUgC/1adR2Xtflk= github.com/libp2p/go-libp2p-pubsub v0.1.1/go.mod h1:ZwlKzRSe1eGvSIdU5bD7+8RZN/Uzw0t1Bp9R1znpR/Q= -github.com/libp2p/go-libp2p-pubsub v0.3.1/go.mod h1:TxPOBuo1FPdsTjFnv+FGZbNbWYsp74Culx+4ViQpato= github.com/libp2p/go-libp2p-quic-transport v0.1.1/go.mod h1:wqG/jzhF3Pu2NrhJEvE+IE0NTHNXslOPn9JQzyCAxzU= -github.com/libp2p/go-libp2p-quic-transport v0.3.7 h1:F9hxonkJvMipNim8swrvRk2uL9s8pqzHz0M6eMf8L58= -github.com/libp2p/go-libp2p-quic-transport v0.3.7/go.mod h1:Kr4aDtnfHHNeENn5J+sZIVc+t8HpQn9W6BOxhVGHbgI= +github.com/libp2p/go-libp2p-quic-transport v0.10.0/go.mod h1:RfJbZ8IqXIhxBRm5hqUEJqjiiY8xmEuq3HUDS993MkA= +github.com/libp2p/go-libp2p-quic-transport v0.13.0/go.mod h1:39/ZWJ1TW/jx1iFkKzzUg00W6tDJh73FC0xYudjr7Hc= +github.com/libp2p/go-libp2p-quic-transport v0.15.0/go.mod h1:wv4uGwjcqe8Mhjj7N/Ic0aKjA+/10UnMlSzLO0yRpYQ= +github.com/libp2p/go-libp2p-quic-transport v0.16.0/go.mod h1:1BXjVMzr+w7EkPfiHkKnwsWjPjtfaNT0q8RS3tGDvEQ= +github.com/libp2p/go-libp2p-quic-transport v0.17.0 h1:yFh4Gf5MlToAYLuw/dRvuzYd1EnE2pX3Lq1N6KDiWRQ= +github.com/libp2p/go-libp2p-quic-transport v0.17.0/go.mod h1:x4pw61P3/GRCcSLypcQJE/Q2+E9f4X+5aRcZLXf20LM= +github.com/libp2p/go-libp2p-record v0.0.1/go.mod h1:grzqg263Rug/sRex85QrDOLntdFAymLDLm7lxMgU79Q= github.com/libp2p/go-libp2p-record v0.1.0/go.mod h1:ujNc8iuE5dlKWVy6wuL6dd58t0n7xI4hAIl8pE6wu5Q= -github.com/libp2p/go-libp2p-record v0.1.1 h1:ZJK2bHXYUBqObHX+rHLSNrM3M8fmJUlUHrodDPPATmY= github.com/libp2p/go-libp2p-record v0.1.1/go.mod h1:VRgKajOyMVgP/F0L5g3kH7SVskp17vFi2xheb5uMJtg= +github.com/libp2p/go-libp2p-record v0.1.3 h1:R27hoScIhQf/A8XJZ8lYpnqh9LatJ5YbHs28kCIfql0= +github.com/libp2p/go-libp2p-record v0.1.3/go.mod h1:yNUff/adKIfPnYQXgp6FQmNu3gLJ6EMg7+/vv2+9pY4= +github.com/libp2p/go-libp2p-resource-manager v0.2.1/go.mod h1:K+eCkiapf+ey/LADO4TaMpMTP9/Qde/uLlrnRqV4PLQ= +github.com/libp2p/go-libp2p-resource-manager v0.3.0 h1:2+cYxUNi33tcydsVLt6K5Fv2E3OTiVeafltecAj15E0= +github.com/libp2p/go-libp2p-resource-manager v0.3.0/go.mod h1:K+eCkiapf+ey/LADO4TaMpMTP9/Qde/uLlrnRqV4PLQ= +github.com/libp2p/go-libp2p-routing v0.0.1/go.mod h1:N51q3yTr4Zdr7V8Jt2JIktVU+3xBBylx1MZeVA6t1Ys= github.com/libp2p/go-libp2p-routing v0.1.0/go.mod h1:zfLhI1RI8RLEzmEaaPwzonRvXeeSHddONWkcTcB54nE= +github.com/libp2p/go-libp2p-secio v0.0.3/go.mod h1:hS7HQ00MgLhRO/Wyu1bTX6ctJKhVpm+j2/S2A5UqYb0= github.com/libp2p/go-libp2p-secio v0.1.0/go.mod h1:tMJo2w7h3+wN4pgU2LSYeiKPrfqBgkOsdiKK77hE7c8= github.com/libp2p/go-libp2p-secio v0.2.0/go.mod h1:2JdZepB8J5V9mBp79BmwsaPQhRPNN2NrnB2lKQcdy6g= github.com/libp2p/go-libp2p-secio v0.2.1/go.mod h1:cWtZpILJqkqrSkiYcDBh5lA3wbT2Q+hz3rJQq3iftD8= -github.com/libp2p/go-libp2p-secio v0.2.2 h1:rLLPvShPQAcY6eNurKNZq3eZjPWfU9kXF2eI9jIYdrg= github.com/libp2p/go-libp2p-secio v0.2.2/go.mod h1:wP3bS+m5AUnFA+OFO7Er03uO1mncHG0uVwGrwvjYlNY= +github.com/libp2p/go-libp2p-swarm v0.0.6/go.mod h1:s5GZvzg9xXe8sbeESuFpjt8CJPTCa8mhEusweJqyFy8= github.com/libp2p/go-libp2p-swarm v0.1.0/go.mod h1:wQVsCdjsuZoc730CgOvh5ox6K8evllckjebkdiY5ta4= github.com/libp2p/go-libp2p-swarm v0.2.1/go.mod h1:x07b4zkMFo2EvgPV2bMTlNmdQc8i+74Jjio7xGvsTgU= github.com/libp2p/go-libp2p-swarm v0.2.2/go.mod h1:fvmtQ0T1nErXym1/aa1uJEyN7JzaTNyBcHImCxRpPKU= github.com/libp2p/go-libp2p-swarm v0.2.3/go.mod h1:P2VO/EpxRyDxtChXz/VPVXyTnszHvokHKRhfkEgFKNM= -github.com/libp2p/go-libp2p-swarm v0.2.4/go.mod h1:/xIpHFPPh3wmSthtxdGbkHZ0OET1h/GGZes8Wku/M5Y= -github.com/libp2p/go-libp2p-swarm v0.2.6 h1:UhMXIa+yCOALQyceENEIStMlbTCzOM6aWo6vw8QW17Q= -github.com/libp2p/go-libp2p-swarm v0.2.6/go.mod h1:F9hrkZjO7dDbcEiYii/fAB1QdpLuU6h1pa4P5VNsEgc= +github.com/libp2p/go-libp2p-swarm v0.2.8/go.mod h1:JQKMGSth4SMqonruY0a8yjlPVIkb0mdNSwckW7OYziM= +github.com/libp2p/go-libp2p-swarm v0.3.0/go.mod h1:hdv95GWCTmzkgeJpP+GK/9D9puJegb7H57B5hWQR5Kk= +github.com/libp2p/go-libp2p-swarm v0.5.0/go.mod h1:sU9i6BoHE0Ve5SKz3y9WfKrh8dUat6JknzUehFx8xW4= +github.com/libp2p/go-libp2p-swarm v0.8.0/go.mod h1:sOMp6dPuqco0r0GHTzfVheVBh6UEL0L1lXUZ5ot2Fvc= +github.com/libp2p/go-libp2p-swarm v0.10.0/go.mod h1:71ceMcV6Rg/0rIQ97rsZWMzto1l9LnNquef+efcRbmA= +github.com/libp2p/go-libp2p-swarm v0.10.2 h1:UaXf+CTq6Ns1N2V1EgqJ9Q3xaRsiN7ImVlDMpirMAWw= +github.com/libp2p/go-libp2p-swarm v0.10.2/go.mod h1:Pdkq0QU5a+qu+oyqIV3bknMsnzk9lnNyKvB9acJ5aZs= +github.com/libp2p/go-libp2p-testing v0.0.1/go.mod h1:gvchhf3FQOtBdr+eFUABet5a4MBLK8jM3V4Zghvmi+E= github.com/libp2p/go-libp2p-testing v0.0.2/go.mod h1:gvchhf3FQOtBdr+eFUABet5a4MBLK8jM3V4Zghvmi+E= github.com/libp2p/go-libp2p-testing v0.0.3/go.mod h1:gvchhf3FQOtBdr+eFUABet5a4MBLK8jM3V4Zghvmi+E= github.com/libp2p/go-libp2p-testing v0.0.4/go.mod h1:gvchhf3FQOtBdr+eFUABet5a4MBLK8jM3V4Zghvmi+E= github.com/libp2p/go-libp2p-testing v0.1.0/go.mod h1:xaZWMJrPUM5GlDBxCeGUi7kI4eqnjVyavGroI2nxEM0= -github.com/libp2p/go-libp2p-testing v0.1.1 h1:U03z3HnGI7Ni8Xx6ONVZvUFOAzWYmolWf5W5jAOPNmU= github.com/libp2p/go-libp2p-testing v0.1.1/go.mod h1:xaZWMJrPUM5GlDBxCeGUi7kI4eqnjVyavGroI2nxEM0= -github.com/libp2p/go-libp2p-tls v0.1.3 h1:twKMhMu44jQO+HgQK9X8NHO5HkeJu2QbhLzLJpa8oNM= +github.com/libp2p/go-libp2p-testing v0.1.2-0.20200422005655-8775583591d8/go.mod h1:Qy8sAncLKpwXtS2dSnDOP8ktexIAHKu+J+pnZOFZLTc= +github.com/libp2p/go-libp2p-testing v0.3.0/go.mod h1:efZkql4UZ7OVsEfaxNHZPzIehtsBXMrXnCfJIgDti5g= +github.com/libp2p/go-libp2p-testing v0.4.0/go.mod h1:Q+PFXYoiYFN5CAEG2w3gLPEzotlKsNSbKQ/lImlOWF0= +github.com/libp2p/go-libp2p-testing v0.4.2/go.mod h1:Q+PFXYoiYFN5CAEG2w3gLPEzotlKsNSbKQ/lImlOWF0= +github.com/libp2p/go-libp2p-testing v0.5.0/go.mod h1:QBk8fqIL1XNcno/l3/hhaIEn4aLRijpYOR+zVjjlh+A= +github.com/libp2p/go-libp2p-testing v0.7.0/go.mod h1:OLbdn9DbgdMwv00v+tlp1l3oe2Cl+FAjoWIA2pa0X6E= +github.com/libp2p/go-libp2p-testing v0.9.0/go.mod h1:Td7kbdkWqYTJYQGTwzlgXwaqldraIanyjuRiAbK/XQU= +github.com/libp2p/go-libp2p-testing v0.9.2 h1:dCpODRtRaDZKF8HXT9qqqgON+OMEB423Knrgeod8j84= +github.com/libp2p/go-libp2p-testing v0.9.2/go.mod h1:Td7kbdkWqYTJYQGTwzlgXwaqldraIanyjuRiAbK/XQU= github.com/libp2p/go-libp2p-tls v0.1.3/go.mod h1:wZfuewxOndz5RTnCAxFliGjvYSDA40sKitV4c50uI1M= +github.com/libp2p/go-libp2p-tls v0.3.0/go.mod h1:fwF5X6PWGxm6IDRwF3V8AVCCj/hOd5oFlg+wo2FxJDY= +github.com/libp2p/go-libp2p-tls v0.3.1/go.mod h1:fwF5X6PWGxm6IDRwF3V8AVCCj/hOd5oFlg+wo2FxJDY= +github.com/libp2p/go-libp2p-tls v0.4.1 h1:1ByJUbyoMXvYXDoW6lLsMxqMViQNXmt+CfQqlnCpY+M= +github.com/libp2p/go-libp2p-tls v0.4.1/go.mod h1:EKCixHEysLNDlLUoKxv+3f/Lp90O2EXNjTr0UQDnrIw= +github.com/libp2p/go-libp2p-transport v0.0.1/go.mod h1:UzbUs9X+PHOSw7S3ZmeOxfnwaQY5vGDzZmKPod3N3tk= +github.com/libp2p/go-libp2p-transport v0.0.5/go.mod h1:StoY3sx6IqsP6XKoabsPnHCwqKXWUMWU7Rfcsubee/A= +github.com/libp2p/go-libp2p-transport-upgrader v0.0.4/go.mod h1:RGq+tupk+oj7PzL2kn/m1w6YXxcIAYJYeI90h6BGgUc= github.com/libp2p/go-libp2p-transport-upgrader v0.1.1/go.mod h1:IEtA6or8JUbsV07qPW4r01GnTenLW4oi3lOPbUMGJJA= github.com/libp2p/go-libp2p-transport-upgrader v0.2.0/go.mod h1:mQcrHj4asu6ArfSoMuyojOdjx73Q47cYD7s5+gZOlns= -github.com/libp2p/go-libp2p-transport-upgrader v0.3.0 h1:q3ULhsknEQ34eVDhv4YwKS8iet69ffs9+Fir6a7weN4= github.com/libp2p/go-libp2p-transport-upgrader v0.3.0/go.mod h1:i+SKzbRnvXdVbU3D1dwydnTmKRPXiAR/fyvi1dXuL4o= +github.com/libp2p/go-libp2p-transport-upgrader v0.4.2/go.mod h1:NR8ne1VwfreD5VIWIU62Agt/J18ekORFU/j1i2y8zvk= +github.com/libp2p/go-libp2p-transport-upgrader v0.4.3/go.mod h1:bpkldbOWXMrXhpZbSV1mQxTrefOg2Fi+k1ClDSA4ppw= +github.com/libp2p/go-libp2p-transport-upgrader v0.5.0/go.mod h1:Rc+XODlB3yce7dvFV4q/RmyJGsFcCZRkeZMu/Zdg0mo= +github.com/libp2p/go-libp2p-transport-upgrader v0.7.0/go.mod h1:GIR2aTRp1J5yjVlkUoFqMkdobfob6RnAwYg/RZPhrzg= +github.com/libp2p/go-libp2p-transport-upgrader v0.7.1 h1:MSMe+tUfxpC9GArTz7a4G5zQKQgGh00Vio87d3j3xIg= +github.com/libp2p/go-libp2p-transport-upgrader v0.7.1/go.mod h1:GIR2aTRp1J5yjVlkUoFqMkdobfob6RnAwYg/RZPhrzg= +github.com/libp2p/go-libp2p-yamux v0.1.2/go.mod h1:xUoV/RmYkg6BW/qGxA9XJyg+HzXFYkeXbnhjmnYzKp8= +github.com/libp2p/go-libp2p-yamux v0.1.3/go.mod h1:VGSQVrqkh6y4nm0189qqxMtvyBft44MOYYPpYKXiVt4= github.com/libp2p/go-libp2p-yamux v0.2.0/go.mod h1:Db2gU+XfLpm6E4rG5uGCFX6uXA8MEXOxFcRoXUODaK8= github.com/libp2p/go-libp2p-yamux v0.2.1/go.mod h1:1FBXiHDk1VyRM1C0aez2bCfHQ4vMZKkAQzZbkSQt5fI= github.com/libp2p/go-libp2p-yamux v0.2.2/go.mod h1:lIohaR0pT6mOt0AZ0L2dFze9hds9Req3OfS+B+dv4qw= github.com/libp2p/go-libp2p-yamux v0.2.5/go.mod h1:Zpgj6arbyQrmZ3wxSZxfBmbdnWtbZ48OpsfmQVTErwA= github.com/libp2p/go-libp2p-yamux v0.2.7/go.mod h1:X28ENrBMU/nm4I3Nx4sZ4dgjZ6VhLEn0XhIoZ5viCwU= -github.com/libp2p/go-libp2p-yamux v0.2.8 h1:0s3ELSLu2O7hWKfX1YjzudBKCP0kZ+m9e2+0veXzkn4= github.com/libp2p/go-libp2p-yamux v0.2.8/go.mod h1:/t6tDqeuZf0INZMTgd0WxIRbtK2EzI2h7HbFm9eAKI4= +github.com/libp2p/go-libp2p-yamux v0.4.0/go.mod h1:+DWDjtFMzoAwYLVkNZftoucn7PelNoy5nm3tZ3/Zw30= +github.com/libp2p/go-libp2p-yamux v0.5.0/go.mod h1:AyR8k5EzyM2QN9Bbdg6X1SkVVuqLwTGf0L4DFq9g6po= +github.com/libp2p/go-libp2p-yamux v0.5.4/go.mod h1:tfrXbyaTqqSU654GTvK3ocnSZL3BuHoeTSqhcel1wsE= +github.com/libp2p/go-libp2p-yamux v0.6.0/go.mod h1:MRhd6mAYnFRnSISp4M8i0ClV/j+mWHo2mYLifWGw33k= +github.com/libp2p/go-libp2p-yamux v0.8.0/go.mod h1:yTkPgN2ib8FHyU1ZcVD7aelzyAqXXwEPbyx+aSKm9h8= +github.com/libp2p/go-libp2p-yamux v0.8.1/go.mod h1:rUozF8Jah2dL9LLGyBaBeTQeARdwhefMCTQVQt6QobE= +github.com/libp2p/go-libp2p-yamux v0.9.1 h1:oplewiRix8s45SOrI30rCPZG5mM087YZp+VYhXAh4+c= +github.com/libp2p/go-libp2p-yamux v0.9.1/go.mod h1:wRc6wvyxQINFcKe7daL4BeQ02Iyp+wxyC8WCNfngBrA= +github.com/libp2p/go-maddr-filter v0.0.1/go.mod h1:6eT12kSQMA9x2pvFQa+xesMKUBlj9VImZbj3B9FBH/Q= github.com/libp2p/go-maddr-filter v0.0.4/go.mod h1:6eT12kSQMA9x2pvFQa+xesMKUBlj9VImZbj3B9FBH/Q= -github.com/libp2p/go-maddr-filter v0.0.5 h1:CW3AgbMO6vUvT4kf87y4N+0P8KUl2aqLYhrGyDUbLSg= github.com/libp2p/go-maddr-filter v0.0.5/go.mod h1:Jk+36PMfIqCJhAnaASRH83bdAvfDRp/w6ENFaC9bG+M= +github.com/libp2p/go-maddr-filter v0.1.0/go.mod h1:VzZhTXkMucEGGEOSKddrwGiOv0tUhgnKqNEmIAz/bPU= github.com/libp2p/go-mplex v0.0.3/go.mod h1:pK5yMLmOoBR1pNCqDlA2GQrdAVTMkqFalaTWe7l4Yd0= +github.com/libp2p/go-mplex v0.0.4/go.mod h1:pK5yMLmOoBR1pNCqDlA2GQrdAVTMkqFalaTWe7l4Yd0= github.com/libp2p/go-mplex v0.1.0/go.mod h1:SXgmdki2kwCUlCCbfGLEgHjC4pFqhTp0ZoV6aiKgxDU= github.com/libp2p/go-mplex v0.1.1/go.mod h1:Xgz2RDCi3co0LeZfgjm4OgUF15+sVR8SRcu3SFXI1lk= -github.com/libp2p/go-mplex v0.1.2 h1:qOg1s+WdGLlpkrczDqmhYzyk3vCfsQ8+RxRTQjOZWwI= github.com/libp2p/go-mplex v0.1.2/go.mod h1:Xgz2RDCi3co0LeZfgjm4OgUF15+sVR8SRcu3SFXI1lk= +github.com/libp2p/go-mplex v0.2.0/go.mod h1:0Oy/A9PQlwBytDRp4wSkFnzHYDKcpLot35JQ6msjvYQ= +github.com/libp2p/go-mplex v0.3.0/go.mod h1:0Oy/A9PQlwBytDRp4wSkFnzHYDKcpLot35JQ6msjvYQ= +github.com/libp2p/go-mplex v0.4.0/go.mod h1:y26Lx+wNVtMYMaPu300Cbot5LkEZ4tJaNYeHeT9dh6E= +github.com/libp2p/go-mplex v0.7.0 h1:BDhFZdlk5tbr0oyFq/xv/NPGfjbnrsDam1EvutpBDbY= +github.com/libp2p/go-mplex v0.7.0/go.mod h1:rW8ThnRcYWft/Jb2jeORBmPd6xuG3dGxWN/W168L9EU= github.com/libp2p/go-msgio v0.0.2/go.mod h1:63lBBgOTDKQL6EWazRMCwXsEeEeK9O2Cd+0+6OOuipQ= github.com/libp2p/go-msgio v0.0.3/go.mod h1:63lBBgOTDKQL6EWazRMCwXsEeEeK9O2Cd+0+6OOuipQ= -github.com/libp2p/go-msgio v0.0.4 h1:agEFehY3zWJFUHK6SEMR7UYmk2z6kC3oeCM7ybLhguA= github.com/libp2p/go-msgio v0.0.4/go.mod h1:63lBBgOTDKQL6EWazRMCwXsEeEeK9O2Cd+0+6OOuipQ= +github.com/libp2p/go-msgio v0.0.6/go.mod h1:4ecVB6d9f4BDSL5fqvPiC4A3KivjWn+Venn/1ALLMWA= +github.com/libp2p/go-msgio v0.1.0/go.mod h1:eNlv2vy9V2X/kNldcZ+SShFE++o2Yjxwx6RAYsmgJnE= +github.com/libp2p/go-msgio v0.2.0 h1:W6shmB+FeynDrUVl2dgFQvzfBZcXiyqY4VmpQLu9FqU= +github.com/libp2p/go-msgio v0.2.0/go.mod h1:dBVM1gW3Jk9XqHkU4eKdGvVHdLa51hoGfll6jMJMSlY= github.com/libp2p/go-nat v0.0.3/go.mod h1:88nUEt0k0JD45Bk93NIwDqjlhiOwOoV36GchpcVc1yI= github.com/libp2p/go-nat v0.0.4/go.mod h1:Nmw50VAvKuk38jUBcmNh6p9lUJLoODbJRvYAa/+KSDo= -github.com/libp2p/go-nat v0.0.5 h1:qxnwkco8RLKqVh1NmjQ+tJ8p8khNLFxuElYG/TwqW4Q= github.com/libp2p/go-nat v0.0.5/go.mod h1:B7NxsVNPZmRLvMOwiEO1scOSyjA56zxYAGv1yQgRkEU= -github.com/libp2p/go-netroute v0.1.2 h1:UHhB35chwgvcRI392znJA3RCBtZ3MpE3ahNCN5MR4Xg= +github.com/libp2p/go-nat v0.1.0 h1:MfVsH6DLcpa04Xr+p8hmVRG4juse0s3J8HyNWYHffXg= +github.com/libp2p/go-nat v0.1.0/go.mod h1:X7teVkwRHNInVNWQiO/tAiAVRwSr5zoRz4YSTC3uRBM= github.com/libp2p/go-netroute v0.1.2/go.mod h1:jZLDV+1PE8y5XxBySEBgbuVAXbhtuHSdmLPL2n9MKbk= +github.com/libp2p/go-netroute v0.1.3/go.mod h1:jZLDV+1PE8y5XxBySEBgbuVAXbhtuHSdmLPL2n9MKbk= +github.com/libp2p/go-netroute v0.1.5/go.mod h1:V1SR3AaECRkEQCoFFzYwVYWvYIEtlxx89+O3qcpCl4A= +github.com/libp2p/go-netroute v0.1.6/go.mod h1:AqhkMh0VuWmfgtxKPp3Oc1LdU5QSWS7wl0QLhSZqXxQ= +github.com/libp2p/go-netroute v0.2.0 h1:0FpsbsvuSnAhXFnCY0VLFbJOzaK0VnP0r1QT/o4nWRE= +github.com/libp2p/go-netroute v0.2.0/go.mod h1:Vio7LTzZ+6hoT4CMZi5/6CpY3Snzh2vgZhWgxMNwlQI= github.com/libp2p/go-openssl v0.0.2/go.mod h1:v8Zw2ijCSWBQi8Pq5GAixw6DbFfa9u6VIYDXnvOXkc0= github.com/libp2p/go-openssl v0.0.3/go.mod h1:unDrJpgy3oFr+rqXsarWifmJuNnJR4chtO1HmaZjggc= github.com/libp2p/go-openssl v0.0.4/go.mod h1:unDrJpgy3oFr+rqXsarWifmJuNnJR4chtO1HmaZjggc= -github.com/libp2p/go-openssl v0.0.5 h1:pQkejVhF0xp08D4CQUcw8t+BFJeXowja6RVcb5p++EA= github.com/libp2p/go-openssl v0.0.5/go.mod h1:unDrJpgy3oFr+rqXsarWifmJuNnJR4chtO1HmaZjggc= -github.com/libp2p/go-reuseport v0.0.1 h1:7PhkfH73VXfPJYKQ6JwS5I/eVcoyYi9IMNGc6FWpFLw= +github.com/libp2p/go-openssl v0.0.7 h1:eCAzdLejcNVBzP/iZM9vqHnQm+XyCEbSSIheIPRGNsw= +github.com/libp2p/go-openssl v0.0.7/go.mod h1:unDrJpgy3oFr+rqXsarWifmJuNnJR4chtO1HmaZjggc= github.com/libp2p/go-reuseport v0.0.1/go.mod h1:jn6RmB1ufnQwl0Q1f+YxAj8isJgDCQzaaxIFYDhcYEA= +github.com/libp2p/go-reuseport v0.0.2/go.mod h1:SPD+5RwGC7rcnzngoYC86GjPzjSywuQyMVAheVBD9nQ= +github.com/libp2p/go-reuseport v0.1.0 h1:0ooKOx2iwyIkf339WCZ2HN3ujTDbkK0PjC7JVoP1AiM= +github.com/libp2p/go-reuseport v0.1.0/go.mod h1:bQVn9hmfcTaoo0c9v5pBhOarsU1eNOBZdaAd2hzXRKU= github.com/libp2p/go-reuseport-transport v0.0.2/go.mod h1:YkbSDrvjUVDL6b8XqriyA20obEtsW9BLkuOUyQAOCbs= -github.com/libp2p/go-reuseport-transport v0.0.3 h1:zzOeXnTooCkRvoH+bSXEfXhn76+LAiwoneM0gnXjF2M= github.com/libp2p/go-reuseport-transport v0.0.3/go.mod h1:Spv+MPft1exxARzP2Sruj2Wb5JSyHNncjf1Oi2dEbzM= +github.com/libp2p/go-reuseport-transport v0.0.4/go.mod h1:trPa7r/7TJK/d+0hdBLOCGvpQQVOU74OXbNCIMkufGw= +github.com/libp2p/go-reuseport-transport v0.1.0 h1:C3PHeHjmnz8m6f0uydObj02tMEoi7CyD1zuN7xQT8gc= +github.com/libp2p/go-reuseport-transport v0.1.0/go.mod h1:vev0C0uMkzriDY59yFHD9v+ujJvYmDQVLowvAjEOmfw= github.com/libp2p/go-sockaddr v0.0.2/go.mod h1:syPvOmNs24S3dFVGJA1/mrqdeijPxLV2Le3BRLKd68k= -github.com/libp2p/go-sockaddr v0.1.0 h1:Y4s3/jNoryVRKEBrkJ576F17CPOaMIzUeCsg7dlTDj0= github.com/libp2p/go-sockaddr v0.1.0/go.mod h1:syPvOmNs24S3dFVGJA1/mrqdeijPxLV2Le3BRLKd68k= +github.com/libp2p/go-sockaddr v0.1.1/go.mod h1:syPvOmNs24S3dFVGJA1/mrqdeijPxLV2Le3BRLKd68k= github.com/libp2p/go-stream-muxer v0.0.1/go.mod h1:bAo8x7YkSpadMTbtTaxGVHWUQsR/l5MEaHbKaliuT14= +github.com/libp2p/go-stream-muxer v0.1.0/go.mod h1:8JAVsjeRBCWwPoZeH0W1imLOcriqXJyFvB0mR4A04sQ= +github.com/libp2p/go-stream-muxer-multistream v0.1.1/go.mod h1:zmGdfkQ1AzOECIAcccoL8L//laqawOsO03zX8Sa+eGw= github.com/libp2p/go-stream-muxer-multistream v0.2.0/go.mod h1:j9eyPol/LLRqT+GPLSxvimPhNph4sfYfMoDPd7HkzIc= -github.com/libp2p/go-stream-muxer-multistream v0.3.0 h1:TqnSHPJEIqDEO7h1wZZ0p3DXdvDSiLHQidKKUGZtiOY= github.com/libp2p/go-stream-muxer-multistream v0.3.0/go.mod h1:yDh8abSIzmZtqtOt64gFJUXEryejzNb0lisTt+fAMJA= +github.com/libp2p/go-stream-muxer-multistream v0.4.0 h1:HsM/9OdtqnIzjVXcxTXjmqKrj3gJ8kacaOJwJS1ipaY= +github.com/libp2p/go-stream-muxer-multistream v0.4.0/go.mod h1:nb+dGViZleRP4XcyHuZSVrJCBl55nRBOMmiSL/dyziw= +github.com/libp2p/go-tcp-transport v0.0.4/go.mod h1:+E8HvC8ezEVOxIo3V5vCK9l1y/19K427vCzQ+xHKH/o= github.com/libp2p/go-tcp-transport v0.1.0/go.mod h1:oJ8I5VXryj493DEJ7OsBieu8fcg2nHGctwtInJVpipc= github.com/libp2p/go-tcp-transport v0.1.1/go.mod h1:3HzGvLbx6etZjnFlERyakbaYPdfjg2pWP97dFZworkY= -github.com/libp2p/go-tcp-transport v0.2.0 h1:YoThc549fzmNJIh7XjHVtMIFaEDRtIrtWciG5LyYAPo= github.com/libp2p/go-tcp-transport v0.2.0/go.mod h1:vX2U0CnWimU4h0SGSEsg++AzvBcroCGYw28kh94oLe0= +github.com/libp2p/go-tcp-transport v0.2.3/go.mod h1:9dvr03yqrPyYGIEN6Dy5UvdJZjyPFvl1S/igQ5QD1SU= +github.com/libp2p/go-tcp-transport v0.4.0/go.mod h1:0y52Rwrn4076xdJYu/51/qJIdxz+EWDAOG2S45sV3VI= +github.com/libp2p/go-tcp-transport v0.5.0/go.mod h1:UPPL0DIjQqiWRwVAb+CEQlaAG0rp/mCqJfIhFcLHc4Y= +github.com/libp2p/go-tcp-transport v0.5.1 h1:edOOs688VLZAozWC7Kj5/6HHXKNwi9M6wgRmmLa8M6Q= +github.com/libp2p/go-tcp-transport v0.5.1/go.mod h1:UPPL0DIjQqiWRwVAb+CEQlaAG0rp/mCqJfIhFcLHc4Y= +github.com/libp2p/go-testutil v0.0.1/go.mod h1:iAcJc/DKJQanJ5ws2V+u5ywdL2n12X1WbbEG+Jjy69I= github.com/libp2p/go-testutil v0.1.0/go.mod h1:81b2n5HypcVyrCg/MJx4Wgfp/VHojytjVe/gLzZ2Ehc= +github.com/libp2p/go-ws-transport v0.0.5/go.mod h1:Qbl4BxPfXXhhd/o0wcrgoaItHqA9tnZjoFZnxykuaXU= github.com/libp2p/go-ws-transport v0.1.0/go.mod h1:rjw1MG1LU9YDC6gzmwObkPd/Sqwhw7yT74kj3raBFuo= github.com/libp2p/go-ws-transport v0.1.2/go.mod h1:dsh2Ld8F+XNmzpkaAijmg5Is+e9l6/1tK/6VFOdN69Y= github.com/libp2p/go-ws-transport v0.2.0/go.mod h1:9BHJz/4Q5A9ludYWKoGCFC5gUElzlHoKzu0yY9p/klM= github.com/libp2p/go-ws-transport v0.3.0/go.mod h1:bpgTJmRZAvVHrgHybCVyqoBmyLQ1fiZuEaBYusP5zsk= -github.com/libp2p/go-ws-transport v0.3.1 h1:ZX5rWB8nhRRJVaPO6tmkGI/Xx8XNboYX20PW5hXIscw= -github.com/libp2p/go-ws-transport v0.3.1/go.mod h1:bpgTJmRZAvVHrgHybCVyqoBmyLQ1fiZuEaBYusP5zsk= +github.com/libp2p/go-ws-transport v0.4.0/go.mod h1:EcIEKqf/7GDjth6ksuS/6p7R49V4CBY6/E7R/iyhYUA= +github.com/libp2p/go-ws-transport v0.5.0/go.mod h1:I2juo1dNTbl8BKSBYo98XY85kU2xds1iamArLvl8kNg= +github.com/libp2p/go-ws-transport v0.6.0 h1:326XBL6Q+5CQ2KtjXz32+eGu02W/Kz2+Fm4SpXdr0q4= +github.com/libp2p/go-ws-transport v0.6.0/go.mod h1:dXqtI9e2JV9FtF1NOtWVZSKXh5zXvnuwPXfj8GPBbYU= +github.com/libp2p/go-yamux v1.2.1/go.mod h1:FGTiPvoV/3DVdgWpX+tM0OW3tsM+W5bSE3gZwqQTcow= github.com/libp2p/go-yamux v1.2.2/go.mod h1:FGTiPvoV/3DVdgWpX+tM0OW3tsM+W5bSE3gZwqQTcow= github.com/libp2p/go-yamux v1.2.3/go.mod h1:FGTiPvoV/3DVdgWpX+tM0OW3tsM+W5bSE3gZwqQTcow= github.com/libp2p/go-yamux v1.3.0/go.mod h1:FGTiPvoV/3DVdgWpX+tM0OW3tsM+W5bSE3gZwqQTcow= github.com/libp2p/go-yamux v1.3.3/go.mod h1:FGTiPvoV/3DVdgWpX+tM0OW3tsM+W5bSE3gZwqQTcow= github.com/libp2p/go-yamux v1.3.5/go.mod h1:FGTiPvoV/3DVdgWpX+tM0OW3tsM+W5bSE3gZwqQTcow= -github.com/libp2p/go-yamux v1.3.7 h1:v40A1eSPJDIZwz2AvrV3cxpTZEGDP11QJbukmEhYyQI= github.com/libp2p/go-yamux v1.3.7/go.mod h1:fr7aVgmdNGJK+N1g+b6DW6VxzbRCjCOejR/hkmpooHE= +github.com/libp2p/go-yamux v1.4.0/go.mod h1:fr7aVgmdNGJK+N1g+b6DW6VxzbRCjCOejR/hkmpooHE= +github.com/libp2p/go-yamux v1.4.1 h1:P1Fe9vF4th5JOxxgQvfbOHkrGqIZniTLf+ddhZp8YTI= +github.com/libp2p/go-yamux v1.4.1/go.mod h1:fr7aVgmdNGJK+N1g+b6DW6VxzbRCjCOejR/hkmpooHE= +github.com/libp2p/go-yamux/v2 v2.2.0/go.mod h1:3So6P6TV6r75R9jiBpiIKgU/66lOarCZjqROGxzPpPQ= +github.com/libp2p/go-yamux/v2 v2.3.0/go.mod h1:iTU+lOIn/2h0AgKcL49clNTwfEw+WSfDYrXe05EyKIs= +github.com/libp2p/go-yamux/v3 v3.0.1/go.mod h1:s2LsDhHbh+RfCsQoICSYt58U2f8ijtPANFD8BmE74Bo= +github.com/libp2p/go-yamux/v3 v3.0.2/go.mod h1:s2LsDhHbh+RfCsQoICSYt58U2f8ijtPANFD8BmE74Bo= +github.com/libp2p/go-yamux/v3 v3.1.1 h1:X0qSVodCZciOu/f4KTp9V+O0LAqcqP2tdaUGB0+0lng= +github.com/libp2p/go-yamux/v3 v3.1.1/go.mod h1:jeLEQgLXqE2YqX1ilAClIfCMDY+0uXQUKmmb/qp0gT4= +github.com/libp2p/zeroconf/v2 v2.1.1/go.mod h1:fuJqLnUwZTshS3U/bMRJ3+ow/v9oid1n0DmyYyNO1Xs= +github.com/lightstep/lightstep-tracer-common/golang/gogo v0.0.0-20190605223551-bc2310a04743/go.mod h1:qklhhLq1aX+mtWk9cPHPzaBjWImj5ULL6C7HFJtXQMM= +github.com/lightstep/lightstep-tracer-go v0.18.1/go.mod h1:jlF1pusYV4pidLvZ+XD0UBX0ZE6WURAspgAczcDHrL4= github.com/logrusorgru/aurora v0.0.0-20181002194514-a7b3b318ed4e/go.mod h1:7rIyQOR62GCctdiQpZ/zOJlFyk6y+94wXzv6RNZgaR4= github.com/lucas-clemente/quic-go v0.11.2/go.mod h1:PpMmPfPKO9nKJ/psF49ESTAGQSdfXxlg1otPbEB2nOw= -github.com/lucas-clemente/quic-go v0.15.7 h1:Pu7To5/G9JoP1mwlrcIvfV8ByPBlCzif3MCl8+1W83I= -github.com/lucas-clemente/quic-go v0.15.7/go.mod h1:Myi1OyS0FOjL3not4BxT7KN29bRkcMUV5JVVFLKtDp8= +github.com/lucas-clemente/quic-go v0.19.3/go.mod h1:ADXpNbTQjq1hIzCpB+y/k5iz4n4z4IwqoLb94Kh5Hu8= +github.com/lucas-clemente/quic-go v0.23.0/go.mod h1:paZuzjXCE5mj6sikVLMvqXk8lJV2AsqtJ6bDhjEfxx0= +github.com/lucas-clemente/quic-go v0.24.0/go.mod h1:paZuzjXCE5mj6sikVLMvqXk8lJV2AsqtJ6bDhjEfxx0= +github.com/lucas-clemente/quic-go v0.25.0/go.mod h1:YtzP8bxRVCBlO77yRanE264+fY/T2U9ZlW1AaHOsMOg= +github.com/lucas-clemente/quic-go v0.27.0 h1:v6WY87q9zD4dKASbG8hy/LpzAVNzEQzw8sEIeloJsc4= +github.com/lucas-clemente/quic-go v0.27.0/go.mod h1:AzgQoPda7N+3IqMMMkywBKggIFo2KT6pfnlrQ2QieeI= +github.com/lufia/plan9stats v0.0.0-20211012122336-39d0f177ccd0/go.mod h1:zJYVVT2jmtg6P3p1VtQj7WsuWi/y4VnjVBn7F8KPB3I= github.com/lunixbochs/vtclean v1.0.0/go.mod h1:pHhQNgMf3btfWnGBVipUOjRYhoOsdGqdm/+2c2E2WMI= +github.com/lyft/protoc-gen-star v0.5.3/go.mod h1:V0xaHgaf5oCCqmcxYcWiDfTiKsZsRc87/1qhoTACD8w= +github.com/lyft/protoc-gen-validate v0.0.13/go.mod h1:XbGvPuh87YZc5TdIa2/I4pLk0QoUACkjt2znoq26NVQ= github.com/magiconair/properties v1.8.0/go.mod h1:PppfXfuXeibc/6YijjN8zIbojt8czPbwD3XqdrwzmxQ= -github.com/magiconair/properties v1.8.1 h1:ZC2Vc7/ZFkGmsVC9KvOjumD+G5lXy2RtTKyzRKO2BQ4= -github.com/magiconair/properties v1.8.1/go.mod h1:PppfXfuXeibc/6YijjN8zIbojt8czPbwD3XqdrwzmxQ= +github.com/magiconair/properties v1.8.5 h1:b6kJs+EmPFMYGkow9GiUyCyOvIwYetYJ3fSaWak/Gls= +github.com/magiconair/properties v1.8.5/go.mod h1:y3VJvCyxH9uVvJTWEGAELF3aiYNyPKd5NZ3oSwXrF60= github.com/mailru/easyjson v0.0.0-20180823135443-60711f1a8329/go.mod h1:C1wdFJiN94OJF2b5HbByQZoLdCWB1Yqtg26g4irojpc= github.com/mailru/easyjson v0.0.0-20190312143242-1de009706dbe/go.mod h1:C1wdFJiN94OJF2b5HbByQZoLdCWB1Yqtg26g4irojpc= github.com/maratori/testpackage v1.0.1 h1:QtJ5ZjqapShm0w5DosRjg0PRlSdAdlx+W6cCKoALdbQ= github.com/maratori/testpackage v1.0.1/go.mod h1:ddKdw+XG0Phzhx8BFDTKgpWP4i7MpApTE5fXSKAqwDU= -github.com/marten-seemann/qpack v0.1.0/go.mod h1:LFt1NU/Ptjip0C2CPkhimBz5CGE3WGDAUWqna+CNTrI= +github.com/marten-seemann/qpack v0.2.1/go.mod h1:F7Gl5L1jIgN1D11ucXefiuJS9UMVP2opoCp2jDKb7wc= github.com/marten-seemann/qtls v0.2.3/go.mod h1:xzjG7avBwGGbdZ8dTGxlBnLArsVKLvwmjgmPuiQEcYk= -github.com/marten-seemann/qtls v0.9.1 h1:O0YKQxNVPaiFgMng0suWEOY2Sb4LT2sRn9Qimq3Z1IQ= -github.com/marten-seemann/qtls v0.9.1/go.mod h1:T1MmAdDPyISzxlK6kjRr0pcZFBVd1OZbBb/j3cvzHhk= -github.com/matoous/godox v0.0.0-20190911065817-5d6d842e92eb h1:RHba4YImhrUVQDHUCe2BNSOz4tVy2yGyXhvYDvxGgeE= -github.com/matoous/godox v0.0.0-20190911065817-5d6d842e92eb/go.mod h1:1BELzlh859Sh1c6+90blK8lbYy0kwQf1bYlBhBysy1s= +github.com/marten-seemann/qtls v0.10.0/go.mod h1:UvMd1oaYDACI99/oZUYLzMCkBXQVT0aGm99sJhbT8hs= +github.com/marten-seemann/qtls-go1-15 v0.1.1/go.mod h1:GyFwywLKkRt+6mfU99csTEY1joMZz5vmB1WNZH3P81I= +github.com/marten-seemann/qtls-go1-15 v0.1.4/go.mod h1:GyFwywLKkRt+6mfU99csTEY1joMZz5vmB1WNZH3P81I= +github.com/marten-seemann/qtls-go1-16 v0.1.4/go.mod h1:gNpI2Ol+lRS3WwSOtIUUtRwZEQMXjYK+dQSBFbethAk= +github.com/marten-seemann/qtls-go1-16 v0.1.5 h1:o9JrYPPco/Nukd/HpOHMHZoBDXQqoNtUCmny98/1uqQ= +github.com/marten-seemann/qtls-go1-16 v0.1.5/go.mod h1:gNpI2Ol+lRS3WwSOtIUUtRwZEQMXjYK+dQSBFbethAk= +github.com/marten-seemann/qtls-go1-17 v0.1.0/go.mod h1:fz4HIxByo+LlWcreM4CZOYNuz3taBQ8rN2X6FqvaWo8= +github.com/marten-seemann/qtls-go1-17 v0.1.1 h1:DQjHPq+aOzUeh9/lixAGunn6rIOQyWChPSI4+hgW7jc= +github.com/marten-seemann/qtls-go1-17 v0.1.1/go.mod h1:C2ekUKcDdz9SDWxec1N/MvcXBpaX9l3Nx67XaR84L5s= +github.com/marten-seemann/qtls-go1-18 v0.1.0-beta.1/go.mod h1:PUhIQk19LoFt2174H4+an8TYvWOGjb/hHwphBeaDHwI= +github.com/marten-seemann/qtls-go1-18 v0.1.1 h1:qp7p7XXUFL7fpBvSS1sWD+uSqPvzNQK43DH+/qEkj0Y= +github.com/marten-seemann/qtls-go1-18 v0.1.1/go.mod h1:mJttiymBAByA49mhlNZZGrH5u1uXYZJ+RW28Py7f4m4= +github.com/marten-seemann/tcp v0.0.0-20210406111302-dfbc87cc63fd h1:br0buuQ854V8u83wA0rVZ8ttrq5CpaPZdvrK0LP2lOk= +github.com/marten-seemann/tcp v0.0.0-20210406111302-dfbc87cc63fd/go.mod h1:QuCEs1Nt24+FYQEqAAncTDPJIuGs+LxK1MCiFL25pMU= +github.com/matoous/godox v0.0.0-20210227103229-6504466cf951 h1:pWxk9e//NbPwfxat7RXkts09K+dEBJWakUWwICVqYbA= +github.com/matoous/godox v0.0.0-20210227103229-6504466cf951/go.mod h1:1BELzlh859Sh1c6+90blK8lbYy0kwQf1bYlBhBysy1s= +github.com/matryer/is v1.4.0 h1:sosSmIWwkYITGrxZ25ULNDeKiMNzFSr4V/eqBQP0PeE= +github.com/matryer/is v1.4.0/go.mod h1:8I/i5uYgLzgsgEloJE1U6xx5HkBQpAZvepWuujKwMRU= github.com/mattn/go-colorable v0.0.9/go.mod h1:9vuHe8Xs5qXnSaW/c/ABM9alt+Vo+STaOChaDxuIBZU= github.com/mattn/go-colorable v0.1.1/go.mod h1:FuOcm+DKB9mbwrcAfNl7/TZVBZ6rcnceauSikq3lYCQ= github.com/mattn/go-colorable v0.1.2/go.mod h1:U0ppj6V5qS13XJ6of8GYAs25YV2eR4EVcfRqFIhoBtE= -github.com/mattn/go-colorable v0.1.4 h1:snbPLB8fVfU9iwbbo30TPtbLRzwWu6aJS6Xh4eaaviA= github.com/mattn/go-colorable v0.1.4/go.mod h1:U0ppj6V5qS13XJ6of8GYAs25YV2eR4EVcfRqFIhoBtE= +github.com/mattn/go-colorable v0.1.6/go.mod h1:u6P/XSegPjTcexA+o6vUJrdnUu04hMope9wVRipJSqc= +github.com/mattn/go-colorable v0.1.8/go.mod h1:u6P/XSegPjTcexA+o6vUJrdnUu04hMope9wVRipJSqc= +github.com/mattn/go-colorable v0.1.9/go.mod h1:u6P/XSegPjTcexA+o6vUJrdnUu04hMope9wVRipJSqc= +github.com/mattn/go-colorable v0.1.12 h1:jF+Du6AlPIjs2BiUiQlKOX0rt3SujHxPnksPKZbaA40= +github.com/mattn/go-colorable v0.1.12/go.mod h1:u5H1YNBxpqRaxsYJYSkiCWKzEfiAb1Gb520KVy5xxl4= github.com/mattn/go-isatty v0.0.3/go.mod h1:M+lRXTBqGeGNdLjl/ufCoiOlB5xdOkqRJdNxMWT7Zi4= github.com/mattn/go-isatty v0.0.4/go.mod h1:M+lRXTBqGeGNdLjl/ufCoiOlB5xdOkqRJdNxMWT7Zi4= github.com/mattn/go-isatty v0.0.5/go.mod h1:Iq45c/XA43vh69/j3iqttzPXn0bhXyGjM0Hdxcsrc5s= -github.com/mattn/go-isatty v0.0.8 h1:HLtExJ+uU2HOZ+wI0Tt5DtUDrx8yhUqDcp7fYERX4CE= github.com/mattn/go-isatty v0.0.8/go.mod h1:Iq45c/XA43vh69/j3iqttzPXn0bhXyGjM0Hdxcsrc5s= +github.com/mattn/go-isatty v0.0.10/go.mod h1:qgIWMr58cqv1PHHyhnkY9lrL7etaEgOFcMEpPG5Rm84= +github.com/mattn/go-isatty v0.0.11/go.mod h1:PhnuNfih5lzO57/f3n+odYbM4JtupLOxQOAqxQCu2WE= +github.com/mattn/go-isatty v0.0.12/go.mod h1:cbi8OIDigv2wuxKPP5vlRcQ1OAZbq2CE4Kysco4FUpU= +github.com/mattn/go-isatty v0.0.13/go.mod h1:cbi8OIDigv2wuxKPP5vlRcQ1OAZbq2CE4Kysco4FUpU= +github.com/mattn/go-isatty v0.0.14 h1:yVuAays6BHfxijgZPzw+3Zlu5yQgKGP2/hcQbHb7S9Y= +github.com/mattn/go-isatty v0.0.14/go.mod h1:7GGIvUiUoEMVVmxf/4nioHXj79iQHKdU27kJ6hsGG94= +github.com/mattn/go-runewidth v0.0.2/go.mod h1:LwmH8dsx7+W8Uxz3IHJYH5QSwggIsqBzpuz5H//U1FU= +github.com/mattn/go-runewidth v0.0.4/go.mod h1:LwmH8dsx7+W8Uxz3IHJYH5QSwggIsqBzpuz5H//U1FU= +github.com/mattn/go-runewidth v0.0.6/go.mod h1:H031xJmbD/WCDINGzjvQ9THkh0rPKHF+m2gUSrubnMI= +github.com/mattn/go-runewidth v0.0.9 h1:Lm995f3rfxdpd6TSmuVCHVb/QhupuXlYr8sCI/QdE+0= +github.com/mattn/go-runewidth v0.0.9/go.mod h1:H031xJmbD/WCDINGzjvQ9THkh0rPKHF+m2gUSrubnMI= github.com/mattn/go-sqlite3 v1.9.0/go.mod h1:FPy6KqzDD04eiIsT53CuJW3U88zkxoIYsOqkbpncsNc= -github.com/mattn/goveralls v0.0.2/go.mod h1:8d1ZMHsd7fW6IRPKQh46F2WRpyib5/X4FOpevwGNQEw= +github.com/matttproud/golang_protobuf_extensions v1.0.1 h1:4hp9jkHxhMHkqkrB3Ix0jegS5sx/RkqARlsWZ6pIwiU= github.com/matttproud/golang_protobuf_extensions v1.0.1/go.mod h1:D8He9yQNgCq6Z5Ld7szi9bcBfOoFv/3dc6xSMkL2PC0= +github.com/mbilski/exhaustivestruct v1.2.0 h1:wCBmUnSYufAHO6J4AVWY6ff+oxWxsVFrwgOdMUQePUo= +github.com/mbilski/exhaustivestruct v1.2.0/go.mod h1:OeTBVxQWoEmB2J2JCHmXWPJ0aksxSUOUy+nvtVEfzXc= +github.com/mgechev/dots v0.0.0-20210922191527-e955255bf517/go.mod h1:KQ7+USdGKfpPjXk4Ga+5XxQM4Lm4e3gAogrreFAYpOg= +github.com/mgechev/revive v1.1.4 h1:sZOjY6GU35Kr9jKa/wsKSHgrFz8eASIB5i3tqWZMp0A= +github.com/mgechev/revive v1.1.4/go.mod h1:ZZq2bmyssGh8MSPz3VVziqRNIMYTJXzP8MUKG90vZ9A= github.com/mgutz/ansi v0.0.0-20170206155736-9520e82c474b/go.mod h1:01TrycV0kFyexm33Z7vhZRXopbI8J3TDReVlkTgMUxE= github.com/microcosm-cc/bluemonday v1.0.1/go.mod h1:hsXNsILzKxV+sX77C5b8FSuKF00vh2OMYv+xgHpAMF4= +github.com/miekg/dns v1.0.14/go.mod h1:W1PPwlIAgtquWBMBEV9nkV9Cazfe8ScdGz/Lj7v3Nrg= github.com/miekg/dns v1.1.12/go.mod h1:W1PPwlIAgtquWBMBEV9nkV9Cazfe8ScdGz/Lj7v3Nrg= +github.com/miekg/dns v1.1.26/go.mod h1:bPDLeHnStXmXAq1m/Ch/hvfNHr14JKNPMBo3VZKjuso= github.com/miekg/dns v1.1.28/go.mod h1:KNUDUusw/aVsxyTYZM1oqvCicbwhgbNgztCETuNZ7xM= +github.com/miekg/dns v1.1.35/go.mod h1:KNUDUusw/aVsxyTYZM1oqvCicbwhgbNgztCETuNZ7xM= +github.com/miekg/dns v1.1.41/go.mod h1:p6aan82bvRIyn+zDIv9xYNUpwa73JcSh9BKwknJysuI= +github.com/miekg/dns v1.1.43/go.mod h1:+evo5L0630/F6ca/Z9+GAqzhjGyn8/c+TBaOyfEl0V4= +github.com/miekg/dns v1.1.48 h1:Ucfr7IIVyMBz4lRE8qmGUuZ4Wt3/ZGu9hmcMT3Uu4tQ= +github.com/miekg/dns v1.1.48/go.mod h1:e3IlAVfNqAllflbibAZEWOXOQ+Ynzk/dDozDxY7XnME= +github.com/miekg/pkcs11 v1.0.2/go.mod h1:XsNlhZGX73bx86s2hdc/FuaLm2CPZJemRLMA+WTFxgs= +github.com/miekg/pkcs11 v1.0.3/go.mod h1:XsNlhZGX73bx86s2hdc/FuaLm2CPZJemRLMA+WTFxgs= +github.com/mikioh/tcp v0.0.0-20190314235350-803a9b46060c h1:bzE/A84HN25pxAuk9Eej1Kz9OUelF97nAc82bDquQI8= +github.com/mikioh/tcp v0.0.0-20190314235350-803a9b46060c/go.mod h1:0SQS9kMwD2VsyFEB++InYyBJroV/FRmBgcydeSUcJms= +github.com/mikioh/tcpinfo v0.0.0-20190314235526-30a79bb1804b h1:z78hV3sbSMAUoyUMM0I83AUIT6Hu17AWfgjzIbtrYFc= +github.com/mikioh/tcpinfo v0.0.0-20190314235526-30a79bb1804b/go.mod h1:lxPUiZwKoFL8DUUmalo2yJJUCxbPKtm8OKfqr2/FTNU= +github.com/mikioh/tcpopt v0.0.0-20190314235656-172688c1accc h1:PTfri+PuQmWDqERdnNMiD9ZejrlswWrCpBEZgWOiTrc= +github.com/mikioh/tcpopt v0.0.0-20190314235656-172688c1accc/go.mod h1:cGKTAVKx4SxOuR/czcZ/E2RSJ3sfHs8FpHhQ5CWMf9s= github.com/minio/blake2b-simd v0.0.0-20160723061019-3f5f724cb5b1 h1:lYpkrQH5ajf0OXOcUbGjvZxxijuBwbbmlSxLiuofa+g= github.com/minio/blake2b-simd v0.0.0-20160723061019-3f5f724cb5b1/go.mod h1:pD8RvIylQ358TN4wwqatJ8rNavkEINozVn9DtGI3dfQ= github.com/minio/sha256-simd v0.0.0-20190131020904-2d45a736cd16/go.mod h1:2FMWW+8GMoPweT6+pI63m9YE3Lmw4J71hV56Chs1E/U= github.com/minio/sha256-simd v0.0.0-20190328051042-05b4dd3047e5/go.mod h1:2FMWW+8GMoPweT6+pI63m9YE3Lmw4J71hV56Chs1E/U= github.com/minio/sha256-simd v0.1.0/go.mod h1:2FMWW+8GMoPweT6+pI63m9YE3Lmw4J71hV56Chs1E/U= github.com/minio/sha256-simd v0.1.1-0.20190913151208-6de447530771/go.mod h1:B5e1o+1/KgNmWrSQK08Y6Z1Vb5pwIktudl0J58iy0KM= -github.com/minio/sha256-simd v0.1.1 h1:5QHSlgo3nt5yKOJrC7W8w7X+NFl8cMPZm96iu8kKUJU= github.com/minio/sha256-simd v0.1.1/go.mod h1:B5e1o+1/KgNmWrSQK08Y6Z1Vb5pwIktudl0J58iy0KM= +github.com/minio/sha256-simd v1.0.0 h1:v1ta+49hkWZyvaKwrQB8elexRqm6Y0aMLjCNsrYxo6g= +github.com/minio/sha256-simd v1.0.0/go.mod h1:OuYzVNI5vcoYIAmbIvHPl3N3jUzVedXbKy5RFepssQM= +github.com/mitchellh/cli v1.0.0/go.mod h1:hNIlj7HEI86fIcpObd7a0FcrxTWetlwJDGcceTlRvqc= +github.com/mitchellh/cli v1.1.0/go.mod h1:xcISNoH86gajksDmfB23e/pu+B+GeFRMYmoHXxx3xhI= +github.com/mitchellh/copystructure v1.0.0/go.mod h1:SNtv71yrdKgLRyLFxmLdkAbkKEFWgYaq1OVrnRcwhnw= +github.com/mitchellh/go-homedir v1.0.0/go.mod h1:SfyaCUpYCn1Vlf4IUYiD9fPX4A5wJrkLzIz1N1q0pr0= github.com/mitchellh/go-homedir v1.1.0 h1:lukF9ziXFxDFPkA1vsr5zpc1XuPDn/wFntq5mG+4E0Y= github.com/mitchellh/go-homedir v1.1.0/go.mod h1:SfyaCUpYCn1Vlf4IUYiD9fPX4A5wJrkLzIz1N1q0pr0= -github.com/mitchellh/go-ps v0.0.0-20190716172923-621e5597135b/go.mod h1:r1VsdOzOPt1ZSrGZWFoNhsAedKnEd6r9Np1+5blZCWk= -github.com/mitchellh/mapstructure v1.1.2 h1:fmNYVwqnSfB9mZU6OS2O6GsXM+wcskZDuKQzvN1EDeE= +github.com/mitchellh/go-ps v1.0.0/go.mod h1:J4lOc8z8yJs6vUwklHw2XEIiT4z4C40KtWVN3nvg8Pg= +github.com/mitchellh/go-testing-interface v1.0.0/go.mod h1:kRemZodwjscx+RGhAo8eIhFbs2+BFgRtFPeD/KE+zxI= +github.com/mitchellh/gox v0.4.0/go.mod h1:Sd9lOJ0+aimLBi73mGofS1ycjY8lL3uZM3JPS42BGNg= +github.com/mitchellh/iochan v1.0.0/go.mod h1:JwYml1nuB7xOzsp52dPpHFffvOCDupsG0QubkSMEySY= +github.com/mitchellh/mapstructure v0.0.0-20160808181253-ca63d7c062ee/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh9fWfEaFds41c1Y= github.com/mitchellh/mapstructure v1.1.2/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh9fWfEaFds41c1Y= +github.com/mitchellh/mapstructure v1.4.2/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo= +github.com/mitchellh/mapstructure v1.4.3 h1:OVowDSCllw/YjdLkam3/sm7wEtOy59d8ndGgCcyj8cs= +github.com/mitchellh/mapstructure v1.4.3/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo= +github.com/mitchellh/reflectwalk v1.0.0/go.mod h1:mSTlrgnPZtwu0c4WaC2kGObEpuNDbx0jmZXqmk4esnw= +github.com/mitchellh/reflectwalk v1.0.1/go.mod h1:mSTlrgnPZtwu0c4WaC2kGObEpuNDbx0jmZXqmk4esnw= github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= github.com/modern-go/reflect2 v0.0.0-20180701023420-4b7aa43c6742/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0= github.com/modern-go/reflect2 v1.0.1/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0= -github.com/mozilla/tls-observatory v0.0.0-20200220173314-aae45faa4006/go.mod h1:SrKMQvPiws7F7iqYp8/TX+IhxCYhzr6N/1yb8cwHsGk= +github.com/modern-go/reflect2 v1.0.2/go.mod h1:yWuevngMOJpCy52FWWMvUC8ws7m/LJsjYzDa0/r8luk= +github.com/mohae/deepcopy v0.0.0-20170929034955-c48cc78d4826/go.mod h1:TaXosZuwdSHYgviHp1DAtfrULt5eUgsSMsZf+YrPgl8= +github.com/moricho/tparallel v0.2.1 h1:95FytivzT6rYzdJLdtfn6m1bfFJylOJK41+lgv/EHf4= +github.com/moricho/tparallel v0.2.1/go.mod h1:fXEIZxG2vdfl0ZF8b42f5a78EhjjD5mX8qUplsoSU4k= +github.com/mozilla/scribe v0.0.0-20180711195314-fb71baf557c1/go.mod h1:FIczTrinKo8VaLxe6PWTPEXRXDIHz2QAwiaBaP5/4a8= +github.com/mozilla/tls-observatory v0.0.0-20210609171429-7bc42856d2e5/go.mod h1:FUqVoUPHSEdDR0MnFM3Dh8AU0pZHLXUD127SAJGER/s= github.com/mr-tron/base58 v1.1.0/go.mod h1:xcD2VGqlgYjBdcBLw+TuYLr8afG+Hj8g2eTVqeSzSU8= github.com/mr-tron/base58 v1.1.1/go.mod h1:xcD2VGqlgYjBdcBLw+TuYLr8afG+Hj8g2eTVqeSzSU8= github.com/mr-tron/base58 v1.1.2/go.mod h1:BinMc/sQntlIE1frQmRFPUoPA1Zkr8VRgBdjWI2mNwc= -github.com/mr-tron/base58 v1.1.3 h1:v+sk57XuaCKGXpWtVBX8YJzO7hMGx4Aajh4TQbdEFdc= github.com/mr-tron/base58 v1.1.3/go.mod h1:BinMc/sQntlIE1frQmRFPUoPA1Zkr8VRgBdjWI2mNwc= -github.com/multiformats/go-base32 v0.0.3 h1:tw5+NhuwaOjJCC5Pp82QuXbrmLzWg7uxlMFp8Nq/kkI= +github.com/mr-tron/base58 v1.2.0 h1:T/HDJBh4ZCPbU39/+c3rRvE0uKBQlU27+QI8LJ4t64o= +github.com/mr-tron/base58 v1.2.0/go.mod h1:BinMc/sQntlIE1frQmRFPUoPA1Zkr8VRgBdjWI2mNwc= github.com/multiformats/go-base32 v0.0.3/go.mod h1:pLiuGC8y0QR3Ue4Zug5UzK9LjgbkL8NSQj0zQ5Nz/AA= +github.com/multiformats/go-base32 v0.0.4 h1:+qMh4a2f37b4xTNs6mqitDinryCI+tfO2dRVMN9mjSE= +github.com/multiformats/go-base32 v0.0.4/go.mod h1:jNLFzjPZtp3aIARHbJRZIaPuspdH0J6q39uUM5pnABM= github.com/multiformats/go-base36 v0.1.0 h1:JR6TyF7JjGd3m6FbLU2cOxhC0Li8z8dLNGQ89tUg4F4= github.com/multiformats/go-base36 v0.1.0/go.mod h1:kFGE83c6s80PklsHO9sRn2NCoffoRdUUOENyW/Vv6sM= github.com/multiformats/go-multiaddr v0.0.1/go.mod h1:xKVEak1K9cS1VdmPZW3LSIb6lgmoS58qz/pzqmAxV44= @@ -695,14 +1371,21 @@ github.com/multiformats/go-multiaddr v0.1.0/go.mod h1:xKVEak1K9cS1VdmPZW3LSIb6lg github.com/multiformats/go-multiaddr v0.1.1/go.mod h1:aMKBKNEYmzmDmxfX88/vz+J5IU55txyt0p4aiWVohjo= github.com/multiformats/go-multiaddr v0.2.0/go.mod h1:0nO36NvPpyV4QzvTLi/lafl2y95ncPj0vFwVF6k6wJ4= github.com/multiformats/go-multiaddr v0.2.1/go.mod h1:s/Apk6IyxfvMjDafnhJgJ3/46z7tZ04iMk5wP4QMGGE= -github.com/multiformats/go-multiaddr v0.2.2 h1:XZLDTszBIJe6m0zF6ITBrEcZR73OPUhCBBS9rYAuUzI= github.com/multiformats/go-multiaddr v0.2.2/go.mod h1:NtfXiOtHvghW9KojvtySjH5y0u0xW5UouOmQQrn6a3Y= +github.com/multiformats/go-multiaddr v0.3.0/go.mod h1:dF9kph9wfJ+3VLAaeBqo9Of8x4fJxp6ggJGteB8HQTI= +github.com/multiformats/go-multiaddr v0.3.1/go.mod h1:uPbspcUPd5AfaP6ql3ujFY+QWzmBD8uLLL4bXW0XfGc= +github.com/multiformats/go-multiaddr v0.3.3/go.mod h1:lCKNGP1EQ1eZ35Za2wlqnabm9xQkib3fyB+nZXHLag0= +github.com/multiformats/go-multiaddr v0.4.0/go.mod h1:YcpyLH8ZPudLxQlemYBPhSm0/oCXAT8Z4mzFpyoPyRc= +github.com/multiformats/go-multiaddr v0.4.1/go.mod h1:3afI9HfVW8csiF8UZqtpYRiDyew8pRX7qLIGHu9FLuM= +github.com/multiformats/go-multiaddr v0.5.0 h1:i/JuOoVg4szYQ4YEzDGtb2h0o8M7CG/Yq6cGlcjWZpM= +github.com/multiformats/go-multiaddr v0.5.0/go.mod h1:3KAxNkUqLTJ20AAwN4XVX4kZar+bR+gh4zgbfr3SNug= github.com/multiformats/go-multiaddr-dns v0.0.1/go.mod h1:9kWcqw/Pj6FwxAwW38n/9403szc57zJPs45fmnznu3Q= github.com/multiformats/go-multiaddr-dns v0.0.2/go.mod h1:9kWcqw/Pj6FwxAwW38n/9403szc57zJPs45fmnznu3Q= github.com/multiformats/go-multiaddr-dns v0.0.3/go.mod h1:9kWcqw/Pj6FwxAwW38n/9403szc57zJPs45fmnznu3Q= github.com/multiformats/go-multiaddr-dns v0.1.0/go.mod h1:01k2RAqtoXIuPa3DCavAE9/6jc6nM0H3EgZyfUhN2oY= -github.com/multiformats/go-multiaddr-dns v0.2.0 h1:YWJoIDwLePniH7OU5hBnDZV6SWuvJqJ0YtN6pLeH9zA= github.com/multiformats/go-multiaddr-dns v0.2.0/go.mod h1:TJ5pr5bBO7Y1B18djPuRsVkduhQH2YqYSbxWJzYGdK0= +github.com/multiformats/go-multiaddr-dns v0.3.1 h1:QgQgR+LQVt3NPTjbrLLpsaT2ufAA2y0Mkk+QRVJbW3A= +github.com/multiformats/go-multiaddr-dns v0.3.1/go.mod h1:G/245BRQ6FJGmryJCrOuTdB37AMA5AMOVuO6NY3JwTk= github.com/multiformats/go-multiaddr-fmt v0.0.1/go.mod h1:aBYjqL4T/7j4Qx+R73XSv/8JsgnRFlf0w2KGLCmXl3Q= github.com/multiformats/go-multiaddr-fmt v0.1.0 h1:WLEFClPycPkp4fnIzoFoV9FVd49/eQsuaL3/CWe167E= github.com/multiformats/go-multiaddr-fmt v0.1.0/go.mod h1:hGtDIW4PU4BqJ50gW2quDuPVjyWNZxToGUh/HwTZYJo= @@ -712,101 +1395,248 @@ github.com/multiformats/go-multiaddr-net v0.1.1/go.mod h1:5JNbcfBOP4dnhoZOv10JJV github.com/multiformats/go-multiaddr-net v0.1.2/go.mod h1:QsWt3XK/3hwvNxZJp92iMQKME1qHfpYmyIjFVsSOY6Y= github.com/multiformats/go-multiaddr-net v0.1.3/go.mod h1:ilNnaM9HbmVFqsb/qcNysjCu4PVONlrBZpHIrw/qQuA= github.com/multiformats/go-multiaddr-net v0.1.4/go.mod h1:ilNnaM9HbmVFqsb/qcNysjCu4PVONlrBZpHIrw/qQuA= -github.com/multiformats/go-multiaddr-net v0.1.5 h1:QoRKvu0xHN1FCFJcMQLbG/yQE2z441L5urvG3+qyz7g= github.com/multiformats/go-multiaddr-net v0.1.5/go.mod h1:ilNnaM9HbmVFqsb/qcNysjCu4PVONlrBZpHIrw/qQuA= +github.com/multiformats/go-multiaddr-net v0.2.0/go.mod h1:gGdH3UXny6U3cKKYCvpXI5rnK7YaOIEOPVDI9tsJbEA= github.com/multiformats/go-multibase v0.0.1/go.mod h1:bja2MqRZ3ggyXtZSEDKpl0uO/gviWFaSteVbWT51qgs= -github.com/multiformats/go-multibase v0.0.2/go.mod h1:bja2MqRZ3ggyXtZSEDKpl0uO/gviWFaSteVbWT51qgs= github.com/multiformats/go-multibase v0.0.3 h1:l/B6bJDQjvQ5G52jw4QGSYeOTZoAwIO77RblWplfIqk= github.com/multiformats/go-multibase v0.0.3/go.mod h1:5+1R4eQrT3PkYZ24C3W2Ue2tPwIdYQD509ZjSb5y9Oc= +github.com/multiformats/go-multicodec v0.3.0/go.mod h1:qGGaQmioCDh+TeFOnxrbU0DaIPw8yFgAZgFG0V7p1qQ= +github.com/multiformats/go-multicodec v0.4.1 h1:BSJbf+zpghcZMZrwTYBGwy0CPcVZGWiC72Cp8bBd4R4= +github.com/multiformats/go-multicodec v0.4.1/go.mod h1:1Hj/eHRaVWSXiSNNfcEPcwZleTmdNP81xlxDLnWU9GQ= github.com/multiformats/go-multihash v0.0.1/go.mod h1:w/5tugSrLEbWqlcgJabL3oHFKTwfvkofsjW2Qa1ct4U= github.com/multiformats/go-multihash v0.0.5/go.mod h1:lt/HCbqlQwlPBz7lv0sQCdtfcMtlJvakRUn/0Ual8po= github.com/multiformats/go-multihash v0.0.8/go.mod h1:YSLudS+Pi8NHE7o6tb3D8vrpKa63epEDmG8nTduyAew= github.com/multiformats/go-multihash v0.0.10/go.mod h1:YSLudS+Pi8NHE7o6tb3D8vrpKa63epEDmG8nTduyAew= -github.com/multiformats/go-multihash v0.0.13 h1:06x+mk/zj1FoMsgNejLpy6QTvJqlSt/BhLEy87zidlc= github.com/multiformats/go-multihash v0.0.13/go.mod h1:VdAWLKTwram9oKAatUcLxBNUjdtcVwxObEQBtRfuyjc= +github.com/multiformats/go-multihash v0.0.14/go.mod h1:VdAWLKTwram9oKAatUcLxBNUjdtcVwxObEQBtRfuyjc= +github.com/multiformats/go-multihash v0.0.15/go.mod h1:D6aZrWNLFTV/ynMpKsNtB40mJzmCl4jb1alC0OvHiHg= +github.com/multiformats/go-multihash v0.1.0 h1:CgAgwqk3//SVEw3T+6DqI4mWMyRuDwZtOWcJT0q9+EA= +github.com/multiformats/go-multihash v0.1.0/go.mod h1:RJlXsxt6vHGaia+S8We0ErjhojtKzPP2AH4+kYM7k84= +github.com/multiformats/go-multistream v0.0.1/go.mod h1:fJTiDfXJVmItycydCnNx4+wSzZ5NwG2FEVAI30fiovg= +github.com/multiformats/go-multistream v0.0.4/go.mod h1:fJTiDfXJVmItycydCnNx4+wSzZ5NwG2FEVAI30fiovg= github.com/multiformats/go-multistream v0.1.0/go.mod h1:fJTiDfXJVmItycydCnNx4+wSzZ5NwG2FEVAI30fiovg= -github.com/multiformats/go-multistream v0.1.1 h1:JlAdpIFhBhGRLxe9W6Om0w++Gd6KMWoFPZL/dEnm9nI= github.com/multiformats/go-multistream v0.1.1/go.mod h1:KmHZ40hzVxiaiwlj3MEbYgK9JFk2/9UktWZAF54Du38= +github.com/multiformats/go-multistream v0.2.1/go.mod h1:5GZPQZbkWOLOn3J2y4Y99vVW7vOfsAflxARk3x14o6k= +github.com/multiformats/go-multistream v0.2.2/go.mod h1:UIcnm7Zuo8HKG+HkWgfQsGL+/MIEhyTqbODbIUwSXKs= +github.com/multiformats/go-multistream v0.3.0 h1:yX1v4IWseLPmr0rmnDo148wWJbNx40JxBZGmQb5fUP4= +github.com/multiformats/go-multistream v0.3.0/go.mod h1:ODRoqamLUsETKS9BNcII4gcRsJBU5VAwRIv7O39cEXg= github.com/multiformats/go-varint v0.0.1/go.mod h1:3Ls8CIEsrijN6+B7PbrXRPxHRPuXSrVKRY101jdMZYE= github.com/multiformats/go-varint v0.0.2/go.mod h1:3Ls8CIEsrijN6+B7PbrXRPxHRPuXSrVKRY101jdMZYE= -github.com/multiformats/go-varint v0.0.5 h1:XVZwSo04Cs3j/jS0uAEPpT3JY6DzMcVLLoWOSnCxOjg= github.com/multiformats/go-varint v0.0.5/go.mod h1:3Ls8CIEsrijN6+B7PbrXRPxHRPuXSrVKRY101jdMZYE= +github.com/multiformats/go-varint v0.0.6 h1:gk85QWKxh3TazbLxED/NlDVv8+q+ReFJk7Y2W/KhfNY= +github.com/multiformats/go-varint v0.0.6/go.mod h1:3Ls8CIEsrijN6+B7PbrXRPxHRPuXSrVKRY101jdMZYE= github.com/mwitkow/go-conntrack v0.0.0-20161129095857-cc309e4a2223/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U= -github.com/nakabonne/nestif v0.3.0 h1:+yOViDGhg8ygGrmII72nV9B/zGxY188TYpfolntsaPw= -github.com/nakabonne/nestif v0.3.0/go.mod h1:dI314BppzXjJ4HsCnbo7XzrJHPszZsjnk5wEBSYHI2c= -github.com/nbutton23/zxcvbn-go v0.0.0-20180912185939-ae427f1e4c1d h1:AREM5mwr4u1ORQBMvzfzBgpsctsbQikCVpvC+tX285E= -github.com/nbutton23/zxcvbn-go v0.0.0-20180912185939-ae427f1e4c1d/go.mod h1:o96djdrsSGy3AWPyBgZMAGfxZNfgntdJG+11KU4QvbU= +github.com/mwitkow/go-conntrack v0.0.0-20190716064945-2f068394615f/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U= +github.com/mwitkow/go-proto-validators v0.0.0-20180403085117-0950a7990007/go.mod h1:m2XC9Qq0AlmmVksL6FktJCdTYyLk7V3fKyp0sl1yWQo= +github.com/mwitkow/go-proto-validators v0.2.0/go.mod h1:ZfA1hW+UH/2ZHOWvQ3HnQaU0DtnpXu850MZiy+YUgcc= +github.com/nakabonne/nestif v0.3.1 h1:wm28nZjhQY5HyYPx+weN3Q65k6ilSBxDb8v5S81B81U= +github.com/nakabonne/nestif v0.3.1/go.mod h1:9EtoZochLn5iUprVDmDjqGKPofoUEBL8U4Ngq6aY7OE= +github.com/nats-io/jwt v0.3.0/go.mod h1:fRYCDE99xlTsqUzISS1Bi75UBJ6ljOJQOAAu5VglpSg= +github.com/nats-io/jwt v0.3.2/go.mod h1:/euKqTS1ZD+zzjYrY7pseZrTtWQSjujC7xjPc8wL6eU= +github.com/nats-io/nats-server/v2 v2.1.2/go.mod h1:Afk+wRZqkMQs/p45uXdrVLuab3gwv3Z8C4HTBu8GD/k= +github.com/nats-io/nats.go v1.9.1/go.mod h1:ZjDU1L/7fJ09jvUSRVBR2e7+RnLiiIQyqyzEE/Zbp4w= +github.com/nats-io/nkeys v0.1.0/go.mod h1:xpnFELMwJABBLVhffcfd1MZx6VsNRFpEugbxziKVo7w= +github.com/nats-io/nkeys v0.1.3/go.mod h1:xpnFELMwJABBLVhffcfd1MZx6VsNRFpEugbxziKVo7w= +github.com/nats-io/nuid v1.0.1/go.mod h1:19wcPz3Ph3q0Jbyiqsd0kePYG7A95tJPxeL+1OSON2c= +github.com/nbutton23/zxcvbn-go v0.0.0-20210217022336-fa2cb2858354 h1:4kuARK6Y6FxaNu/BnU2OAaLF86eTVhP2hjTB6iMvItA= +github.com/nbutton23/zxcvbn-go v0.0.0-20210217022336-fa2cb2858354/go.mod h1:KSVJerMDfblTH7p5MZaTt+8zaT2iEk3AkVb9PQdZuE8= github.com/neelance/astrewrite v0.0.0-20160511093645-99348263ae86/go.mod h1:kHJEU3ofeGjhHklVoIGuVj85JJwZ6kWPaJwCIxgnFmo= github.com/neelance/sourcemap v0.0.0-20151028013722-8c68805598ab/go.mod h1:Qr6/a/Q4r9LP1IltGz7tA7iOK1WonHEYhu1HRBA7ZiM= -github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e h1:fD57ERR4JtEqsWbfPhv4DMiApHyliiK5xCTNVSPiaAs= github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e/go.mod h1:zD1mROLANZcx1PVRCS0qkT7pwLkGfwJo4zjcN/Tysno= -github.com/oklog/ulid v1.3.1/go.mod h1:CirwcVhetQ6Lv90oh/F+FBtV6XMibvdAFo93nm5qn4U= +github.com/nishanths/exhaustive v0.7.11 h1:xV/WU3Vdwh5BUH4N06JNUznb6d5zhRPOnlgCrpNYNKA= +github.com/nishanths/exhaustive v0.7.11/go.mod h1:gX+MP7DWMKJmNa1HfMozK+u04hQd3na9i0hyqf3/dOI= +github.com/nishanths/predeclared v0.0.0-20190419143655-18a43bb90ffc/go.mod h1:62PewwiQTlm/7Rj+cxVYqZvDIUc+JjZq6GHAC1fsObQ= +github.com/nishanths/predeclared v0.2.1 h1:1TXtjmy4f3YCFjTxRd8zcFHOmoUir+gp0ESzjFzG2sw= +github.com/nishanths/predeclared v0.2.1/go.mod h1:HvkGJcA3naj4lOwnFXFDkFxVtSqQMB9sbB1usJ+xjQE= +github.com/nxadm/tail v1.4.4/go.mod h1:kenIhsEOeOJmVchQTgglprH7qJGnHDVpk1VPCcaMI8A= +github.com/nxadm/tail v1.4.8 h1:nPr65rt6Y5JFSKQO7qToXr7pePgD6Gwiw05lkbyAQTE= +github.com/nxadm/tail v1.4.8/go.mod h1:+ncqLTQzXmGhMZNUePPaPqPvBxHAIsmXswZKocGu+AU= +github.com/oklog/oklog v0.3.2/go.mod h1:FCV+B7mhrz4o+ueLpx+KqkyXRGMWOYEvfiXtdGtbWGs= +github.com/oklog/run v1.0.0/go.mod h1:dlhp/R75TPv97u0XWUtDeV/lRKWPKSdTuV0TZvrmrQA= +github.com/olekukonko/tablewriter v0.0.0-20170122224234-a0225b3f23b5/go.mod h1:vsDQFd/mU46D+Z4whnwzcISnGGzXWMclvtLoiIKAKIo= +github.com/olekukonko/tablewriter v0.0.1/go.mod h1:vsDQFd/mU46D+Z4whnwzcISnGGzXWMclvtLoiIKAKIo= +github.com/olekukonko/tablewriter v0.0.2/go.mod h1:rSAaSIOAGT9odnlyGlUfAJaoc5w2fSBUmeGDbRWPxyQ= +github.com/olekukonko/tablewriter v0.0.5 h1:P2Ga83D34wi1o9J6Wh1mRuqd4mF/x/lgBS7N7AbDhec= +github.com/olekukonko/tablewriter v0.0.5/go.mod h1:hPp6KlRPjbx+hW8ykQs1w3UBbZlj6HuIJcUGPhkA7kY= github.com/onsi/ginkgo v1.6.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= github.com/onsi/ginkgo v1.7.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= github.com/onsi/ginkgo v1.8.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= -github.com/onsi/ginkgo v1.11.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= -github.com/onsi/ginkgo v1.12.0 h1:Iw5WCbBcaAAd0fpRb1c9r5YCylv4XDoCSigm1zLevwU= +github.com/onsi/ginkgo v1.10.3/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= github.com/onsi/ginkgo v1.12.0/go.mod h1:oUhWkIvk5aDxtKvDDuw8gItl8pKl42LzjC9KZE0HfGg= +github.com/onsi/ginkgo v1.12.1/go.mod h1:zj2OWP4+oCPe1qIXoGWkgMRwljMUYCdkwsT2108oapk= +github.com/onsi/ginkgo v1.14.0/go.mod h1:iSB4RoI2tjJc9BBv4NKIKWKya62Rps+oPG/Lv9klQyY= +github.com/onsi/ginkgo v1.16.2/go.mod h1:CObGmKUOKaSC0RjmoAK7tKyn4Azo5P2IWuoMnvwxz1E= +github.com/onsi/ginkgo v1.16.4/go.mod h1:dX+/inL/fNMqNlz0e9LfyB9TswhZpCVdJM/Z6Vvnwo0= +github.com/onsi/ginkgo v1.16.5 h1:8xi0RTUf59SOSfEtZMvwTvXYMzG4gV23XVHOZiXNtnE= +github.com/onsi/ginkgo v1.16.5/go.mod h1:+E8gABHa3K6zRBolWtd+ROzc/U5bkGt0FwiG042wbpU= +github.com/onsi/ginkgo/v2 v2.0.0/go.mod h1:vw5CSIxN1JObi/U8gcbwft7ZxR2dgaR70JSE3/PpL4c= +github.com/onsi/ginkgo/v2 v2.1.3 h1:e/3Cwtogj0HA+25nMP1jCMDIf8RtRYbGwGGuBIFztkc= +github.com/onsi/ginkgo/v2 v2.1.3/go.mod h1:vw5CSIxN1JObi/U8gcbwft7ZxR2dgaR70JSE3/PpL4c= +github.com/onsi/gomega v1.4.1/go.mod h1:C1qb7wdrVGGVU+Z6iS04AVkA3Q65CEZX59MT0QO5uiA= github.com/onsi/gomega v1.4.3/go.mod h1:ex+gbHU/CVuBBDIJjb2X0qEXbFg53c61hWP/1CpauHY= github.com/onsi/gomega v1.5.0/go.mod h1:ex+gbHU/CVuBBDIJjb2X0qEXbFg53c61hWP/1CpauHY= github.com/onsi/gomega v1.7.1/go.mod h1:XdKZgCCFLUoM/7CFJVPcG8C1xQ1AJ0vpAezJrB7JYyY= -github.com/onsi/gomega v1.8.1/go.mod h1:Ho0h+IUsWyvy1OpqCwxlQ/21gkhVunqlU8fDGcoTdcA= -github.com/onsi/gomega v1.9.0 h1:R1uwffexN6Pr340GtYRIdZmAiN4J+iw6WG4wog1DUXg= github.com/onsi/gomega v1.9.0/go.mod h1:Ho0h+IUsWyvy1OpqCwxlQ/21gkhVunqlU8fDGcoTdcA= +github.com/onsi/gomega v1.10.1/go.mod h1:iN09h71vgCQne3DLsj+A5owkum+a2tYe+TOCB1ybHNo= +github.com/onsi/gomega v1.13.0/go.mod h1:lRk9szgn8TxENtWd0Tp4c3wjlRfMTMH27I+3Je41yGY= +github.com/onsi/gomega v1.17.0/go.mod h1:HnhC7FXeEQY45zxNK3PPoIUhzk/80Xly9PcubAlGdZY= +github.com/onsi/gomega v1.18.1 h1:M1GfJqGRrBrrGGsbxzV5dqM2U2ApXefZCQpkukxYRLE= +github.com/onsi/gomega v1.18.1/go.mod h1:0q+aL8jAiMXy9hbwj2mr5GziHiwhAIQpFmmtT5hitRs= +github.com/op/go-logging v0.0.0-20160315200505-970db520ece7/go.mod h1:HzydrMdWErDVzsI23lYNej1Htcns9BCg93Dk0bBINWk= +github.com/opencontainers/runtime-spec v1.0.2 h1:UfAcuLBJB9Coz72x1hgl8O5RVzTdNiaglX6v2DM6FI0= +github.com/opencontainers/runtime-spec v1.0.2/go.mod h1:jwyrGlmzljRJv/Fgzds9SsS/C5hL+LL3ko9hs6T5lQ0= +github.com/opentracing-contrib/go-observer v0.0.0-20170622124052-a52f23424492/go.mod h1:Ngi6UdF0k5OKD5t5wlmGhe/EDKPoUM3BXZSSfIuJbis= +github.com/opentracing/basictracer-go v1.0.0/go.mod h1:QfBfYuafItcjQuMwinw9GhYKwFXS9KnPs5lxoYwgW74= github.com/opentracing/opentracing-go v1.0.2/go.mod h1:UkNAQd3GIcIGf0SeVgPpRdFStlNbqXla1AfSYxPUl2o= -github.com/opentracing/opentracing-go v1.1.0 h1:pWlfV3Bxv7k65HYwkikxat0+s3pV4bsqf19k25Ur8rU= github.com/opentracing/opentracing-go v1.1.0/go.mod h1:UkNAQd3GIcIGf0SeVgPpRdFStlNbqXla1AfSYxPUl2o= +github.com/opentracing/opentracing-go v1.2.0 h1:uEJPy/1a5RIPAJ0Ov+OIO8OxWu77jEv+1B0VhjKrZUs= +github.com/opentracing/opentracing-go v1.2.0/go.mod h1:GxEUsuufX4nBwe+T+Wl9TAgYrxe9dPLANfrWvHYVTgc= +github.com/openzipkin-contrib/zipkin-go-opentracing v0.4.5/go.mod h1:/wsWhb9smxSfWAKL3wpBW7V8scJMt8N8gnaMCS9E/cA= github.com/openzipkin/zipkin-go v0.1.1/go.mod h1:NtoC/o8u3JlF1lSlyPNswIbeQH9bJTmOf0Erfk+hxe8= +github.com/openzipkin/zipkin-go v0.1.6/go.mod h1:QgAqvLzwWbR/WpD4A3cGpPtJrZXNIiJc5AZX7/PBEpw= +github.com/openzipkin/zipkin-go v0.2.1/go.mod h1:NaW6tEwdmWMaCDZzg8sh+IBNOxHMPnhQw8ySjnjRyN4= +github.com/openzipkin/zipkin-go v0.2.2/go.mod h1:NaW6tEwdmWMaCDZzg8sh+IBNOxHMPnhQw8ySjnjRyN4= +github.com/otiai10/copy v1.2.0 h1:HvG945u96iNadPoG2/Ja2+AUJeW5YuFQMixq9yirC+k= +github.com/otiai10/copy v1.2.0/go.mod h1:rrF5dJ5F0t/EWSYODDu4j9/vEeYHMkc8jt0zJChqQWw= +github.com/otiai10/curr v0.0.0-20150429015615-9b4961190c95/go.mod h1:9qAhocn7zKJG+0mI8eUu6xqkFDYS2kb2saOteoSB3cE= +github.com/otiai10/curr v1.0.0/go.mod h1:LskTG5wDwr8Rs+nNQ+1LlxRjAtTZZjtJW4rMXl6j4vs= +github.com/otiai10/mint v1.3.0/go.mod h1:F5AjcsTsWUqX+Na9fpHb52P8pcRX2CI6A3ctIT91xUo= +github.com/otiai10/mint v1.3.1/go.mod h1:/yxELlJQ0ufhjUwhshSj+wFjZ78CnZ48/1wtmBH1OTc= +github.com/pact-foundation/pact-go v1.0.4/go.mod h1:uExwJY4kCzNPcHRj+hCR/HBbOOIwwtUjcrb0b5/5kLM= +github.com/pascaldekloe/goe v0.0.0-20180627143212-57f6aae5913c/go.mod h1:lzWF7FIEvWOWxwDKqyGYQf6ZUaNfKdP144TG7ZOy1lc= +github.com/pascaldekloe/goe v0.1.0/go.mod h1:lzWF7FIEvWOWxwDKqyGYQf6ZUaNfKdP144TG7ZOy1lc= +github.com/pbnjay/memory v0.0.0-20210728143218-7b4eea64cf58 h1:onHthvaw9LFnH4t2DcNVpwGmV9E1BkGknEliJkfwQj0= +github.com/pbnjay/memory v0.0.0-20210728143218-7b4eea64cf58/go.mod h1:DXv8WO4yhMYhSNPKjeNKa5WY9YCIEBRbNzFFPJbWO6Y= github.com/pborman/uuid v1.2.0/go.mod h1:X/NO0urCmaxf9VXbdlT7C2Yzkj2IKimNn4k+gtPdI/k= -github.com/pelletier/go-toml v1.2.0 h1:T5zMGML61Wp+FlcbWjRDT7yAxhJNAiPPLOFECq181zc= github.com/pelletier/go-toml v1.2.0/go.mod h1:5z9KED0ma1S8pY6P1sdut58dfprrGBbd/94hg7ilaic= +github.com/pelletier/go-toml v1.9.4 h1:tjENF6MfZAg8e4ZmZTeWaWiT2vXtsoO6+iuOjFhECwM= +github.com/pelletier/go-toml v1.9.4/go.mod h1:u1nR/EPcESfeI/szUZKdtJ0xRNbUoANCkoOuaOx1Y+c= +github.com/performancecopilot/speed v3.0.0+incompatible/go.mod h1:/CLtqpZ5gBg1M9iaPbIdPPGyKcA8hKdoy6hAWba7Yac= +github.com/peterbourgon/diskv v2.0.1+incompatible/go.mod h1:uqqh8zWWbv1HBMNONnaR/tNboyR3/BZd58JJSHlUSCU= +github.com/phayes/checkstyle v0.0.0-20170904204023-bfd46e6a821d h1:CdDQnGF8Nq9ocOS/xlSptM1N3BbrA6/kmaep5ggwaIA= github.com/phayes/checkstyle v0.0.0-20170904204023-bfd46e6a821d/go.mod h1:3OzsM7FXDQlpCiw2j81fOmAwQLnZnLGXVKUzeKQXIAw= +github.com/pierrec/lz4 v1.0.2-0.20190131084431-473cd7ce01a1/go.mod h1:3/3N9NVKO0jef7pBehbT1qWhCMrIgbYNnFAZCqQ5LRc= +github.com/pierrec/lz4 v2.0.5+incompatible/go.mod h1:pdkljMzZIN41W+lC3N2tnIh5sFi+IEE17M5jbnwPHcY= +github.com/pkg/diff v0.0.0-20210226163009-20ebb0f2a09e/go.mod h1:pJLUxLENpZxwdsKMEsNbx1VGcRFpLqf3715MtcvvzbA= github.com/pkg/errors v0.8.0/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4= github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= +github.com/pkg/profile v1.2.1/go.mod h1:hJw3o1OdXxsrSjjVksARp5W95eeEaEfptyVZyv6JUPA= +github.com/pkg/sftp v1.10.1/go.mod h1:lYOWFsE0bwd1+KfKJaKeuokY15vzFx25BLbzYYoAxZI= +github.com/pmezard/go-difflib v0.0.0-20151028094244-d8ed2627bdf0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= github.com/polydawn/refmt v0.0.0-20190221155625-df39d6c2d992/go.mod h1:uIp+gprXxxrWSjjklXD+mN4wed/tMfjMMmN/9+JsA9o= github.com/polydawn/refmt v0.0.0-20190408063855-01bf1e26dd14/go.mod h1:uIp+gprXxxrWSjjklXD+mN4wed/tMfjMMmN/9+JsA9o= github.com/polydawn/refmt v0.0.0-20190807091052-3d65705ee9f1/go.mod h1:uIp+gprXxxrWSjjklXD+mN4wed/tMfjMMmN/9+JsA9o= -github.com/polydawn/refmt v0.0.0-20190809202753-05966cbd336a h1:hjZfReYVLbqFkAtr2us7vdy04YWz3LVAirzP7reh8+M= -github.com/polydawn/refmt v0.0.0-20190809202753-05966cbd336a/go.mod h1:uIp+gprXxxrWSjjklXD+mN4wed/tMfjMMmN/9+JsA9o= +github.com/polydawn/refmt v0.0.0-20201211092308-30ac6d18308e h1:ZOcivgkkFRnjfoTcGsDq3UQYiBmekwLA+qg0OjyB/ls= +github.com/polydawn/refmt v0.0.0-20201211092308-30ac6d18308e/go.mod h1:uIp+gprXxxrWSjjklXD+mN4wed/tMfjMMmN/9+JsA9o= +github.com/polyfloyd/go-errorlint v0.0.0-20211125173453-6d6d39c5bb8b h1:/BDyEJWLnDUYKGWdlNx/82qSaVu2bUok/EvPUtIGuvw= +github.com/polyfloyd/go-errorlint v0.0.0-20211125173453-6d6d39c5bb8b/go.mod h1:wi9BfjxjF/bwiZ701TzmfKu6UKC357IOAtNr0Td0Lvw= +github.com/posener/complete v1.1.1/go.mod h1:em0nMJCgc9GFtwrmVmEMR/ZL6WyhyjMBndrE9hABlRI= +github.com/posener/complete v1.2.3/go.mod h1:WZIdtGGp+qx0sLrYKtIRAruyNpv6hFCicSgv7Sy7s/s= +github.com/power-devops/perfstat v0.0.0-20210106213030-5aafc221ea8c/go.mod h1:OmDBASR4679mdNQnz2pUhc2G8CO2JrUAVFDRBDP/hJE= github.com/prometheus/client_golang v0.8.0/go.mod h1:7SWBe2y4D6OKWSNQJUaRYU/AaXPKyh/dDVn+NZz0KFw= github.com/prometheus/client_golang v0.9.1/go.mod h1:7SWBe2y4D6OKWSNQJUaRYU/AaXPKyh/dDVn+NZz0KFw= -github.com/prometheus/client_golang v0.9.3/go.mod h1:/TN21ttK/J9q6uSwhBd54HahCDft0ttaMvbicHlPoso= +github.com/prometheus/client_golang v0.9.3-0.20190127221311-3c4408c8b829/go.mod h1:p2iRAGwDERtqlqzRXnrOVns+ignqQo//hLXqYxZYVNs= github.com/prometheus/client_golang v1.0.0/go.mod h1:db9x61etRT2tGnBNRi70OPL5FsnadC4Ky3P0J6CfImo= github.com/prometheus/client_golang v1.1.0/go.mod h1:I1FGZT9+L76gKKOs5djB6ezCbFQP1xR9D75/vuwEF3g= +github.com/prometheus/client_golang v1.3.0/go.mod h1:hJaj2vgQTGQmVCsAACORcieXFeDPbaTKGT+JTgUa3og= +github.com/prometheus/client_golang v1.4.0/go.mod h1:e9GMxYsXl05ICDXkRhurwBS4Q3OK1iX/F2sw+iXX5zU= +github.com/prometheus/client_golang v1.7.1/go.mod h1:PY5Wy2awLA44sXw4AOSfFBetzPP4j5+D6mVACh+pe2M= +github.com/prometheus/client_golang v1.9.0/go.mod h1:FqZLKOZnGdFAhOK4nqGHa7D66IdsO+O441Eve7ptJDU= +github.com/prometheus/client_golang v1.10.0/go.mod h1:WJM3cc3yu7XKBKa/I8WeZm+V3eltZnBwfENSU7mdogU= +github.com/prometheus/client_golang v1.11.0/go.mod h1:Z6t4BnS23TR94PD6BsDNk8yVqroYurpAkEiz0P2BEV0= +github.com/prometheus/client_golang v1.12.1 h1:ZiaPsmm9uiBeaSMRznKsCDNtPCS0T3JVDGF+06gjBzk= +github.com/prometheus/client_golang v1.12.1/go.mod h1:3Z9XVyYiZYEO+YQWt3RD2R3jrbd179Rt297l4aS6nDY= github.com/prometheus/client_model v0.0.0-20180712105110-5c3871d89910/go.mod h1:MbSGuTsp3dbXC40dX6PRTWyKYBIrTGTE9sqQNg2J8bo= +github.com/prometheus/client_model v0.0.0-20190115171406-56726106282f/go.mod h1:MbSGuTsp3dbXC40dX6PRTWyKYBIrTGTE9sqQNg2J8bo= github.com/prometheus/client_model v0.0.0-20190129233127-fd36f4220a90/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= +github.com/prometheus/client_model v0.0.0-20190812154241-14fe0d1b01d4/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= +github.com/prometheus/client_model v0.1.0/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= +github.com/prometheus/client_model v0.2.0 h1:uq5h0d+GuxiXLJLNABMgp2qUWDPiLvgCzz2dUR+/W/M= +github.com/prometheus/client_model v0.2.0/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= github.com/prometheus/common v0.0.0-20180801064454-c7de2306084e/go.mod h1:daVV7qP5qjZbuso7PdcryaAu0sAZbrN9i7WWcTMWvro= -github.com/prometheus/common v0.0.0-20181113130724-41aa239b4cce/go.mod h1:daVV7qP5qjZbuso7PdcryaAu0sAZbrN9i7WWcTMWvro= -github.com/prometheus/common v0.4.0/go.mod h1:TNfzLD0ON7rHzMJeJkieUDPYmFC7Snx/y86RQel1bk4= +github.com/prometheus/common v0.2.0/go.mod h1:TNfzLD0ON7rHzMJeJkieUDPYmFC7Snx/y86RQel1bk4= github.com/prometheus/common v0.4.1/go.mod h1:TNfzLD0ON7rHzMJeJkieUDPYmFC7Snx/y86RQel1bk4= github.com/prometheus/common v0.6.0/go.mod h1:eBmuwkDJBwy6iBfxCBob6t6dR6ENT/y+J+Zk0j9GMYc= +github.com/prometheus/common v0.7.0/go.mod h1:DjGbpBbp5NYNiECxcL/VnbXCCaQpKd3tt26CguLLsqA= +github.com/prometheus/common v0.9.1/go.mod h1:yhUN8i9wzaXS3w1O07YhxHEBxD+W35wd8bs7vj7HSQ4= +github.com/prometheus/common v0.10.0/go.mod h1:Tlit/dnDKsSWFlCLTWaA1cyBgKHSMdTB80sz/V91rCo= +github.com/prometheus/common v0.15.0/go.mod h1:U+gB1OBLb1lF3O42bTCL+FK18tX9Oar16Clt/msog/s= +github.com/prometheus/common v0.18.0/go.mod h1:U+gB1OBLb1lF3O42bTCL+FK18tX9Oar16Clt/msog/s= +github.com/prometheus/common v0.26.0/go.mod h1:M7rCNAaPfAosfx8veZJCuw84e35h3Cfd9VFqTh1DIvc= +github.com/prometheus/common v0.30.0/go.mod h1:vu+V0TpY+O6vW9J44gczi3Ap/oXXR10b+M/gUGO4Hls= +github.com/prometheus/common v0.32.1/go.mod h1:vu+V0TpY+O6vW9J44gczi3Ap/oXXR10b+M/gUGO4Hls= +github.com/prometheus/common v0.33.0 h1:rHgav/0a6+uYgGdNt3jwz8FNSesO/Hsang3O0T9A5SE= +github.com/prometheus/common v0.33.0/go.mod h1:gB3sOl7P0TvJabZpLY5uQMpUqRCPPCyRLCZYc7JZTNE= github.com/prometheus/procfs v0.0.0-20180725123919-05ee40e3a273/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk= github.com/prometheus/procfs v0.0.0-20181005140218-185b4288413d/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk= -github.com/prometheus/procfs v0.0.0-20190507164030-5867b95ac084/go.mod h1:TjEm7ze935MbeOT/UhFTIMYKhuLP4wbCsTZCD3I8kEA= +github.com/prometheus/procfs v0.0.0-20190117184657-bf6a532e95b1/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk= github.com/prometheus/procfs v0.0.2/go.mod h1:TjEm7ze935MbeOT/UhFTIMYKhuLP4wbCsTZCD3I8kEA= github.com/prometheus/procfs v0.0.3/go.mod h1:4A/X28fw3Fc593LaREMrKMqOKvUAntwMDaekg4FpcdQ= -github.com/prometheus/tsdb v0.7.1/go.mod h1:qhTCs0VvXwvX/y3TZrWD7rabWM+ijKTux40TwIPHuXU= -github.com/quasilyte/go-consistent v0.0.0-20190521200055-c6f3937de18c/go.mod h1:5STLWrekHfjyYwxBRVRXNOSewLJ3PWfDJd1VyTS21fI= +github.com/prometheus/procfs v0.0.8/go.mod h1:7Qr8sr6344vo1JqZ6HhLceV9o3AJ1Ff+GxbHq6oeK9A= +github.com/prometheus/procfs v0.1.3/go.mod h1:lV6e/gmhEcM9IjHGsFOCxxuZ+z1YqCvr4OA4YeYWdaU= +github.com/prometheus/procfs v0.2.0/go.mod h1:lV6e/gmhEcM9IjHGsFOCxxuZ+z1YqCvr4OA4YeYWdaU= +github.com/prometheus/procfs v0.6.0/go.mod h1:cz+aTbrPOrUb4q7XlbU9ygM+/jj0fzG6c1xBZuNvfVA= +github.com/prometheus/procfs v0.7.3 h1:4jVXhlkAyzOScmCkXBTOLRLTz8EeU+eyjrwB/EPq0VU= +github.com/prometheus/procfs v0.7.3/go.mod h1:cz+aTbrPOrUb4q7XlbU9ygM+/jj0fzG6c1xBZuNvfVA= +github.com/pseudomuto/protoc-gen-doc v1.3.2/go.mod h1:y5+P6n3iGrbKG+9O04V5ld71in3v/bX88wUwgt+U8EA= +github.com/pseudomuto/protokit v0.2.0/go.mod h1:2PdH30hxVHsup8KpBTOXTBeMVhJZVio3Q8ViKSAXT0Q= +github.com/quasilyte/go-ruleguard v0.3.1-0.20210203134552-1b5a410e1cc8/go.mod h1:KsAh3x0e7Fkpgs+Q9pNLS5XpFSvYCEVl5gP9Pp1xp30= +github.com/quasilyte/go-ruleguard v0.3.15 h1:iWYzp1z72IlXTioET0+XI6SjQdPfMGfuAiZiKznOt7g= +github.com/quasilyte/go-ruleguard v0.3.15/go.mod h1:NhuWhnlVEM1gT1A4VJHYfy9MuYSxxwHgxWoPsn9llB4= +github.com/quasilyte/go-ruleguard/dsl v0.3.0/go.mod h1:KeCP03KrjuSO0H1kTuZQCWlQPulDV6YMIXmpQss17rU= +github.com/quasilyte/go-ruleguard/dsl v0.3.12-0.20220101150716-969a394a9451/go.mod h1:KeCP03KrjuSO0H1kTuZQCWlQPulDV6YMIXmpQss17rU= +github.com/quasilyte/go-ruleguard/dsl v0.3.12/go.mod h1:KeCP03KrjuSO0H1kTuZQCWlQPulDV6YMIXmpQss17rU= +github.com/quasilyte/go-ruleguard/dsl v0.3.17/go.mod h1:KeCP03KrjuSO0H1kTuZQCWlQPulDV6YMIXmpQss17rU= +github.com/quasilyte/go-ruleguard/rules v0.0.0-20201231183845-9e62ed36efe1/go.mod h1:7JTjp89EGyU1d6XfBiXihJNG37wB2VRkd125Q1u7Plc= +github.com/quasilyte/go-ruleguard/rules v0.0.0-20211022131956-028d6511ab71/go.mod h1:4cgAphtvu7Ftv7vOT2ZOYhC6CvBxZixcasr8qIOTA50= +github.com/quasilyte/gogrep v0.0.0-20220103110004-ffaa07af02e3 h1:P4QPNn+TK49zJjXKERt/vyPbv/mCHB/zQ4flDYOMN+M= +github.com/quasilyte/gogrep v0.0.0-20220103110004-ffaa07af02e3/go.mod h1:wSEyW6O61xRV6zb6My3HxrQ5/8ke7NE2OayqCHa3xRM= +github.com/quasilyte/regex/syntax v0.0.0-20200407221936-30656e2c4a95 h1:L8QM9bvf68pVdQ3bCFZMDmnt9yqcMBro1pC7F+IPYMY= +github.com/quasilyte/regex/syntax v0.0.0-20200407221936-30656e2c4a95/go.mod h1:rlzQ04UMyJXu/aOvhd8qT+hvDrFpiwqp8MRXDY9szc0= +github.com/raulk/clock v1.1.0 h1:dpb29+UKMbLqiU/jqIJptgLR1nn23HLgMY0sTCDza5Y= +github.com/raulk/clock v1.1.0/go.mod h1:3MpVxdZ/ODBQDxbN+kzshf5OSZwPjtMDx6BBXBmOeY0= +github.com/raulk/go-watchdog v1.2.0 h1:konN75pw2BMmZ+AfuAm5rtFsWcJpKF3m02rKituuXNo= +github.com/raulk/go-watchdog v1.2.0/go.mod h1:lzSbAl5sh4rtI8tYHU01BWIDzgzqaQLj6RcA1i4mlqI= +github.com/rcrowley/go-metrics v0.0.0-20181016184325-3113b8401b8a/go.mod h1:bCqnVzQkZxMG4s8nGwiZ5l3QUCyqpo9Y+/ZMZ9VjZe4= github.com/rogpeppe/fastuuid v0.0.0-20150106093220-6724a57986af/go.mod h1:XWv6SoW27p1b0cqNHllgS5HIMJraePCO15w5zCzIWYg= +github.com/rogpeppe/fastuuid v1.2.0/go.mod h1:jVj6XXZzXRy/MSR5jhDC/2q6DgLz+nrA6LYCDYWNEvQ= github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4= +github.com/rogpeppe/go-internal v1.6.1/go.mod h1:xXDCJY+GAPziupqXw64V24skbSoqbTEfhy4qGm1nDQc= +github.com/rogpeppe/go-internal v1.8.1 h1:geMPLpDpQOgVyCg5z5GoRwLHepNdb71NXb67XFkP+Eg= +github.com/rogpeppe/go-internal v1.8.1/go.mod h1:JeRgkft04UBgHMgCIwADu4Pn6Mtm5d4nPKWu0nJ5d+o= +github.com/rs/cors v1.7.0/go.mod h1:gFx+x8UowdsKA9AchylcLynDq+nNFfI8FkUZdN/jGCU= +github.com/russross/blackfriday v1.5.2 h1:HyvC0ARfnZBqnXwABFeSZHpKvJHJJfPz81GNueLj0oo= github.com/russross/blackfriday v1.5.2/go.mod h1:JO/DiYxRf+HjHt06OyowR9PTA263kcR/rfWxYHBV53g= -github.com/ryancurrah/gomodguard v1.0.4 h1:oCreMAt9GuFXDe9jW4HBpc3GjdX3R/sUEcLAGh1zPx8= -github.com/ryancurrah/gomodguard v1.0.4/go.mod h1:9T/Cfuxs5StfsocWr4WzDL36HqnX0fVb9d5fSEaLhoE= -github.com/securego/gosec v0.0.0-20200316084457-7da9f46445fd h1:qB+l4fYZsH78xORC1aqVS0zNmgkQp4rkj2rvfxQMtzc= -github.com/securego/gosec v0.0.0-20200316084457-7da9f46445fd/go.mod h1:NurAFZsWJAEZjogSwdVPlHkOZB3DOAU7gsPP8VFZCHc= +github.com/russross/blackfriday/v2 v2.0.1/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM= +github.com/russross/blackfriday/v2 v2.1.0 h1:JIOH55/0cWyOuilr9/qlrm0BSXldqnqwMsf35Ld67mk= +github.com/russross/blackfriday/v2 v2.1.0/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM= +github.com/ryancurrah/gomodguard v1.2.3 h1:ww2fsjqocGCAFamzvv/b8IsRduuHHeK2MHTcTxZTQX8= +github.com/ryancurrah/gomodguard v1.2.3/go.mod h1:rYbA/4Tg5c54mV1sv4sQTP5WOPBcoLtnBZ7/TEhXAbg= +github.com/ryanrolds/sqlclosecheck v0.3.0 h1:AZx+Bixh8zdUBxUA1NxbxVAS78vTPq4rCb8OUZI9xFw= +github.com/ryanrolds/sqlclosecheck v0.3.0/go.mod h1:1gREqxyTGR3lVtpngyFo3hZAgk0KCtEdgEkHwDbigdA= +github.com/ryanuber/columnize v0.0.0-20160712163229-9b3edd62028f/go.mod h1:sm1tb6uqfes/u+d4ooFouqFdy9/2g9QGwK3SQygK0Ts= +github.com/sagikazarmark/crypt v0.1.0/go.mod h1:B/mN0msZuINBtQ1zZLEQcegFJJf9vnYIR88KRMEuODE= +github.com/sagikazarmark/crypt v0.3.0/go.mod h1:uD/D+6UF4SrIR1uGEv7bBNkNqLGqUr43MRiaGWX1Nig= +github.com/sagikazarmark/crypt v0.4.0/go.mod h1:ALv2SRj7GxYV4HO9elxH9nS6M9gW+xDNxqmyJ6RfDFM= +github.com/samuel/go-zookeeper v0.0.0-20190923202752-2cc03de413da/go.mod h1:gi+0XIa01GRL2eRQVjQkKGqKF3SF9vZR/HnPullcV2E= +github.com/sanposhiho/wastedassign/v2 v2.0.6 h1:+6/hQIHKNJAUixEj6EmOngGIisyeI+T3335lYTyxRoA= +github.com/sanposhiho/wastedassign/v2 v2.0.6/go.mod h1:KyZ0MWTwxxBmfwn33zh3k1dmsbF2ud9pAAGfoLfjhtI= +github.com/sean-/seed v0.0.0-20170313163322-e2103e2c3529/go.mod h1:DxrIzT+xaE7yg65j358z/aeFdxmN0P9QXhEzd20vsDc= +github.com/securego/gosec/v2 v2.10.0 h1:l6BET4EzWtyUXCpY2v7N92v0DDCas0L7ngg3bpqbr8g= +github.com/securego/gosec/v2 v2.10.0/go.mod h1:PVq8Ewh/nCN8l/kKC6zrGXSr7m2NmEK6ITIAWMtIaA0= github.com/sergi/go-diff v1.0.0/go.mod h1:0CfEIISq7TuYL3j771MWULgwwjU+GofnZX9QAmXWZgo= -github.com/shirou/gopsutil v0.0.0-20190901111213-e4ec7b275ada/go.mod h1:WWnYX4lzhCH5h/3YBfyVA3VbLYjlMZZAQcW9ojMexNc= -github.com/shirou/w32 v0.0.0-20160930032740-bb4de0191aa4/go.mod h1:qsXQc7+bwAM3Q1u/4XEfrquwF8Lw7D7y5cD8CuHnfIc= +github.com/sergi/go-diff v1.1.0/go.mod h1:STckp+ISIX8hZLjrqAeVduY0gWCT9IjLuqbuNXdaHfM= +github.com/shazow/go-diff v0.0.0-20160112020656-b6b7b6733b8c h1:W65qqJCIOVP4jpqPQ0YvHYKwcMEMVWIzWC5iNQQfBTU= +github.com/shazow/go-diff v0.0.0-20160112020656-b6b7b6733b8c/go.mod h1:/PevMnwAxekIXwN8qQyfc5gl2NlkB3CQlkizAbOkeBs= +github.com/shirou/gopsutil/v3 v3.22.2/go.mod h1:WapW1AOOPlHyXr+yOyw3uYx36enocrtSoSBy0L5vUHY= github.com/shurcooL/component v0.0.0-20170202220835-f88ec8f54cc4/go.mod h1:XhFIlyj5a1fBNx5aJTbKoIq0mNaPvOagO+HjB3EtxrY= github.com/shurcooL/events v0.0.0-20181021180414-410e4ca65f48/go.mod h1:5u70Mqkb5O5cxEA8nxTsgrgLehJeAw6Oc4Ab1c/P1HM= github.com/shurcooL/github_flavored_markdown v0.0.0-20181002035957-2122de532470/go.mod h1:2dOwnU2uBioM+SGy2aZoq1f/Sd1l9OkAeAUvjSyvgU0= -github.com/shurcooL/go v0.0.0-20180423040247-9e1955d9fb6e h1:MZM7FHLqUHYI0Y/mQAt3d2aYa0SiNms/hFqC9qJYolM= github.com/shurcooL/go v0.0.0-20180423040247-9e1955d9fb6e/go.mod h1:TDJrrUr11Vxrven61rcy3hJMUqaf/CLWYhHNPmT14Lk= -github.com/shurcooL/go-goon v0.0.0-20170922171312-37c2f522c041 h1:llrF3Fs4018ePo4+G/HV/uQUqEI1HMDjCeOf2V6puPc= github.com/shurcooL/go-goon v0.0.0-20170922171312-37c2f522c041/go.mod h1:N5mDOmsrJOB+vfqUK+7DmDyjhSLIIBnXo9lvZJj3MWQ= github.com/shurcooL/gofontwoff v0.0.0-20180329035133-29b52fc0a18d/go.mod h1:05UtEgK5zq39gLST6uB0cf3NEHjETfB4Fgr3Gx5R9Vw= github.com/shurcooL/gopherjslib v0.0.0-20160914041154-feb6d3990c2c/go.mod h1:8d3azKNyqcHP1GaQE/c6dDgjkgSx2BZ4IoEi4F1reUI= @@ -823,26 +1653,35 @@ github.com/shurcooL/notifications v0.0.0-20181007000457-627ab5aea122/go.mod h1:b github.com/shurcooL/octicon v0.0.0-20181028054416-fa4f57f9efb2/go.mod h1:eWdoE5JD4R5UVWDucdOPg1g2fqQRq78IQa9zlOV1vpQ= github.com/shurcooL/reactions v0.0.0-20181006231557-f2e0b4ca5b82/go.mod h1:TCR1lToEk4d2s07G3XGfz2QrgHXg4RJBvjrOozvoWfk= github.com/shurcooL/sanitized_anchor_name v0.0.0-20170918181015-86672fcb3f95/go.mod h1:1NzhyTcUVG4SuEtjjoZeVRXNmyL/1OwPU0+IJeTBvfc= +github.com/shurcooL/sanitized_anchor_name v1.0.0/go.mod h1:1NzhyTcUVG4SuEtjjoZeVRXNmyL/1OwPU0+IJeTBvfc= github.com/shurcooL/users v0.0.0-20180125191416-49c67e49c537/go.mod h1:QJTqeLYEDaXHZDBsXlPCDqdhQuJkuw4NOtaxYe3xii4= github.com/shurcooL/webdavfs v0.0.0-20170829043945-18c3829fa133/go.mod h1:hKmq5kWdCj2z2KEozexVbfEZIWiTjhE0+UjmZgPqehw= github.com/sirupsen/logrus v1.0.5/go.mod h1:pMByvHTf9Beacp5x1UXfOR9xyW/9antXMhjMPG0dEzc= github.com/sirupsen/logrus v1.2.0/go.mod h1:LxeOpSwHxABJmUn/MG1IvRgCAasNZTLOkJPxbbu5VWo= -github.com/sirupsen/logrus v1.4.2 h1:SPIRibHv4MatM3XXNO2BJeFLZwZ2LvZgfQ5+UNI2im4= github.com/sirupsen/logrus v1.4.2/go.mod h1:tLMulIdttU9McNUspp0xgXVQah82FyeX6MwdIuYE2rE= +github.com/sirupsen/logrus v1.6.0/go.mod h1:7uNnSEd1DgxDLC74fIahvMZmmYsHGZGEOFrfsX/uA88= +github.com/sirupsen/logrus v1.7.0/go.mod h1:yWOB1SBYBC5VeMP7gHvWumXLIWorT60ONWic61uBYv0= +github.com/sirupsen/logrus v1.8.1 h1:dJKuHgqk1NNQlqoA6BTlM1Wf9DOH3NBjQyu0h9+AZZE= +github.com/sirupsen/logrus v1.8.1/go.mod h1:yWOB1SBYBC5VeMP7gHvWumXLIWorT60ONWic61uBYv0= +github.com/sivchari/containedctx v1.0.2 h1:0hLQKpgC53OVF1VT7CeoFHk9YKstur1XOgfYIc1yrHI= +github.com/sivchari/containedctx v1.0.2/go.mod h1:PwZOeqm4/DLoJOqMSIJs3aKqXRX4YO+uXww087KZ7Bw= +github.com/sivchari/tenv v1.4.7 h1:FdTpgRlTue5eb5nXIYgS/lyVXSjugU8UUVDwhP1NLU8= +github.com/sivchari/tenv v1.4.7/go.mod h1:5nF+bITvkebQVanjU6IuMbvIot/7ReNsUV7I5NbprB0= github.com/smartystreets/assertions v0.0.0-20180927180507-b2de0cb4f26d/go.mod h1:OnSkiWE9lh6wB0YB77sQom3nweQdgAjqCqsofrRNTgc= +github.com/smartystreets/assertions v1.0.0 h1:UVQPSSmc3qtTi+zPPkCXvZX9VvW/xT/NsRvKfwY81a8= github.com/smartystreets/assertions v1.0.0/go.mod h1:kHHU4qYBaI3q23Pp3VPrmWhuIUrLW/7eUrw0BU5VaoM= -github.com/smartystreets/assertions v1.0.1 h1:voD4ITNjPL5jjBfgR/r8fPIIBrliWrWHeiJApdr3r4w= -github.com/smartystreets/assertions v1.0.1/go.mod h1:kHHU4qYBaI3q23Pp3VPrmWhuIUrLW/7eUrw0BU5VaoM= github.com/smartystreets/goconvey v0.0.0-20190222223459-a17d461953aa/go.mod h1:2RVY1rIf+2J2o/IM9+vPq9RzmHDSseB7FoXiSNIUsoU= github.com/smartystreets/goconvey v0.0.0-20190330032615-68dc04aab96a/go.mod h1:syvi0/a8iFYH4r/RixwvyeAJjdLS9QV7WQ/tjFTllLA= -github.com/smartystreets/goconvey v0.0.0-20190731233626-505e41936337/go.mod h1:syvi0/a8iFYH4r/RixwvyeAJjdLS9QV7WQ/tjFTllLA= github.com/smartystreets/goconvey v1.6.4 h1:fv0U8FUIMPNf1L9lnHLvLhgicrIVChEkdzIKYqbNC9s= github.com/smartystreets/goconvey v1.6.4/go.mod h1:syvi0/a8iFYH4r/RixwvyeAJjdLS9QV7WQ/tjFTllLA= github.com/smola/gocompat v0.2.0/go.mod h1:1B0MlxbmoZNo3h8guHp8HztB3BSYR5itql9qtVc0ypY= github.com/soheilhy/cmux v0.1.4/go.mod h1:IM3LyeVVIOuxMH7sFAkER9+bJ4dT7Ms6E4xg4kGIyLM= +github.com/sonatard/noctx v0.0.1 h1:VC1Qhl6Oxx9vvWo3UDgrGXYCeKCe3Wbw7qAWL6FrmTY= +github.com/sonatard/noctx v0.0.1/go.mod h1:9D2D/EoULe8Yy2joDHJj7bv3sZoq9AaSb8B4lqBjiZI= +github.com/sony/gobreaker v0.4.1/go.mod h1:ZKptC7FHNvhBz7dN2LGjPVBz2sZJmc0/PkyDJOjmxWY= github.com/sourcegraph/annotate v0.0.0-20160123013949-f4cad6c6324d/go.mod h1:UdhH50NIW0fCiwBSr0co2m7BnFLdv4fQTgdqdJTHFeE= -github.com/sourcegraph/go-diff v0.5.1 h1:gO6i5zugwzo1RVTvgvfwCOSVegNuvnNi6bAD1QCmkHs= -github.com/sourcegraph/go-diff v0.5.1/go.mod h1:j2dHj3m8aZgQO8lMTcTnBcXkRRRqi34cd2MNlA9u1mE= +github.com/sourcegraph/go-diff v0.6.1 h1:hmA1LzxW0n1c3Q4YbrFgg4P99GSnebYa3x8gr0HZqLQ= +github.com/sourcegraph/go-diff v0.6.1/go.mod h1:iBszgVvyxdc8SFZ7gm69go2KDdt3ag071iBaWPF6cjs= github.com/sourcegraph/syntaxhighlight v0.0.0-20170531221838-bd320f5d308e/go.mod h1:HuIsMU8RRBOtsCgI77wP899iHVBQpCmg4ErYMZB+2IA= github.com/spacemonkeygo/openssl v0.0.0-20181017203307-c2dcc5cca94a/go.mod h1:7AyxJNCJ7SBZ1MfVQCWD6Uqo2oubI2Eq2y2eqf+A5r0= github.com/spacemonkeygo/spacelog v0.0.0-20180420211403-2296661a0572 h1:RC6RW7j+1+HkWaX/Yh71Ee5ZHaHYt7ZP4sQgUrm6cDU= @@ -850,68 +1689,107 @@ github.com/spacemonkeygo/spacelog v0.0.0-20180420211403-2296661a0572/go.mod h1:w github.com/spaolacci/murmur3 v0.0.0-20180118202830-f09979ecbc72/go.mod h1:JwIasOWyU6f++ZhiEuf87xNszmSA2myDM2Kzu9HwQUA= github.com/spaolacci/murmur3 v1.1.0 h1:7c1g84S4BPRrfL5Xrdp6fOJ206sU9y293DDHaoy0bLI= github.com/spaolacci/murmur3 v1.1.0/go.mod h1:JwIasOWyU6f++ZhiEuf87xNszmSA2myDM2Kzu9HwQUA= -github.com/spf13/afero v1.1.2 h1:m8/z1t7/fwjysjQRYbP0RD+bUIF/8tJwPdEZsI83ACI= github.com/spf13/afero v1.1.2/go.mod h1:j4pytiNVoe2o6bmDsKpLACNPDBIoEAkihy7loJ1B0CQ= -github.com/spf13/cast v1.3.0 h1:oget//CVOEoFewqQxwr0Ej5yjygnqGkvggSE/gB35Q8= +github.com/spf13/afero v1.3.3/go.mod h1:5KUK8ByomD5Ti5Artl0RtHeI5pTF7MIDuXL3yY520V4= +github.com/spf13/afero v1.6.0 h1:xoax2sJ2DT8S8xA2paPFjDCScCNeWsg75VG0DLRreiY= +github.com/spf13/afero v1.6.0/go.mod h1:Ai8FlHk4v/PARR026UzYexafAt9roJ7LcLMAmO6Z93I= github.com/spf13/cast v1.3.0/go.mod h1:Qx5cxh0v+4UWYiBimWS+eyWzqEqokIECu5etghLkUJE= -github.com/spf13/cobra v0.0.5 h1:f0B+LkLX6DtmRH1isoNA9VTtNUK9K8xYd28JNNfOv/s= +github.com/spf13/cast v1.4.1 h1:s0hze+J0196ZfEMTs80N7UlFt0BDuQ7Q+JDnHiMWKdA= +github.com/spf13/cast v1.4.1/go.mod h1:Qx5cxh0v+4UWYiBimWS+eyWzqEqokIECu5etghLkUJE= +github.com/spf13/cobra v0.0.3/go.mod h1:1l0Ry5zgKvJasoi3XT1TypsSe7PqH0Sj9dhYf7v3XqQ= github.com/spf13/cobra v0.0.5/go.mod h1:3K3wKZymM7VvHMDS9+Akkh4K60UwM26emMESw8tLCHU= -github.com/spf13/jwalterweatherman v1.0.0 h1:XHEdyB+EcvlqZamSM4ZOMGlc93t6AcsBEu9Gc1vn7yk= +github.com/spf13/cobra v1.3.0/go.mod h1:BrRVncBjOJa/eUcVVm9CE+oC6as8k+VYr4NY7WCi9V4= +github.com/spf13/cobra v1.4.0 h1:y+wJpx64xcgO1V+RcnwW0LEHxTKRi2ZDPSBjWnrg88Q= +github.com/spf13/cobra v1.4.0/go.mod h1:Wo4iy3BUC+X2Fybo0PDqwJIv3dNRiZLHQymsfxlB84g= github.com/spf13/jwalterweatherman v1.0.0/go.mod h1:cQK4TGJAtQXfYWX+Ddv3mKDzgVb68N+wFjFa4jdeBTo= +github.com/spf13/jwalterweatherman v1.1.0 h1:ue6voC5bR5F8YxI5S67j9i582FU4Qvo2bmqnqMYADFk= +github.com/spf13/jwalterweatherman v1.1.0/go.mod h1:aNWZUN0dPAAO/Ljvb5BEdw96iTZ0EXowPYD95IqWIGo= +github.com/spf13/pflag v1.0.1/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnInEg4= github.com/spf13/pflag v1.0.3/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnInEg4= github.com/spf13/pflag v1.0.5 h1:iy+VFUOCP1a+8yFto/drg2CJ5u0yRoB7fZw3DKv/JXA= github.com/spf13/pflag v1.0.5/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg= github.com/spf13/viper v1.3.2/go.mod h1:ZiWeW+zYFKm7srdB9IoDzzZXaJaI5eL9QjNiN/DMA2s= -github.com/spf13/viper v1.6.1 h1:VPZzIkznI1YhVMRi6vNFLHSwhnhReBfgTxIPccpfdZk= -github.com/spf13/viper v1.6.1/go.mod h1:t3iDnF5Jlj76alVNuyFBk5oUMCvsrkbvZK0WQdfDi5k= +github.com/spf13/viper v1.9.0/go.mod h1:+i6ajR7OX2XaiBkrcZJFK21htRk7eDeLg7+O6bhUPP4= +github.com/spf13/viper v1.10.0/go.mod h1:SoyBPwAtKDzypXNDFKN5kzH7ppppbGZtls1UpIy5AsM= +github.com/spf13/viper v1.10.1 h1:nuJZuYpG7gTj/XqiUwg8bA0cp1+M2mC3J4g5luUYBKk= +github.com/spf13/viper v1.10.1/go.mod h1:IGlFPqhNAPKRxohIzWpI5QEy4kuI7tcl5WvR+8qy1rU= github.com/src-d/envconfig v1.0.0/go.mod h1:Q9YQZ7BKITldTBnoxsE5gOeB5y66RyPXeue/R4aaNBc= +github.com/ssgreg/nlreturn/v2 v2.2.1 h1:X4XDI7jstt3ySqGU86YGAURbxw3oTDPK9sPEi6YEwQ0= +github.com/ssgreg/nlreturn/v2 v2.2.1/go.mod h1:E/iiPB78hV7Szg2YfRgyIrk1AD6JVMTRkkxBiELzh2I= +github.com/streadway/amqp v0.0.0-20190404075320-75d898a42a94/go.mod h1:AZpEONHx3DKn8O/DFsRAY58/XVQiIPMTMB1SddzLXVw= +github.com/streadway/amqp v0.0.0-20190827072141-edfb9018d271/go.mod h1:AZpEONHx3DKn8O/DFsRAY58/XVQiIPMTMB1SddzLXVw= +github.com/streadway/handy v0.0.0-20190108123426-d5acb3125c2a/go.mod h1:qNTQ5P5JnDBl6z3cMAg/SywNDC5ABu5ApDIw6lUbRmI= github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= github.com/stretchr/objx v0.2.0 h1:Hbg2NidpLE8veEBkEZTL3CvlkUIVzuU9jDplZO54c48= github.com/stretchr/objx v0.2.0/go.mod h1:qt09Ya8vawLte6SNmTgCsAVtYtaKzEcn8ATUoHMkEqE= +github.com/stretchr/testify v0.0.0-20170130113145-4d4bfba8f1d1/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs= +github.com/stretchr/testify v1.1.4/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs= github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs= github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4= github.com/stretchr/testify v1.5.1/go.mod h1:5W2xD1RspED5o8YsWQXVCued0rvSQ+mT+I5cxcmMvtA= -github.com/stretchr/testify v1.6.1 h1:hDPOHmpOpP40lSULcqw7IrRb/u7w6RpDC9399XyoNd0= github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= +github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= +github.com/stretchr/testify v1.7.1 h1:5TQK59W5E3v0r2duFAb7P95B6hEeOyEnHRa8MjYSMTY= +github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= github.com/subosito/gotenv v1.2.0 h1:Slr1R9HxAlEKefgq5jn9U+DnETlIUa6HfgEzj0g5d7s= github.com/subosito/gotenv v1.2.0/go.mod h1:N0PQaV/YGNqwC0u51sEeR/aUtSLEXKX9iv69rRypqCw= +github.com/sylvia7788/contextcheck v1.0.4 h1:MsiVqROAdr0efZc/fOCt0c235qm9XJqHtWwM+2h2B04= +github.com/sylvia7788/contextcheck v1.0.4/go.mod h1:vuPKJMQ7MQ91ZTqfdyreNKwZjyUg6KO+IebVyQDedZQ= github.com/syndtr/goleveldb v1.0.0/go.mod h1:ZVVdQEZoIme9iO1Ch2Jdy24qqXrMMOU6lpPAyBWyWuQ= github.com/tarm/serial v0.0.0-20180830185346-98f6abe2eb07/go.mod h1:kDXzergiv9cbyO7IOYJZWg1U88JhDg3PB6klq9Hg2pA= -github.com/tdakkota/asciicheck v0.0.0-20200416190851-d7f85be797a2 h1:Xr9gkxfOP0KQWXKNqmwe8vEeSUiUj4Rlee9CMVX2ZUQ= -github.com/tdakkota/asciicheck v0.0.0-20200416190851-d7f85be797a2/go.mod h1:yHp0ai0Z9gUljN3o0xMhYJnH/IcvkdTBOX2fmJ93JEM= -github.com/tetafro/godot v0.3.3 h1:uJjg8N+Ee10rAnaqJGet1WeI0YW4fiX9pKbwqnsqH6k= -github.com/tetafro/godot v0.3.3/go.mod h1:pT6/T8+h6//L/LwQcFc4C0xpfy1euZwzS1sHdrFCms0= -github.com/timakin/bodyclose v0.0.0-20190930140734-f7f2e9bca95e h1:RumXZ56IrCj4CL+g1b9OL/oH0QnsF976bC8xQFYUD5Q= -github.com/timakin/bodyclose v0.0.0-20190930140734-f7f2e9bca95e/go.mod h1:Qimiffbc6q9tBWlVV6x0P9sat/ao1xEkREYPPj9hphk= +github.com/tdakkota/asciicheck v0.1.1 h1:PKzG7JUTUmVspQTDqtkX9eSiLGossXTybutHwTXuO0A= +github.com/tdakkota/asciicheck v0.1.1/go.mod h1:yHp0ai0Z9gUljN3o0xMhYJnH/IcvkdTBOX2fmJ93JEM= +github.com/tenntenn/modver v1.0.1 h1:2klLppGhDgzJrScMpkj9Ujy3rXPUspSjAcev9tSEBgA= +github.com/tenntenn/modver v1.0.1/go.mod h1:bePIyQPb7UeioSRkw3Q0XeMhYZSMx9B8ePqg6SAMGH0= +github.com/tenntenn/text/transform v0.0.0-20200319021203-7eef512accb3 h1:f+jULpRQGxTSkNYKJ51yaw6ChIqO+Je8UqsTKN/cDag= +github.com/tenntenn/text/transform v0.0.0-20200319021203-7eef512accb3/go.mod h1:ON8b8w4BN/kE1EOhwT0o+d62W65a6aPw1nouo9LMgyY= +github.com/tetafro/godot v1.4.11 h1:BVoBIqAf/2QdbFmSwAWnaIqDivZdOV0ZRwEm6jivLKw= +github.com/tetafro/godot v1.4.11/go.mod h1:LR3CJpxDVGlYOWn3ZZg1PgNZdTUvzsZWu8xaEohUpn8= +github.com/timakin/bodyclose v0.0.0-20210704033933-f49887972144 h1:kl4KhGNsJIbDHS9/4U9yQo1UcPQM0kOMJHn29EoH/Ro= +github.com/timakin/bodyclose v0.0.0-20210704033933-f49887972144/go.mod h1:Qimiffbc6q9tBWlVV6x0P9sat/ao1xEkREYPPj9hphk= +github.com/tklauser/go-sysconf v0.3.9/go.mod h1:11DU/5sG7UexIrp/O6g35hrWzu0JxlwQ3LSFUzyeuhs= +github.com/tklauser/numcpus v0.3.0/go.mod h1:yFGUr7TUHQRAhyqBcEg0Ge34zDBAsIvJJcyE6boqnA8= +github.com/tmc/grpc-websocket-proxy v0.0.0-20170815181823-89b8d40f7ca8/go.mod h1:ncp9v5uamzpCO7NfCPTXjqaC+bZgJeR0sMTm6dMHP7U= github.com/tmc/grpc-websocket-proxy v0.0.0-20190109142713-0ad062ec5ee5/go.mod h1:ncp9v5uamzpCO7NfCPTXjqaC+bZgJeR0sMTm6dMHP7U= -github.com/tommy-muehle/go-mnd v1.3.1-0.20200224220436-e6f9a994e8fa h1:RC4maTWLKKwb7p1cnoygsbKIgNlJqSYBeAFON3Ar8As= -github.com/tommy-muehle/go-mnd v1.3.1-0.20200224220436-e6f9a994e8fa/go.mod h1:dSUh0FtTP8VhvkL1S+gUR1OKd9ZnSaozuI6r3m6wOig= -github.com/ugorji/go v1.1.4/go.mod h1:uQMGLiO92mf5W77hV/PUCpI3pbzQx3CRekS0kk+RGrc= +github.com/tmc/grpc-websocket-proxy v0.0.0-20200427203606-3cfed13b9966/go.mod h1:ncp9v5uamzpCO7NfCPTXjqaC+bZgJeR0sMTm6dMHP7U= +github.com/tomarrell/wrapcheck/v2 v2.5.0 h1:g27SGGHNoQdvHz4KZA9o4v09RcWzylR+b1yueE5ECiw= +github.com/tomarrell/wrapcheck/v2 v2.5.0/go.mod h1:68bQ/eJg55BROaRTbMjC7vuhL2OgfoG8bLp9ZyoBfyY= +github.com/tomasen/realip v0.0.0-20180522021738-f0c99a92ddce/go.mod h1:o8v6yHRoik09Xen7gje4m9ERNah1d1PPsVq1VEx9vE4= +github.com/tommy-muehle/go-mnd/v2 v2.5.0 h1:iAj0a8e6+dXSL7Liq0aXPox36FiN1dBbjA6lt9fl65s= +github.com/tommy-muehle/go-mnd/v2 v2.5.0/go.mod h1:WsUAkMJMYww6l/ufffCD3m+P7LEvr8TnZn9lwVDlgzw= +github.com/tv42/httpunix v0.0.0-20150427012821-b75d8614f926/go.mod h1:9ESjWnEqriFuLhtthL60Sar/7RFoluCcXsuvEwTV5KM= github.com/ugorji/go/codec v0.0.0-20181204163529-d75b2dcb6bc8/go.mod h1:VFNgLljTbGfSG7qAOspJ7OScBnGdDN/yBr0sguwnwf0= -github.com/ultraware/funlen v0.0.2 h1:Av96YVBwwNSe4MLR7iI/BIa3VyI7/djnto/pK3Uxbdo= -github.com/ultraware/funlen v0.0.2/go.mod h1:Dp4UiAus7Wdb9KUZsYWZEWiRzGuM2kXM1lPbfaF6xhA= -github.com/ultraware/whitespace v0.0.4 h1:If7Va4cM03mpgrNH9k49/VOicWpGoG70XPBFFODYDsg= -github.com/ultraware/whitespace v0.0.4/go.mod h1:aVMh/gQve5Maj9hQ/hg+F75lr/X5A89uZnzAmWSineA= -github.com/urfave/cli v1.20.0 h1:fDqGv3UG/4jbVl/QkFwEdddtEDjh/5Ov6X+0B/3bPaw= +github.com/ultraware/funlen v0.0.3 h1:5ylVWm8wsNwH5aWo9438pwvsK0QiqVuUrt9bn7S/iLA= +github.com/ultraware/funlen v0.0.3/go.mod h1:Dp4UiAus7Wdb9KUZsYWZEWiRzGuM2kXM1lPbfaF6xhA= +github.com/ultraware/whitespace v0.0.5 h1:hh+/cpIcopyMYbZNVov9iSxvJU3OYQg78Sfaqzi/CzI= +github.com/ultraware/whitespace v0.0.5/go.mod h1:aVMh/gQve5Maj9hQ/hg+F75lr/X5A89uZnzAmWSineA= github.com/urfave/cli v1.20.0/go.mod h1:70zkFmudgCuE/ngEzBv17Jvp/497gISqfk5gWijbERA= -github.com/uudashr/gocognit v1.0.1 h1:MoG2fZ0b/Eo7NXoIwCVFLG5JED3qgQz5/NEE+rOsjPs= -github.com/uudashr/gocognit v1.0.1/go.mod h1:j44Ayx2KW4+oB6SWMv8KsmHzZrOInQav7D3cQMJ5JUM= +github.com/urfave/cli v1.22.1/go.mod h1:Gos4lmkARVdJ6EkW0WaNv/tZAAMe9V7XWyB60NtXRu0= +github.com/urfave/cli v1.22.2 h1:gsqYFH8bb9ekPA12kRo0hfjngWQjkJPlN9R0N78BoUo= +github.com/urfave/cli v1.22.2/go.mod h1:Gos4lmkARVdJ6EkW0WaNv/tZAAMe9V7XWyB60NtXRu0= +github.com/urfave/cli/v2 v2.0.0/go.mod h1:SE9GqnLQmjVa0iPEY0f1w3ygNIYcIJ0OKPMoW2caLfQ= +github.com/uudashr/gocognit v1.0.5 h1:rrSex7oHr3/pPLQ0xoWq108XMU8s678FJcQ+aSfOHa4= +github.com/uudashr/gocognit v1.0.5/go.mod h1:wgYz0mitoKOTysqxTDMOUXg+Jb5SvtihkfmugIZYpEA= github.com/valyala/bytebufferpool v1.0.0/go.mod h1:6bBcMArwyJ5K/AmCkWv1jt77kVWyCJ6HpOuEn7z0Csc= -github.com/valyala/fasthttp v1.2.0/go.mod h1:4vX61m6KN+xDduDNwXrhIAVZaZaZiQ1luJk8LWSxF3s= -github.com/valyala/quicktemplate v1.2.0/go.mod h1:EH+4AkTd43SvgIbQHYu59/cJyxDoOVRUAfrukLPuGJ4= -github.com/valyala/tcplisten v0.0.0-20161114210144-ceec8f93295a/go.mod h1:v3UYOV9WzVtRmSR+PDvWpU/qWl4Wa5LApYYX4ZtKbio= +github.com/valyala/fasthttp v1.30.0/go.mod h1:2rsYD01CKFrjjsvFxx75KlEUNpWNBY9JWD3K/7o2Cus= +github.com/valyala/quicktemplate v1.7.0/go.mod h1:sqKJnoaOF88V07vkO+9FL8fb9uZg/VPSJnLYn+LmLk8= +github.com/valyala/tcplisten v1.0.0/go.mod h1:T0xQ8SeCZGxckz9qRXTfG43PvQ/mcWh7FwZEA7Ioqkc= github.com/viant/assertly v0.4.8/go.mod h1:aGifi++jvCrUaklKEKT0BU95igDNaqkvz+49uaYMPRU= github.com/viant/toolbox v0.24.0/go.mod h1:OxMCG57V0PXuIP2HNQrtJf2CjqdmbrOx5EkMILuUhzM= +github.com/viki-org/dnscache v0.0.0-20130720023526-c70c1f23c5d8/go.mod h1:dniwbG03GafCjFohMDmz6Zc6oCuiqgH6tGNyXTkHzXE= +github.com/warpfork/go-testmark v0.3.0 h1:Q81c4u7hT+BR5kNfNQhEF0VT2pmL7+Kk0wD+ORYl7iA= +github.com/warpfork/go-testmark v0.3.0/go.mod h1:jhEf8FVxd+F17juRubpmut64NEG6I2rgkUhlcqqXwE0= github.com/warpfork/go-wish v0.0.0-20180510122957-5ad1f5abf436/go.mod h1:x6AKhvSSexNrVSrViXSHUEbICjmGXhtgABaHIySUSGw= github.com/warpfork/go-wish v0.0.0-20190328234359-8b3e70f8e830/go.mod h1:x6AKhvSSexNrVSrViXSHUEbICjmGXhtgABaHIySUSGw= github.com/warpfork/go-wish v0.0.0-20200122115046-b9ea61034e4a h1:G++j5e0OC488te356JvdhaM8YS6nMsjLAYF7JxCv07w= github.com/warpfork/go-wish v0.0.0-20200122115046-b9ea61034e4a/go.mod h1:x6AKhvSSexNrVSrViXSHUEbICjmGXhtgABaHIySUSGw= github.com/whyrusleeping/base32 v0.0.0-20170828182744-c30ac30633cc/go.mod h1:r45hJU7yEoA81k6MWNhpMj/kms0n14dkzkxYHoB96UM= github.com/whyrusleeping/cbor-gen v0.0.0-20200123233031-1cdf64d27158/go.mod h1:Xj/M2wWU+QdTdRbu/L/1dIZY8/Wb2K9pAhtroQuxJJI= -github.com/whyrusleeping/cbor-gen v0.0.0-20200402171437-3d27c146c105 h1:Sh6UG5dW5xW8Ek2CtRGq4ipdEvvx9hOyBJjEGyTYDl0= -github.com/whyrusleeping/cbor-gen v0.0.0-20200402171437-3d27c146c105/go.mod h1:Xj/M2wWU+QdTdRbu/L/1dIZY8/Wb2K9pAhtroQuxJJI= +github.com/whyrusleeping/cbor-gen v0.0.0-20200710004633-5379fc63235d/go.mod h1:fgkXqYy7bV2cFeIEOkVTZS/WjXARfBqSH6Q2qHL33hQ= +github.com/whyrusleeping/cbor-gen v0.0.0-20210219115102-f37d292932f2 h1:bsUlNhdmbtlfdLVXAVfuvKQ01RnWAM09TVrJkI7NZs4= +github.com/whyrusleeping/cbor-gen v0.0.0-20210219115102-f37d292932f2/go.mod h1:fgkXqYy7bV2cFeIEOkVTZS/WjXARfBqSH6Q2qHL33hQ= github.com/whyrusleeping/chunker v0.0.0-20181014151217-fe64bd25879f h1:jQa4QT2UP9WYv2nzyawpKMOCl+Z/jW7djv2/J50lj9E= github.com/whyrusleeping/chunker v0.0.0-20181014151217-fe64bd25879f/go.mod h1:p9UJB6dDgdPgMJZs7UjUOdulKyRr9fqkS+6JKAInPy8= github.com/whyrusleeping/go-ctrlnet v0.0.0-20180313164037-f564fbbdaa95/go.mod h1:SJqKCCPXRfBFCwXjfNT/skfsceF7+MBFLI2OrvuRA7g= @@ -927,36 +1805,86 @@ github.com/whyrusleeping/multiaddr-filter v0.0.0-20160516205228-e903e4adabd7/go. github.com/whyrusleeping/timecache v0.0.0-20160911033111-cfcb2f1abfee/go.mod h1:m2aV4LZI4Aez7dP5PMyVKEHhUyEJ/RjmPEDOpDvudHg= github.com/x-cray/logrus-prefixed-formatter v0.5.2/go.mod h1:2duySbKsL6M18s5GU7VPsoEPHyzalCE06qoARUCeBBE= github.com/xiang90/probing v0.0.0-20190116061207-43a291ad63a2/go.mod h1:UETIi67q53MR2AWcXfiuqkDkRtnGDLqkBTpCHuJHxtU= +github.com/xo/terminfo v0.0.0-20210125001918-ca9a967f8778/go.mod h1:2MuV+tbUrU1zIOPMxZ5EncGwgmMJsa+9ucAQZXxsObs= github.com/xordataexchange/crypt v0.0.3-0.20170626215501-b2862e3d0a77/go.mod h1:aYKd//L2LvnjZzWKhF00oedf4jCCReLcmhLdhm1A27Q= +github.com/yagipy/maintidx v1.0.0 h1:h5NvIsCz+nRDapQ0exNv4aJ0yXSI0420omVANTv3GJM= +github.com/yagipy/maintidx v1.0.0/go.mod h1:0qNf/I/CCZXSMhsRsrEPDZ+DkekpKLXAJfsTACwgXLk= +github.com/yeya24/promlinter v0.1.1-0.20210918184747-d757024714a1 h1:YAaOqqMTstELMMGblt6yJ/fcOt4owSYuw3IttMnKfAM= +github.com/yeya24/promlinter v0.1.1-0.20210918184747-d757024714a1/go.mod h1:rs5vtZzeBHqqMwXqFScncpCF6u06lezhZepno9AB1Oc= +github.com/yudai/gojsondiff v1.0.0/go.mod h1:AY32+k2cwILAkW1fbgxQ5mUmMiZFgLIV+FBNExI05xg= +github.com/yudai/golcs v0.0.0-20170316035057-ecda9a501e82/go.mod h1:lgjkn3NuSvDfVJdfcVVdX+jpBxNmX4rDAzaS45IcYoM= +github.com/yudai/pp v2.0.1+incompatible/go.mod h1:PuxR/8QJ7cyCkFp/aUDS+JY727OFEZkTdatxwunjIkc= github.com/yuin/goldmark v1.1.25/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= -go.etcd.io/bbolt v1.3.2/go.mod h1:IbVyRI1SCnLcuJnV2u8VeU0CEYM7e686BmAb1XKL+uU= +github.com/yuin/goldmark v1.1.32/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= +github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= +github.com/yuin/goldmark v1.3.5/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k= +github.com/yuin/goldmark v1.4.0/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k= +github.com/yuin/goldmark v1.4.1/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k= +github.com/yusufpapurcu/wmi v1.2.2/go.mod h1:SBZ9tNy3G9/m5Oi98Zks0QjeHVDvuK0qfxQmPyzfmi0= +gitlab.com/bosi/decorder v0.2.1 h1:ehqZe8hI4w7O4b1vgsDZw1YU1PE7iJXrQWFMsocbQ1w= +gitlab.com/bosi/decorder v0.2.1/go.mod h1:6C/nhLSbF6qZbYD8bRmISBwc6vcWdNsiIBkRvjJFrH0= +go.etcd.io/bbolt v1.3.3/go.mod h1:IbVyRI1SCnLcuJnV2u8VeU0CEYM7e686BmAb1XKL+uU= +go.etcd.io/bbolt v1.3.4/go.mod h1:G5EMThwa9y8QZGBClrRx5EY+Yw9kAhnjy3bSjsnlVTQ= +go.etcd.io/etcd v0.0.0-20191023171146-3cf2f69b5738/go.mod h1:dnLIgRNXwCJa5e+c6mIZCrds/GIG4ncV9HhK5PX7jPg= +go.etcd.io/etcd v0.0.0-20200513171258-e048e166ab9c/go.mod h1:xCI7ZzBfRuGgBXyXO6yfWfDmlWd35khcWpUa4L0xI/k= +go.etcd.io/etcd/api/v3 v3.5.0/go.mod h1:cbVKeC6lCfl7j/8jBhAK6aIYO9XOjdptoxU/nLQcPvs= +go.etcd.io/etcd/api/v3 v3.5.1/go.mod h1:cbVKeC6lCfl7j/8jBhAK6aIYO9XOjdptoxU/nLQcPvs= +go.etcd.io/etcd/client/pkg/v3 v3.5.0/go.mod h1:IJHfcCEKxYu1Os13ZdwCwIUTUVGYTSAM3YSwc9/Ac1g= +go.etcd.io/etcd/client/pkg/v3 v3.5.1/go.mod h1:IJHfcCEKxYu1Os13ZdwCwIUTUVGYTSAM3YSwc9/Ac1g= +go.etcd.io/etcd/client/v2 v2.305.0/go.mod h1:h9puh54ZTgAKtEbut2oe9P4L/oqKCVB6xsXlzd7alYQ= +go.etcd.io/etcd/client/v2 v2.305.1/go.mod h1:pMEacxZW7o8pg4CrFE7pquyCJJzZvkvdD2RibOCCCGs= +go.mozilla.org/mozlog v0.0.0-20170222151521-4bb13139d403/go.mod h1:jHoPAGnDrCy6kaI2tAze5Prf0Nr0w/oNkROt2lw3n3o= go.opencensus.io v0.18.0/go.mod h1:vKdFvxhtzZ9onBp9VKHK8z/sRpBMnKAsufL7wlDrCOA= +go.opencensus.io v0.20.1/go.mod h1:6WKK9ahsWS3RSO+PY9ZHZUfv2irvY6gN279GOPZjmmk= +go.opencensus.io v0.20.2/go.mod h1:6WKK9ahsWS3RSO+PY9ZHZUfv2irvY6gN279GOPZjmmk= go.opencensus.io v0.21.0/go.mod h1:mSImk1erAIZhrmZN+AvHh14ztQfjbGwt4TtuofqLduU= +go.opencensus.io v0.22.0/go.mod h1:+kGneAE2xo2IficOXnaByMWTGM9T73dGwxeWcUqIpI8= go.opencensus.io v0.22.1/go.mod h1:Ap50jQcDJrx6rB6VgeeFPtuPIf3wMRvRfrfYDO6+BmA= go.opencensus.io v0.22.2/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw= -go.opencensus.io v0.22.3 h1:8sGtKOrtQqkN1bp2AtX+misvLIlOmsEsNd+9NIcPEm8= go.opencensus.io v0.22.3/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw= +go.opencensus.io v0.22.4/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw= +go.opencensus.io v0.22.5/go.mod h1:5pWMHQbX5EPX2/62yrJeAkowc+lfs/XD7Uxpq3pI6kk= +go.opencensus.io v0.23.0/go.mod h1:XItmlyltB5F7CS4xOC1DcqMoFqwtC6OG2xF7mCv7P7E= +go.opentelemetry.io/proto/otlp v0.7.0/go.mod h1:PqfVotwruBrMGOCsRd/89rSnXhoiJIqeYNgFYFoEGnI= +go.uber.org/atomic v1.3.2/go.mod h1:gD2HeocX3+yG+ygLZcrzQJaqmWj9AIm7n08wl/qW/PE= go.uber.org/atomic v1.4.0/go.mod h1:gD2HeocX3+yG+ygLZcrzQJaqmWj9AIm7n08wl/qW/PE= go.uber.org/atomic v1.5.0/go.mod h1:sABNBOSYdrvTF6hTgEIbc7YasKWGhgEQZyfxyTvoXHQ= -go.uber.org/atomic v1.6.0 h1:Ezj3JGmsOnG1MoRWQkPBsKLe9DwWD9QeXzTRzzldNVk= go.uber.org/atomic v1.6.0/go.mod h1:sABNBOSYdrvTF6hTgEIbc7YasKWGhgEQZyfxyTvoXHQ= -go.uber.org/goleak v1.0.0 h1:qsup4IcBdlmsnGfqyLl4Ntn3C2XCCuKAE7DwHpScyUo= +go.uber.org/atomic v1.7.0/go.mod h1:fEN4uk6kAWBTFdckzkM89CLk9XfWZrxpCo0nPH17wJc= +go.uber.org/atomic v1.9.0 h1:ECmE8Bn/WFTYwEW/bpKD3M8VtR/zQVbavAoalC1PYyE= +go.uber.org/atomic v1.9.0/go.mod h1:fEN4uk6kAWBTFdckzkM89CLk9XfWZrxpCo0nPH17wJc= go.uber.org/goleak v1.0.0/go.mod h1:8a7PlsEVH3e/a/GLqe5IIrQx6GzcnRmZEufDUTk4A7A= +go.uber.org/goleak v1.1.10/go.mod h1:8a7PlsEVH3e/a/GLqe5IIrQx6GzcnRmZEufDUTk4A7A= +go.uber.org/goleak v1.1.11-0.20210813005559-691160354723/go.mod h1:cwTWslyiVhfpKIDGSZEM2HlOvcqm+tG4zioyIeLoqMQ= +go.uber.org/goleak v1.1.11/go.mod h1:cwTWslyiVhfpKIDGSZEM2HlOvcqm+tG4zioyIeLoqMQ= +go.uber.org/goleak v1.1.12 h1:gZAh5/EyT/HQwlpkCy6wTpqfH9H8Lz8zbm3dZh+OyzA= +go.uber.org/goleak v1.1.12/go.mod h1:cwTWslyiVhfpKIDGSZEM2HlOvcqm+tG4zioyIeLoqMQ= go.uber.org/multierr v1.1.0/go.mod h1:wR5kodmAFQ0UK8QlbwjlSNy0Z68gJhDJUG5sjR94q/0= +go.uber.org/multierr v1.3.0/go.mod h1:VgVr7evmIr6uPjLBxg28wmKNXyqE9akIJ5XnfpiKl+4= go.uber.org/multierr v1.4.0/go.mod h1:VgVr7evmIr6uPjLBxg28wmKNXyqE9akIJ5XnfpiKl+4= -go.uber.org/multierr v1.5.0 h1:KCa4XfM8CWFCpxXRGok+Q0SS/0XBhMDbHHGABQLvD2A= go.uber.org/multierr v1.5.0/go.mod h1:FeouvMocqHpRaaGuG9EjoKcStLC43Zu/fmqdUMPcKYU= -go.uber.org/tools v0.0.0-20190618225709-2cfd321de3ee h1:0mgffUl7nfd+FpvXMVz4IDEaUSmT1ysygQC7qYo7sG4= +go.uber.org/multierr v1.6.0/go.mod h1:cdWPpRnG4AhwMwsgIHip0KRBQjJy5kYEpYjJxpXp9iU= +go.uber.org/multierr v1.7.0/go.mod h1:7EAYxJLBy9rStEaz58O2t4Uvip6FSURkq8/ppBp95ak= +go.uber.org/multierr v1.8.0 h1:dg6GjLku4EH+249NNmoIciG9N/jURbDG+pFlTkhzIC8= +go.uber.org/multierr v1.8.0/go.mod h1:7EAYxJLBy9rStEaz58O2t4Uvip6FSURkq8/ppBp95ak= go.uber.org/tools v0.0.0-20190618225709-2cfd321de3ee/go.mod h1:vJERXedbb3MVM5f9Ejo0C68/HhF8uaILCdgjnY+goOA= go.uber.org/zap v1.10.0/go.mod h1:vwi/ZaCAaUcBkycHslxD9B2zi4UTXhF60s6SWpuDF0Q= +go.uber.org/zap v1.13.0/go.mod h1:zwrFLgMcdUuIBviXEYEH1YKNaOBnKXsx2IPda5bBwHM= go.uber.org/zap v1.14.1/go.mod h1:Mb2vm2krFEG5DV0W9qcHBYFtp/Wku1cvYaqPsS/WYfc= -go.uber.org/zap v1.15.0 h1:ZZCA22JRF2gQE5FoNmhmrf7jeJJ2uhqDUNRYKm8dvmM= go.uber.org/zap v1.15.0/go.mod h1:Mb2vm2krFEG5DV0W9qcHBYFtp/Wku1cvYaqPsS/WYfc= +go.uber.org/zap v1.16.0/go.mod h1:MA8QOfq0BHJwdXa996Y4dYkAqRKB8/1K1QMMZVaNZjQ= +go.uber.org/zap v1.17.0/go.mod h1:MXVU+bhUf/A7Xi2HNOnopQOrmycQ5Ih87HtOu4q5SSo= +go.uber.org/zap v1.19.0/go.mod h1:xg/QME4nWcxGxrpdeYfq7UvYrLh66cuVKdrbD1XF/NI= +go.uber.org/zap v1.19.1/go.mod h1:j3DNczoxDZroyBnOT1L/Q79cfUMGZxlv/9dzN7SM1rI= +go.uber.org/zap v1.21.0 h1:WefMeulhovoZ2sYXz7st6K0sLj7bBhpiFaud4r4zST8= +go.uber.org/zap v1.21.0/go.mod h1:wjWOCqI0f2ZZrJF/UufIOkiC8ii6tm1iqIsLo76RfJw= go4.org v0.0.0-20180809161055-417644f6feb5/go.mod h1:MkTOUMDaeVYJUOUsaDXIhWPZYa1yOyC1qaOBpL57BhE= golang.org/x/build v0.0.0-20190111050920-041ab4dc3f9d/go.mod h1:OWs+y06UdEOHN4y+MfF/py+xQ/tYqIWW03b70/CG9Rw= golang.org/x/crypto v0.0.0-20170930174604-9419663f5a44/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= +golang.org/x/crypto v0.0.0-20180501155221-613d6eafa307/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= golang.org/x/crypto v0.0.0-20180904163835-0709b304e793/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= +golang.org/x/crypto v0.0.0-20181029021203-45a5f77698d3/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= golang.org/x/crypto v0.0.0-20181030102418-4d3f4d9ffa16/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= golang.org/x/crypto v0.0.0-20181203042331-505ab145d0a9/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= golang.org/x/crypto v0.0.0-20190211182817-74369b46fc67/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= @@ -968,189 +1896,640 @@ golang.org/x/crypto v0.0.0-20190426145343-a29dc8fdc734/go.mod h1:yigFU9vqHzYiE8U golang.org/x/crypto v0.0.0-20190510104115-cbcb75029529/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= golang.org/x/crypto v0.0.0-20190513172903-22d7a77e9e5f/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= golang.org/x/crypto v0.0.0-20190530122614-20be4c3c3ed5/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= +golang.org/x/crypto v0.0.0-20190605123033-f99c8df09eb5/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= golang.org/x/crypto v0.0.0-20190611184440-5c40567a22f8/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= golang.org/x/crypto v0.0.0-20190618222545-ea8f1a30c443/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= +golang.org/x/crypto v0.0.0-20190701094942-4def268fd1a4/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= +golang.org/x/crypto v0.0.0-20190820162420-60c769a6c586/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= golang.org/x/crypto v0.0.0-20190923035154-9ee001bba392/go.mod h1:/lpIB1dKB+9EgE3H3cr1v9wB50oz8l4C4h62xy7jSTY= golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= -golang.org/x/crypto v0.0.0-20200117160349-530e935923ad/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= +golang.org/x/crypto v0.0.0-20200115085410-6d4e4cb37c7d/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= golang.org/x/crypto v0.0.0-20200221231518-2aa609cf4a9d/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= -golang.org/x/crypto v0.0.0-20200423211502-4bdfaf469ed5/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= -golang.org/x/crypto v0.0.0-20200510223506-06a226fb4e37 h1:cg5LA/zNPRzIXIWSCxQW10Rvpy94aQh3LT/ShoCpkHw= golang.org/x/crypto v0.0.0-20200510223506-06a226fb4e37/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= +golang.org/x/crypto v0.0.0-20200602180216-279210d13fed/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= +golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= +golang.org/x/crypto v0.0.0-20200820211705-5c72a883971a/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= +golang.org/x/crypto v0.0.0-20201221181555-eec23a3978ad/go.mod h1:jdWPYTVW3xRLrWPugEBEK3UY2ZEsg3UU495nc5E+M+I= +golang.org/x/crypto v0.0.0-20210220033148-5ea612d1eb83/go.mod h1:jdWPYTVW3xRLrWPugEBEK3UY2ZEsg3UU495nc5E+M+I= +golang.org/x/crypto v0.0.0-20210322153248-0c34fe9e7dc2/go.mod h1:T9bdIzuCu7OtxOm1hfPfRQxPLYneinmdGuTeoZ9dtd4= +golang.org/x/crypto v0.0.0-20210506145944-38f3c27a63bf/go.mod h1:P+XmwS30IXTQdn5tA2iutPOUgjI07+tq3H3K9MVA1s8= +golang.org/x/crypto v0.0.0-20210513164829-c07d793c2f9a/go.mod h1:P+XmwS30IXTQdn5tA2iutPOUgjI07+tq3H3K9MVA1s8= +golang.org/x/crypto v0.0.0-20210813211128-0a44fdfbc16e/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= +golang.org/x/crypto v0.0.0-20210817164053-32db794688a5/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= +golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= +golang.org/x/crypto v0.0.0-20220214200702-86341886e292/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4= +golang.org/x/crypto v0.0.0-20220411220226-7b82a4e95df4 h1:kUhD7nTDoI3fVd9G4ORWrbV5NY0liEs/Jg2pv5f+bBA= +golang.org/x/crypto v0.0.0-20220411220226-7b82a4e95df4/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4= golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= +golang.org/x/exp v0.0.0-20190306152737-a1d7652674e8/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= +golang.org/x/exp v0.0.0-20190510132918-efd6b22b2522/go.mod h1:ZjyILWgesfNpC6sMxTJOJm9Kp84zZh5NQWvqDGG3Qr8= +golang.org/x/exp v0.0.0-20190829153037-c13cbed26979/go.mod h1:86+5VVa7VpoJ4kLfm080zCjGlMRFzhUhsZKEZO7MGek= +golang.org/x/exp v0.0.0-20191030013958-a1ab85dbe136/go.mod h1:JXzH8nQsPlswgeRAPE3MuO9GYsAcnJvJ4vnMwN/5qkY= +golang.org/x/exp v0.0.0-20191129062945-2f5052295587/go.mod h1:2RIsYlXP63K8oxa1u096TMicItID8zy7Y6sNkU49FU4= +golang.org/x/exp v0.0.0-20191227195350-da58074b4299/go.mod h1:2RIsYlXP63K8oxa1u096TMicItID8zy7Y6sNkU49FU4= +golang.org/x/exp v0.0.0-20200119233911-0405dc783f0a/go.mod h1:2RIsYlXP63K8oxa1u096TMicItID8zy7Y6sNkU49FU4= +golang.org/x/exp v0.0.0-20200207192155-f17229e696bd/go.mod h1:J/WKrq2StrnmMY6+EHIKF9dgMWnmCNThgcyBT1FY9mM= +golang.org/x/exp v0.0.0-20200224162631-6cc2880d07d6/go.mod h1:3jZMyOhIsHpP37uCMkUooju7aAi5cS1Q23tOzKc+0MU= +golang.org/x/exp v0.0.0-20200331195152-e8c3332aa8e5/go.mod h1:4M0jN8W1tt0AVLNr8HDosyJCDCDuyL9N9+3m7wDWgKw= +golang.org/x/image v0.0.0-20190227222117-0694c2d4d067/go.mod h1:kZ7UVZpmo3dzQBMxlp+ypCbDeSB+sBbTgSJuh5dn5js= +golang.org/x/image v0.0.0-20190802002840-cff245a6509b/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0= golang.org/x/lint v0.0.0-20180702182130-06c8688daad7/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE= golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE= golang.org/x/lint v0.0.0-20190227174305-5b3e6a55c961/go.mod h1:wehouNa3lNwaWXcvxsM5YxQ5yQlVC4a0KAMCusXpPoU= +golang.org/x/lint v0.0.0-20190301231843-5614ed5bae6f/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE= golang.org/x/lint v0.0.0-20190313153728-d0100b6bd8b3/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= +golang.org/x/lint v0.0.0-20190409202823-959b441ac422/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= +golang.org/x/lint v0.0.0-20190909230951-414d861bb4ac/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= golang.org/x/lint v0.0.0-20190930215403-16217165b5de/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= -golang.org/x/lint v0.0.0-20191125180803-fdd1cda4f05f h1:J5lckAjkw6qYlOZNj90mLYNTEKDvWeuc1yieZ8qUzUE= golang.org/x/lint v0.0.0-20191125180803-fdd1cda4f05f/go.mod h1:5qLYkcX4OjUUV8bRuDixDT3tpyyb+LUpUlRWLxfhWrs= +golang.org/x/lint v0.0.0-20200130185559-910be7a94367/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY= +golang.org/x/lint v0.0.0-20200302205851-738671d3881b/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY= +golang.org/x/lint v0.0.0-20201208152925-83fdc39ff7b5/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY= +golang.org/x/lint v0.0.0-20210508222113-6edffad5e616/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY= +golang.org/x/mobile v0.0.0-20190312151609-d3739f865fa6/go.mod h1:z+o9i4GpDbdi3rU15maQ/Ox0txvL9dWGYEHz965HBQE= +golang.org/x/mobile v0.0.0-20190719004257-d2bd2a29d028/go.mod h1:E/iHnbuqvinMTCcRqshq8CkpyQDoeVncDDYHnLhea+o= golang.org/x/mod v0.0.0-20190513183733-4bf6d317e70e/go.mod h1:mXi4GBBbnImb6dmsKGUJ2LatrhH/nqhxcFungHvyanc= +golang.org/x/mod v0.1.0/go.mod h1:0QHyrYULN0/3qlju5TqG8bIK38QM8yzMo5ekMj3DlcY= golang.org/x/mod v0.1.1-0.20191105210325-c90efee705ee/go.mod h1:QqPTAvyqsEbceGzBzNggFXnrqF1CaUcvgkdR5Ot7KZg= -golang.org/x/mod v0.2.0 h1:KU7oHjnv3XNWfa5COkzUifxZmxp1TyI7ImMXqFxLwvQ= +golang.org/x/mod v0.1.1-0.20191107180719-034126e5016b/go.mod h1:QqPTAvyqsEbceGzBzNggFXnrqF1CaUcvgkdR5Ot7KZg= golang.org/x/mod v0.2.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= +golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= +golang.org/x/mod v0.4.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= +golang.org/x/mod v0.4.1/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= +golang.org/x/mod v0.4.2/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= +golang.org/x/mod v0.5.0/go.mod h1:5OXOZSfqPIIbmVBIIKWRFfZjPR0E5r58TLhUjH0a2Ro= +golang.org/x/mod v0.5.1/go.mod h1:5OXOZSfqPIIbmVBIIKWRFfZjPR0E5r58TLhUjH0a2Ro= +golang.org/x/mod v0.6.0-dev.0.20220106191415-9b9b3d81d5e3 h1:kQgndtyPBW/JIYERgdxfwMYh3AVStj88WQTlNDi2a+o= +golang.org/x/mod v0.6.0-dev.0.20220106191415-9b9b3d81d5e3/go.mod h1:3p9vT2HGsQu2K1YbXdKPJLVgG5VJdoTa1poYQBtP1AY= +golang.org/x/net v0.0.0-20180719180050-a680a1efc54d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20180906233101-161cd47e91fd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= -golang.org/x/net v0.0.0-20180911220305-26e67e76b6c3/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20181011144130-49bb7cea24b1/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20181023162649-9b4f9f5ad519/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20181029044818-c44066c5c816/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20181106065722-10aee1819953/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20181114220301-adae6a3d119a/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20181201002055-351d144fa1fc/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20181220203305-927f97764cc3/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20190108225652-1e06a53dbb7e/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20190125091013-d26f9f9a57f3/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20190213061140-3a22650c66bd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20190227160552-c95aed5357e7/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= -golang.org/x/net v0.0.0-20190228165749-92fc7df08ae7/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= golang.org/x/net v0.0.0-20190313220215-9f648a60d977/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= +golang.org/x/net v0.0.0-20190501004415-9ce7a6920f09/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= +golang.org/x/net v0.0.0-20190503192946-f4e77d36d62c/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= golang.org/x/net v0.0.0-20190522155817-f3200d17e092/go.mod h1:HSz+uSET+XFnRR8LxR5pz3Of3rY3CfYBVs4xY44aLks= +golang.org/x/net v0.0.0-20190603091049-60506f45cf65/go.mod h1:HSz+uSET+XFnRR8LxR5pz3Of3rY3CfYBVs4xY44aLks= golang.org/x/net v0.0.0-20190611141213-3f473d35a33a/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20190613194153-d28f0bde5980/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20190628185345-da137c7871d7/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20190724013045-ca1201d0de80/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20190813141303-74dc4d7220e7/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20190923162816-aa69164e4478/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20191002035440-2ec189313ef0/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20191209160850-c0dbc17a3553/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20200114155413-6afb5195e5aa/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20200202094626-16171245cfb2/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20200222125558-5a598a2470a0/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20200226121028-0de0cce0169b/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= -golang.org/x/net v0.0.0-20200519113804-d87ec0cfa476 h1:E7ct1C6/33eOdrGZKMoyntcEvs2dwZnDe30crG5vpYU= -golang.org/x/net v0.0.0-20200519113804-d87ec0cfa476/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= +golang.org/x/net v0.0.0-20200301022130-244492dfa37a/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20200324143707-d3edc9973b7e/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= +golang.org/x/net v0.0.0-20200421231249-e086a090c8fd/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= +golang.org/x/net v0.0.0-20200501053045-e0ff5e5a1de5/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= +golang.org/x/net v0.0.0-20200506145744-7e3656a0809f/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= +golang.org/x/net v0.0.0-20200513185701-a91f0712d120/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= +golang.org/x/net v0.0.0-20200520004742-59133d7f0dd7/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= +golang.org/x/net v0.0.0-20200520182314-0ba52f642ac2/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= +golang.org/x/net v0.0.0-20200625001655-4c5254603344/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA= +golang.org/x/net v0.0.0-20200707034311-ab3426394381/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA= +golang.org/x/net v0.0.0-20200822124328-c89045814202/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA= +golang.org/x/net v0.0.0-20200904194848-62affa334b73/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA= +golang.org/x/net v0.0.0-20201021035429-f5854403a974/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= +golang.org/x/net v0.0.0-20201031054903-ff519b6c9102/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= +golang.org/x/net v0.0.0-20201110031124-69a78807bb2b/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= +golang.org/x/net v0.0.0-20201209123823-ac852fbbde11/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= +golang.org/x/net v0.0.0-20210119194325-5f4716e94777/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= +golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= +golang.org/x/net v0.0.0-20210316092652-d523dce5a7f4/go.mod h1:RBQZq4jEuRlivfhVLdyRGr576XBO4/greRjx4P4O3yc= +golang.org/x/net v0.0.0-20210405180319-a5a99cb37ef4/go.mod h1:p54w0d4576C0XHj96bSt6lcn1PtDYWL6XObtHCRCNQM= +golang.org/x/net v0.0.0-20210410081132-afb366fc7cd1/go.mod h1:9tjilg8BloeKEkVJvy7fQ90B1CfIiPueXVOjqfkSzI8= +golang.org/x/net v0.0.0-20210423184538-5f58ad60dda6/go.mod h1:OJAsFXCWl8Ukc7SiCT/9KSuxbyM7479/AVlXFRxuMCk= +golang.org/x/net v0.0.0-20210428140749-89ef3d95e781/go.mod h1:OJAsFXCWl8Ukc7SiCT/9KSuxbyM7479/AVlXFRxuMCk= +golang.org/x/net v0.0.0-20210503060351-7fd8e65b6420/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= +golang.org/x/net v0.0.0-20210510120150-4163338589ed/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= +golang.org/x/net v0.0.0-20210525063256-abc453219eb5/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= +golang.org/x/net v0.0.0-20210726213435-c6fcb2dbf985/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= +golang.org/x/net v0.0.0-20210805182204-aaa1db679c0d/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= +golang.org/x/net v0.0.0-20210813160813-60bc85c4be6d/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= +golang.org/x/net v0.0.0-20211015210444-4f30a5c0130f/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= +golang.org/x/net v0.0.0-20211112202133-69e39bad7dc2/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= +golang.org/x/net v0.0.0-20220127200216-cd36cc0744dd/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk= +golang.org/x/net v0.0.0-20220225172249-27dd8689420f/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk= +golang.org/x/net v0.0.0-20220418201149-a630d4f3e7a2 h1:6mzvA99KwZxbOrxww4EvWVQUnN1+xEu9tafK5ZxkYeA= +golang.org/x/net v0.0.0-20220418201149-a630d4f3e7a2/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk= golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= golang.org/x/oauth2 v0.0.0-20181017192945-9dcd33a902f4/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= golang.org/x/oauth2 v0.0.0-20181203162652-d668ce993890/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= +golang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= +golang.org/x/oauth2 v0.0.0-20191202225959-858c2ad4c8b6/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= +golang.org/x/oauth2 v0.0.0-20200107190931-bf48bf16ab8d/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= +golang.org/x/oauth2 v0.0.0-20200902213428-5d25da1a8d43/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= +golang.org/x/oauth2 v0.0.0-20201109201403-9fd604954f58/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= +golang.org/x/oauth2 v0.0.0-20201208152858-08078c50e5b5/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= +golang.org/x/oauth2 v0.0.0-20210218202405-ba52d332ba99/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= +golang.org/x/oauth2 v0.0.0-20210220000619-9bb904979d93/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= +golang.org/x/oauth2 v0.0.0-20210313182246-cd4f82c27b84/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= +golang.org/x/oauth2 v0.0.0-20210514164344-f6687ab2804c/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= +golang.org/x/oauth2 v0.0.0-20210628180205-a41e5a781914/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= +golang.org/x/oauth2 v0.0.0-20210805134026-6f1e6394065a/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= +golang.org/x/oauth2 v0.0.0-20210819190943-2bc19b11175f/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= +golang.org/x/oauth2 v0.0.0-20211005180243-6b3c2da341f1/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= +golang.org/x/oauth2 v0.0.0-20211104180415-d3ed0bb246c8/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= +golang.org/x/oauth2 v0.0.0-20220223155221-ee480838109b/go.mod h1:DAh4E804XQdzx2j+YRIaUnCqCV2RuMz24cGBJ5QYIrc= golang.org/x/perf v0.0.0-20180704124530-6e6d33e29852/go.mod h1:JLpeXjPJfIyPr5TlbXLkXWLhP8nz10XfvxElABhCtcw= golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20190227155943-e225da77a7e6/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20190412183630-56d357773e84/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= -golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e h1:vcxGaoTs7kV8m5Np9uUNQin4BrLOthgV7252N8V+FwY= golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20200317015054-43a5402ce75a/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20200625203802-6e8e738ad208/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20201207232520-09787c993a3a/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20210220032951-036812b2e83c h1:5KslGYwFpkhGh+Q16bwMP3cOontH8FOep7tGV86Y7SQ= +golang.org/x/sync v0.0.0-20210220032951-036812b2e83c/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sys v0.0.0-20180810173357-98c5dad5d1a0/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20180823144017-11551d06cbcc/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20180905080454-ebe1bf3edb33/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20180909124046-d0be0721c37e/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20181026203630-95b1ffbd15a5/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20181029174526-d69651ed3497/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20181107165924-66b7b1311ac8/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20181116152217-5ac8a444bdc5/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20181122145206-62eef0e2fa9b/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20181205085412-a5c9d58dba9a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20190219092855-153ac476189d/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20190222072716-a9d3bda3a223/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20190228124157-a34e9553db1e/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20190302025703-b6889370fb10/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20190312061237-fead79001313/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190316082340-a2f829d7f35f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190405154228-4b34438f7a67/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190422165155-953cdadca894/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190502145724-3ef323f4f1fd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190507160741-ecd444e8653b/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190524122548-abf6ff778158/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190524152521-dbbf3f1254d4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190526052359-791d8a0f4d09/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190606165138-5da285871e9c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190610200419-93c9922d18ae/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190624142023-c5567b49c5d0/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190626221950-04f50cda93cb/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190726091711-fc99dfbffb4e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190801041406-cbf593c0f2f3/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190826190057-c7b8b68b1456/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190904154756-749cb33beabd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190916202348-b4ddaad3f8a3/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190922100055-0a153f010e69/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190924154521-2837fb4f24fe/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20191001151750-bb3f8db39f24/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20191005200804-aed5e4c7ecf9/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20191008105621-543471e840be/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20191026070338-33540a1f6037/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20191120155948-bd437916bb0e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20191204072324-ce4227a45e2e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20191206220618-eeba5f6aabab/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20191220142924-d4481acd189f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20191228213918-04cbcbbfeed8/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200106162015-b016eb3dc98e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200113162924-86b910548bc1/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200116001909-b77594299b42/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200122134326-e047566fdf82/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200124204421-9fbb57f87de9/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200202164722-d101bd2416d5/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200212091648-12a6c2dcc1e4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200223170610-d5e6a3e2c0ae/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200302150141-5c8b2ff67527/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200323222414-85ca7c5b95cd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20200509044756-6aff5f38e54f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20200519105757-fe76b779f299 h1:DYfZAGf2WMFjMxbgTjaC+2HC7NkNAQs+6Q8b9WEB/F4= +golang.org/x/sys v0.0.0-20200331124033-c3d80250170d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200420163511-1957bb5e6d1f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200501052902-10377860bb8e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200511232937-7e40ca221e25/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200515095857-1151b9dac4a9/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200519105757-fe76b779f299/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200523222454-059865788121/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200602225109-6fdc65e7d980/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200615200032-f1bc736245b1/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200625212154-ddb9806d33ae/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200803210538-64077c9b5642/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200905004654-be1d3432aa8f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20201201145000-ef89a241ccb3/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20201204225414-ed752295db88/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20201214210602-f9fddec55a1e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210104204734-6f8348627aad/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210112080510-489259a85091/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210119212857-b64e53b001e4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210124154548-22da62e12c0c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210220050731-9a76102bfb43/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210303074136-134d130e1a04/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210305230114-8fe3ee5dd75b/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210309074719-68d13333faf2/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210315160823-c6e025ad8005/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210317225723-c4fcb01b228e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210320140829-1e4c9ba3b0c4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210330210617-4fbd30eecc44/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210403161142-5e06dd20ab57/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210426080607-c94f62235c83/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210510120138-977fb7262007/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20210511113859-b0526f3d8744/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20210514084401-e8d321eab015/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20210603081109-ebe580a85c40/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20210603125802-9665404d3644/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20210616094352-59db8d763f22/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20210630005230-0f9fa26af87c/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20210806184541-e5e7981a1069/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20210809222454-d867a43fc93e/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20210816074244-15123e1e1f71/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20210816183151-1e6c022a8912/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20210823070655-63515b42dcdf/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20210908233432-aa78b53d3365/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20210915083310-ed5796bab164/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20210927094055-39ccf1dd6fa6/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20211007075335-d3039528d8ac/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20211019181941-9d821ace8654/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20211105183446-c75c47738b0c/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20211124211545-fe61309f8881/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20211205182925-97ca703d548d/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20211210111614-af8b64212486/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20211213223007-03aa0b5f6827/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20211216021012-1d35b9e2eb4e/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220111092808-5a964db01320/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220114195835-da31bd327af9/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220209214540-3681064d5158/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220412211240-33da011f77ad h1:ntjMns5wyP/fN65tdBD4g8J5w8n015+iIIs9rtjXkY0= +golang.org/x/sys v0.0.0-20220412211240-33da011f77ad/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/term v0.0.0-20201117132131-f5c789dd3221/go.mod h1:Nr5EML6q2oocZ2LXRh80K7BxOlk5/8JxuGnuhpl+muw= +golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= +golang.org/x/term v0.0.0-20210927222741-03fcf44c2211 h1:JGgROgKl9N8DuW20oFS5gxc+lE67/N3FcwmBPMe7ArY= +golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8= golang.org/x/text v0.0.0-20170915032832-14c0d48ead0c/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.1-0.20180807135948-17ff2d5776d2/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= -golang.org/x/text v0.3.2 h1:tW2bmiBqwgJj/UpqtC8EpXEZVYOwU0yG4iWbprSVAcs= golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk= +golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= +golang.org/x/text v0.3.4/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= +golang.org/x/text v0.3.5/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= +golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= +golang.org/x/text v0.3.7 h1:olpwvP2KacW1ZWvsR7uQhoyTYvKAupfQrRGBFM352Gk= +golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ= golang.org/x/time v0.0.0-20180412165947-fbb02b2291d2/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/time v0.0.0-20181108054448-85acf8d2951c/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/time v0.0.0-20190308202827-9d24e82272b4/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= +golang.org/x/time v0.0.0-20191024005414-555d28b269f0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= +golang.org/x/time v0.0.0-20200416051211-89c76fbcd5d1/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/tools v0.0.0-20180221164845-07fd8470d635/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/tools v0.0.0-20180525024113-a5b4c53f6e8b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/tools v0.0.0-20180828015842-6cd1fcedba52/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/tools v0.0.0-20181030000716-a0a13e073c7b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/tools v0.0.0-20181030221726-6c7e314b6563/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= -golang.org/x/tools v0.0.0-20181117154741-2ddaf7f79a09/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/tools v0.0.0-20181130052023-1c3d964395ce/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= -golang.org/x/tools v0.0.0-20190110163146-51295c7ec13a/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/tools v0.0.0-20190114222345-bf090417da8b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= -golang.org/x/tools v0.0.0-20190221204921-83362c3779f5/go.mod h1:9Yl7xja0Znq3iFh3HoIrodX9oNMXvdceNzlUR8zjMvY= golang.org/x/tools v0.0.0-20190226205152-f727befe758c/go.mod h1:9Yl7xja0Znq3iFh3HoIrodX9oNMXvdceNzlUR8zjMvY= +golang.org/x/tools v0.0.0-20190307163923-6a08e3108db3/go.mod h1:25r3+/G6/xytQM8iWZKq3Hn0kr0rgFKPUNVEL/dr3z4= golang.org/x/tools v0.0.0-20190311212946-11955173bddd/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= golang.org/x/tools v0.0.0-20190311215038-5c2858a9cfe5/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= +golang.org/x/tools v0.0.0-20190312151545-0bb0c0a6e846/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= +golang.org/x/tools v0.0.0-20190312170243-e65039ee4138/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= +golang.org/x/tools v0.0.0-20190321232350-e250d351ecad/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= golang.org/x/tools v0.0.0-20190322203728-c1a832b0ad89/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= golang.org/x/tools v0.0.0-20190328211700-ab21143f2384/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= golang.org/x/tools v0.0.0-20190425150028-36563e24a262/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q= -golang.org/x/tools v0.0.0-20190521203540-521d6ed310dd/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q= +golang.org/x/tools v0.0.0-20190506145303-2d16b83fe98c/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q= +golang.org/x/tools v0.0.0-20190524140312-2c0ae7006135/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q= +golang.org/x/tools v0.0.0-20190606124116-d0a3d012864b/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= golang.org/x/tools v0.0.0-20190621195816-6e04913cbbac/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= golang.org/x/tools v0.0.0-20190624222133-a101b041ded4/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= -golang.org/x/tools v0.0.0-20190719005602-e377ae9d6386/go.mod h1:jcCCGcm9btYwXyDqrUWc6MKQKKGJCWEQ3AfLSRIbEuI= +golang.org/x/tools v0.0.0-20190628153133-6cdbf07be9d0/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= +golang.org/x/tools v0.0.0-20190816200558-6889da9d5479/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/tools v0.0.0-20190907020128-2ca718005c18/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/tools v0.0.0-20190910044552-dd2b5c81c578/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/tools v0.0.0-20190911174233-4f2ddba30aff/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/tools v0.0.0-20190916130336-e45ffcd953cc/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/tools v0.0.0-20191010075000-0337d82405ff/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/tools v0.0.0-20191012152004-8de300cfc20a/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/tools v0.0.0-20191029041327-9cc4af7d6b2c/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/tools v0.0.0-20191029190741-b9c20aec41a5/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/tools v0.0.0-20191108193012-7d206e10da11/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/tools v0.0.0-20191113191852-77e3bb0ad9e7/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/tools v0.0.0-20191115202509-3a792d9c32b2/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/tools v0.0.0-20191125144606-a911d9008d1f/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/tools v0.0.0-20191130070609-6e064ea0cf2d/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/tools v0.0.0-20191216052735-49a3e744a425/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= golang.org/x/tools v0.0.0-20191216173652-a0e659d51361/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= -golang.org/x/tools v0.0.0-20200228224639-71482053b885/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= +golang.org/x/tools v0.0.0-20191227053925-7b8e75db28f4/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= +golang.org/x/tools v0.0.0-20200103221440-774c71fcf114/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= +golang.org/x/tools v0.0.0-20200117161641-43d50277825c/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= +golang.org/x/tools v0.0.0-20200117220505-0cba7a3a9ee9/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= +golang.org/x/tools v0.0.0-20200122220014-bf1340f18c4a/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= +golang.org/x/tools v0.0.0-20200130002326-2f3ba24bd6e7/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= +golang.org/x/tools v0.0.0-20200204074204-1cc6d1ef6c74/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= +golang.org/x/tools v0.0.0-20200207183749-b753a1ba74fa/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= +golang.org/x/tools v0.0.0-20200212150539-ea181f53ac56/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= +golang.org/x/tools v0.0.0-20200224181240-023911ca70b2/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= +golang.org/x/tools v0.0.0-20200227222343-706bc42d1f0d/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= +golang.org/x/tools v0.0.0-20200304193943-95d2e580d8eb/go.mod h1:o4KQGtdN14AW+yjsvvwRTJJuXz8XRtIHtEnmAXLyFUw= +golang.org/x/tools v0.0.0-20200312045724-11d5b4c81c7d/go.mod h1:o4KQGtdN14AW+yjsvvwRTJJuXz8XRtIHtEnmAXLyFUw= golang.org/x/tools v0.0.0-20200324003944-a576cf524670/go.mod h1:Sl4aGygMT6LrqrWclx+PTx3U+LnKx/seiNR+3G19Ar8= +golang.org/x/tools v0.0.0-20200329025819-fd4102a86c65/go.mod h1:Sl4aGygMT6LrqrWclx+PTx3U+LnKx/seiNR+3G19Ar8= +golang.org/x/tools v0.0.0-20200331025713-a30bf2db82d4/go.mod h1:Sl4aGygMT6LrqrWclx+PTx3U+LnKx/seiNR+3G19Ar8= golang.org/x/tools v0.0.0-20200414032229-332987a829c3/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= -golang.org/x/tools v0.0.0-20200422022333-3d57cf2e726e h1:3Dzrrxi54Io7Aoyb0PYLsI47K2TxkRQg+cqUn+m04do= golang.org/x/tools v0.0.0-20200422022333-3d57cf2e726e/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= +golang.org/x/tools v0.0.0-20200426102838-f3a5411a4c3b/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= +golang.org/x/tools v0.0.0-20200501065659-ab2804fb9c9d/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= +golang.org/x/tools v0.0.0-20200512131952-2bc93b1c0c88/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= +golang.org/x/tools v0.0.0-20200515010526-7d3b6ebf133d/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= +golang.org/x/tools v0.0.0-20200618134242-20370b0cb4b2/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= +golang.org/x/tools v0.0.0-20200619180055-7c47624df98f/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= +golang.org/x/tools v0.0.0-20200622203043-20e05c1c8ffa/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= +golang.org/x/tools v0.0.0-20200624225443-88f3c62a19ff/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= +golang.org/x/tools v0.0.0-20200625211823-6506e20df31f/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= +golang.org/x/tools v0.0.0-20200626171337-aa94e735be7f/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= +golang.org/x/tools v0.0.0-20200630154851-b2d8b0336632/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= +golang.org/x/tools v0.0.0-20200706234117-b22de6825cf7/go.mod h1:njjCfa9FT2d7l9Bc6FUM5FLjQPp3cFF28FI3qnDFljA= +golang.org/x/tools v0.0.0-20200724022722-7017fd6b1305/go.mod h1:njjCfa9FT2d7l9Bc6FUM5FLjQPp3cFF28FI3qnDFljA= +golang.org/x/tools v0.0.0-20200729194436-6467de6f59a7/go.mod h1:njjCfa9FT2d7l9Bc6FUM5FLjQPp3cFF28FI3qnDFljA= +golang.org/x/tools v0.0.0-20200804011535-6c149bb5ef0d/go.mod h1:njjCfa9FT2d7l9Bc6FUM5FLjQPp3cFF28FI3qnDFljA= +golang.org/x/tools v0.0.0-20200812195022-5ae4c3c160a0/go.mod h1:njjCfa9FT2d7l9Bc6FUM5FLjQPp3cFF28FI3qnDFljA= +golang.org/x/tools v0.0.0-20200820010801-b793a1359eac/go.mod h1:njjCfa9FT2d7l9Bc6FUM5FLjQPp3cFF28FI3qnDFljA= +golang.org/x/tools v0.0.0-20200825202427-b303f430e36d/go.mod h1:njjCfa9FT2d7l9Bc6FUM5FLjQPp3cFF28FI3qnDFljA= +golang.org/x/tools v0.0.0-20200831203904-5a2aa26beb65/go.mod h1:Cj7w3i3Rnn0Xh82ur9kSqwfTHTeVxaDqrfMjpcNT6bE= +golang.org/x/tools v0.0.0-20200904185747-39188db58858/go.mod h1:Cj7w3i3Rnn0Xh82ur9kSqwfTHTeVxaDqrfMjpcNT6bE= +golang.org/x/tools v0.0.0-20201001104356-43ebab892c4c/go.mod h1:z6u4i615ZeAfBE4XtMziQW1fSVJXACjjbWkB/mvPzlU= +golang.org/x/tools v0.0.0-20201002184944-ecd9fd270d5d/go.mod h1:z6u4i615ZeAfBE4XtMziQW1fSVJXACjjbWkB/mvPzlU= +golang.org/x/tools v0.0.0-20201023174141-c8cfbd0f21e6/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= +golang.org/x/tools v0.0.0-20201028025901-8cd080b735b3/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= +golang.org/x/tools v0.0.0-20201110124207-079ba7bd75cd/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= +golang.org/x/tools v0.0.0-20201114224030-61ea331ec02b/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= +golang.org/x/tools v0.0.0-20201201161351-ac6f37ff4c2a/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= +golang.org/x/tools v0.0.0-20201208233053-a543418bbed2/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= +golang.org/x/tools v0.0.0-20201224043029-2b0845dc783e/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= +golang.org/x/tools v0.0.0-20201230224404-63754364767c/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= +golang.org/x/tools v0.0.0-20210105154028-b0ab187a4818/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= +golang.org/x/tools v0.0.0-20210106214847-113979e3529a/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= +golang.org/x/tools v0.1.0/go.mod h1:xkSsbof2nBLbhDlRMhhhyNLN/zl3eTqcnHD5viDpcZ0= +golang.org/x/tools v0.1.1-0.20210205202024-ef80cdb6ec6d/go.mod h1:9bzcO0MWcOuT0tm1iBGzDVPshzfwoVvREIui8C+MHqU= +golang.org/x/tools v0.1.1-0.20210302220138-2ac05c832e1a/go.mod h1:9bzcO0MWcOuT0tm1iBGzDVPshzfwoVvREIui8C+MHqU= +golang.org/x/tools v0.1.1/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk= +golang.org/x/tools v0.1.2/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk= +golang.org/x/tools v0.1.3/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk= +golang.org/x/tools v0.1.4/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk= +golang.org/x/tools v0.1.5/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk= +golang.org/x/tools v0.1.6-0.20210726203631-07bc1bf47fb2/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk= +golang.org/x/tools v0.1.7/go.mod h1:LGqMHiF4EqQNHR1JncWGqT5BVaXmza+X+BDGol+dOxo= +golang.org/x/tools v0.1.8/go.mod h1:nABZi5QlRsZVlzPpHl034qft6wpY4eDcsTt5AaioBiU= +golang.org/x/tools v0.1.9-0.20211228192929-ee1ca4ffc4da/go.mod h1:nABZi5QlRsZVlzPpHl034qft6wpY4eDcsTt5AaioBiU= +golang.org/x/tools v0.1.9/go.mod h1:nABZi5QlRsZVlzPpHl034qft6wpY4eDcsTt5AaioBiU= +golang.org/x/tools v0.1.10 h1:QjFRCZxdOhBJ/UNgnBZLbNV13DlbnK0quyivTnXJM20= +golang.org/x/tools v0.1.10/go.mod h1:Uh6Zz+xoGYZom868N8YTex3t7RhtHDBrE8Gzo9bV56E= golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= -golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543 h1:E7g+9GITq07hpfrRu66IVDexMakfv52eLZ2CXBWiKr4= golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= +golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= +golang.org/x/xerrors v0.0.0-20220411194840-2f41105eb62f h1:GGU+dLjvlC3qDwqYgL6UgRmHXhOOgns0bZu2Ty5mm6U= +golang.org/x/xerrors v0.0.0-20220411194840-2f41105eb62f/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= google.golang.org/api v0.0.0-20180910000450-7ca32eb868bf/go.mod h1:4mhQ8q/RsB7i+udVvVy5NUi08OU8ZlA0gRVgrF7VFY0= google.golang.org/api v0.0.0-20181030000543-1d582fd0359e/go.mod h1:4mhQ8q/RsB7i+udVvVy5NUi08OU8ZlA0gRVgrF7VFY0= google.golang.org/api v0.1.0/go.mod h1:UGEZY7KEX120AnNLIHFMKIo4obdJhkp2tPbaPlQx13Y= +google.golang.org/api v0.3.1/go.mod h1:6wY9I6uQWHQ8EM57III9mq/AjF+i8G65rmVagqKMtkk= +google.golang.org/api v0.4.0/go.mod h1:8k5glujaEP+g9n7WNsDg8QP6cUVNI86fCNMcbazEtwE= +google.golang.org/api v0.7.0/go.mod h1:WtwebWUNSVBH/HAw79HIFXZNqEvBhG+Ra+ax0hx3E3M= +google.golang.org/api v0.8.0/go.mod h1:o4eAsZoiT+ibD93RtjEohWalFOjRDx6CVaqeizhEnKg= +google.golang.org/api v0.9.0/go.mod h1:o4eAsZoiT+ibD93RtjEohWalFOjRDx6CVaqeizhEnKg= +google.golang.org/api v0.10.0/go.mod h1:o4eAsZoiT+ibD93RtjEohWalFOjRDx6CVaqeizhEnKg= +google.golang.org/api v0.13.0/go.mod h1:iLdEw5Ide6rF15KTC1Kkl0iskquN2gFfn9o9XIsbkAI= +google.golang.org/api v0.14.0/go.mod h1:iLdEw5Ide6rF15KTC1Kkl0iskquN2gFfn9o9XIsbkAI= +google.golang.org/api v0.15.0/go.mod h1:iLdEw5Ide6rF15KTC1Kkl0iskquN2gFfn9o9XIsbkAI= +google.golang.org/api v0.17.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE= +google.golang.org/api v0.18.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE= +google.golang.org/api v0.19.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE= +google.golang.org/api v0.20.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE= +google.golang.org/api v0.22.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE= +google.golang.org/api v0.24.0/go.mod h1:lIXQywCXRcnZPGlsd8NbLnOjtAoL6em04bJ9+z0MncE= +google.golang.org/api v0.28.0/go.mod h1:lIXQywCXRcnZPGlsd8NbLnOjtAoL6em04bJ9+z0MncE= +google.golang.org/api v0.29.0/go.mod h1:Lcubydp8VUV7KeIHD9z2Bys/sm/vGKnG1UHuDBSrHWM= +google.golang.org/api v0.30.0/go.mod h1:QGmEvQ87FHZNiUVJkT14jQNYJ4ZJjdRF23ZXz5138Fc= +google.golang.org/api v0.35.0/go.mod h1:/XrVsuzM0rZmrsbjJutiuftIzeuTQcEeaYcSk/mQ1dg= +google.golang.org/api v0.36.0/go.mod h1:+z5ficQTmoYpPn8LCUNVpK5I7hwkpjbcgqA7I34qYtE= +google.golang.org/api v0.40.0/go.mod h1:fYKFpnQN0DsDSKRVRcQSDQNtqWPfM9i+zNPxepjRCQ8= +google.golang.org/api v0.41.0/go.mod h1:RkxM5lITDfTzmyKFPt+wGrCJbVfniCr2ool8kTBzRTU= +google.golang.org/api v0.43.0/go.mod h1:nQsDGjRXMo4lvh5hP0TKqF244gqhGcr/YSIykhUk/94= +google.golang.org/api v0.47.0/go.mod h1:Wbvgpq1HddcWVtzsVLyfLp8lDg6AA241LmgIL59tHXo= +google.golang.org/api v0.48.0/go.mod h1:71Pr1vy+TAZRPkPs/xlCf5SsU8WjuAWv1Pfjbtukyy4= +google.golang.org/api v0.50.0/go.mod h1:4bNT5pAuq5ji4SRZm+5QIkjny9JAyVD/3gaSihNefaw= +google.golang.org/api v0.51.0/go.mod h1:t4HdrdoNgyN5cbEfm7Lum0lcLDLiise1F8qDKX00sOU= +google.golang.org/api v0.54.0/go.mod h1:7C4bFFOvVDGXjfDTAsgGwDgAxRDeQ4X8NvUedIt6z3k= +google.golang.org/api v0.55.0/go.mod h1:38yMfeP1kfjsl8isn0tliTjIb1rJXcQi4UXlbqivdVE= +google.golang.org/api v0.56.0/go.mod h1:38yMfeP1kfjsl8isn0tliTjIb1rJXcQi4UXlbqivdVE= +google.golang.org/api v0.57.0/go.mod h1:dVPlbZyBo2/OjBpmvNdpn2GRm6rPy75jyU7bmhdrMgI= +google.golang.org/api v0.59.0/go.mod h1:sT2boj7M9YJxZzgeZqXogmhfmRWDtPzT31xkieUbuZU= +google.golang.org/api v0.61.0/go.mod h1:xQRti5UdCmoCEqFxcz93fTl338AVqDgyaDRuOZ3hg9I= +google.golang.org/api v0.62.0/go.mod h1:dKmwPCydfsad4qCH08MSdgWjfHOyfpd4VtDGgRFdavw= +google.golang.org/api v0.63.0/go.mod h1:gs4ij2ffTRXwuzzgJl/56BdwJaA194ijkfn++9tDuPo= google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM= google.golang.org/appengine v1.2.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4= google.golang.org/appengine v1.3.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4= google.golang.org/appengine v1.4.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4= +google.golang.org/appengine v1.5.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4= +google.golang.org/appengine v1.6.1/go.mod h1:i06prIuMbXzDqacNJfV5OdTW448YApPu5ww/cMBSeb0= +google.golang.org/appengine v1.6.2/go.mod h1:i06prIuMbXzDqacNJfV5OdTW448YApPu5ww/cMBSeb0= +google.golang.org/appengine v1.6.5/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc= +google.golang.org/appengine v1.6.6/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc= +google.golang.org/appengine v1.6.7/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc= +google.golang.org/genproto v0.0.0-20170818010345-ee236bd376b0/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc= google.golang.org/genproto v0.0.0-20180817151627-c66870c02cf8/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc= google.golang.org/genproto v0.0.0-20180831171423-11092d34479b/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc= google.golang.org/genproto v0.0.0-20181029155118-b69ba1387ce2/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc= +google.golang.org/genproto v0.0.0-20181107211654-5fc9ac540362/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc= google.golang.org/genproto v0.0.0-20181202183823-bd91e49a0898/go.mod h1:7Ep/1NZk928CDR8SjdVbjWNpdIf6nzjE3BTgJDr2Atg= google.golang.org/genproto v0.0.0-20190306203927-b5d61aea6440/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE= google.golang.org/genproto v0.0.0-20190307195333-5fe7a883aa19/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE= +google.golang.org/genproto v0.0.0-20190418145605-e7d98fc518a7/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE= google.golang.org/genproto v0.0.0-20190425155659-357c62f0e4bb/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE= +google.golang.org/genproto v0.0.0-20190502173448-54afdca5d873/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE= +google.golang.org/genproto v0.0.0-20190530194941-fb225487d101/go.mod h1:z3L6/3dTEVtUr6QSP8miRzeRqwQOioJ9I66odjN4I7s= +google.golang.org/genproto v0.0.0-20190801165951-fa694d86fc64/go.mod h1:DMBHOl98Agz4BDEuKkezgsaosCRResVns1a3J2ZsMNc= +google.golang.org/genproto v0.0.0-20190819201941-24fa4b261c55/go.mod h1:DMBHOl98Agz4BDEuKkezgsaosCRResVns1a3J2ZsMNc= +google.golang.org/genproto v0.0.0-20190911173649-1774047e7e51/go.mod h1:IbNlFCBrqXvoKpeg0TB2l7cyZUmoaFKYIwrEpbDKLA8= +google.golang.org/genproto v0.0.0-20190927181202-20e1ac93f88c/go.mod h1:IbNlFCBrqXvoKpeg0TB2l7cyZUmoaFKYIwrEpbDKLA8= +google.golang.org/genproto v0.0.0-20191108220845-16a3f7862a1a/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc= +google.golang.org/genproto v0.0.0-20191115194625-c23dd37a84c9/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc= +google.golang.org/genproto v0.0.0-20191216164720-4f79533eabd1/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc= +google.golang.org/genproto v0.0.0-20191230161307-f3c370f40bfb/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc= +google.golang.org/genproto v0.0.0-20200115191322-ca5a22157cba/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc= +google.golang.org/genproto v0.0.0-20200122232147-0452cf42e150/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc= +google.golang.org/genproto v0.0.0-20200204135345-fa8e72b47b90/go.mod h1:GmwEX6Z4W5gMy59cAlVYjN9JhxgbQH6Gn+gFDQe2lzA= +google.golang.org/genproto v0.0.0-20200212174721-66ed5ce911ce/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= +google.golang.org/genproto v0.0.0-20200224152610-e50cd9704f63/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= +google.golang.org/genproto v0.0.0-20200228133532-8c2c7df3a383/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= +google.golang.org/genproto v0.0.0-20200305110556-506484158171/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= +google.golang.org/genproto v0.0.0-20200312145019-da6875a35672/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= +google.golang.org/genproto v0.0.0-20200331122359-1ee6d9798940/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= +google.golang.org/genproto v0.0.0-20200423170343-7949de9c1215/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= +google.golang.org/genproto v0.0.0-20200430143042-b979b6f78d84/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= +google.golang.org/genproto v0.0.0-20200511104702-f5ebc3bea380/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= +google.golang.org/genproto v0.0.0-20200513103714-09dca8ec2884/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= +google.golang.org/genproto v0.0.0-20200515170657-fc4c6c6a6587/go.mod h1:YsZOwe1myG/8QRHRsmBRE1LrgQY60beZKjly0O1fX9U= +google.golang.org/genproto v0.0.0-20200526211855-cb27e3aa2013/go.mod h1:NbSheEEYHJ7i3ixzK3sjbqSGDJWnxyFXZblF3eUsNvo= +google.golang.org/genproto v0.0.0-20200618031413-b414f8b61790/go.mod h1:jDfRM7FcilCzHH/e9qn6dsT145K34l5v+OpcnNgKAAA= +google.golang.org/genproto v0.0.0-20200626011028-ee7919e894b5/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= +google.golang.org/genproto v0.0.0-20200707001353-8e8330bf89df/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= +google.golang.org/genproto v0.0.0-20200729003335-053ba62fc06f/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= +google.golang.org/genproto v0.0.0-20200804131852-c06518451d9c/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= +google.golang.org/genproto v0.0.0-20200825200019-8632dd797987/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= +google.golang.org/genproto v0.0.0-20200904004341-0bd0a958aa1d/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= +google.golang.org/genproto v0.0.0-20201109203340-2640f1f9cdfb/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= +google.golang.org/genproto v0.0.0-20201201144952-b05cb90ed32e/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= +google.golang.org/genproto v0.0.0-20201210142538-e3217bee35cc/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= +google.golang.org/genproto v0.0.0-20201214200347-8c77b98c765d/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= +google.golang.org/genproto v0.0.0-20210222152913-aa3ee6e6a81c/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= +google.golang.org/genproto v0.0.0-20210303154014-9728d6b83eeb/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= +google.golang.org/genproto v0.0.0-20210310155132-4ce2db91004e/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= +google.golang.org/genproto v0.0.0-20210319143718-93e7006c17a6/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= +google.golang.org/genproto v0.0.0-20210402141018-6c239bbf2bb1/go.mod h1:9lPAdzaEmUacj36I+k7YKbEc5CXzPIeORRgDAUOu28A= +google.golang.org/genproto v0.0.0-20210513213006-bf773b8c8384/go.mod h1:P3QM42oQyzQSnHPnZ/vqoCdDmzH28fzWByN9asMeM8A= +google.golang.org/genproto v0.0.0-20210602131652-f16073e35f0c/go.mod h1:UODoCrxHCcBojKKwX1terBiRUaqAsFqJiF615XL43r0= +google.golang.org/genproto v0.0.0-20210604141403-392c879c8b08/go.mod h1:UODoCrxHCcBojKKwX1terBiRUaqAsFqJiF615XL43r0= +google.golang.org/genproto v0.0.0-20210608205507-b6d2f5bf0d7d/go.mod h1:UODoCrxHCcBojKKwX1terBiRUaqAsFqJiF615XL43r0= +google.golang.org/genproto v0.0.0-20210624195500-8bfb893ecb84/go.mod h1:SzzZ/N+nwJDaO1kznhnlzqS8ocJICar6hYhVyhi++24= +google.golang.org/genproto v0.0.0-20210713002101-d411969a0d9a/go.mod h1:AxrInvYm1dci+enl5hChSFPOmmUF1+uAa/UsgNRWd7k= +google.golang.org/genproto v0.0.0-20210716133855-ce7ef5c701ea/go.mod h1:AxrInvYm1dci+enl5hChSFPOmmUF1+uAa/UsgNRWd7k= +google.golang.org/genproto v0.0.0-20210728212813-7823e685a01f/go.mod h1:ob2IJxKrgPT52GcgX759i1sleT07tiKowYBGbczaW48= +google.golang.org/genproto v0.0.0-20210805201207-89edb61ffb67/go.mod h1:ob2IJxKrgPT52GcgX759i1sleT07tiKowYBGbczaW48= +google.golang.org/genproto v0.0.0-20210813162853-db860fec028c/go.mod h1:cFeNkxwySK631ADgubI+/XFU/xp8FD5KIVV4rj8UC5w= +google.golang.org/genproto v0.0.0-20210821163610-241b8fcbd6c8/go.mod h1:eFjDcFEctNawg4eG61bRv87N7iHBWyVhJu7u1kqDUXY= +google.golang.org/genproto v0.0.0-20210828152312-66f60bf46e71/go.mod h1:eFjDcFEctNawg4eG61bRv87N7iHBWyVhJu7u1kqDUXY= +google.golang.org/genproto v0.0.0-20210831024726-fe130286e0e2/go.mod h1:eFjDcFEctNawg4eG61bRv87N7iHBWyVhJu7u1kqDUXY= +google.golang.org/genproto v0.0.0-20210903162649-d08c68adba83/go.mod h1:eFjDcFEctNawg4eG61bRv87N7iHBWyVhJu7u1kqDUXY= +google.golang.org/genproto v0.0.0-20210909211513-a8c4777a87af/go.mod h1:eFjDcFEctNawg4eG61bRv87N7iHBWyVhJu7u1kqDUXY= +google.golang.org/genproto v0.0.0-20210924002016-3dee208752a0/go.mod h1:5CzLGKJ67TSI2B9POpiiyGha0AjJvZIUgRMt1dSmuhc= +google.golang.org/genproto v0.0.0-20211008145708-270636b82663/go.mod h1:5CzLGKJ67TSI2B9POpiiyGha0AjJvZIUgRMt1dSmuhc= +google.golang.org/genproto v0.0.0-20211028162531-8db9c33dc351/go.mod h1:5CzLGKJ67TSI2B9POpiiyGha0AjJvZIUgRMt1dSmuhc= +google.golang.org/genproto v0.0.0-20211118181313-81c1377c94b1/go.mod h1:5CzLGKJ67TSI2B9POpiiyGha0AjJvZIUgRMt1dSmuhc= +google.golang.org/genproto v0.0.0-20211129164237-f09f9a12af12/go.mod h1:5CzLGKJ67TSI2B9POpiiyGha0AjJvZIUgRMt1dSmuhc= +google.golang.org/genproto v0.0.0-20211203200212-54befc351ae9/go.mod h1:5CzLGKJ67TSI2B9POpiiyGha0AjJvZIUgRMt1dSmuhc= +google.golang.org/genproto v0.0.0-20211206160659-862468c7d6e0/go.mod h1:5CzLGKJ67TSI2B9POpiiyGha0AjJvZIUgRMt1dSmuhc= +google.golang.org/genproto v0.0.0-20211208223120-3a66f561d7aa/go.mod h1:5CzLGKJ67TSI2B9POpiiyGha0AjJvZIUgRMt1dSmuhc= +google.golang.org/grpc v1.8.0/go.mod h1:yo6s7OP7yaDglbqo1J04qKzAhqBH6lvTonzMVmEdcZw= google.golang.org/grpc v1.14.0/go.mod h1:yo6s7OP7yaDglbqo1J04qKzAhqBH6lvTonzMVmEdcZw= google.golang.org/grpc v1.16.0/go.mod h1:0JHn/cJsOMiMfNA9+DeHDlAU7KAAB5GDlYFpa9MZMio= google.golang.org/grpc v1.17.0/go.mod h1:6QZJwpn2B+Zp71q/5VxRsJ6NXXVCE5NRUHRo+f3cWCs= google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c= +google.golang.org/grpc v1.20.0/go.mod h1:chYK+tFQF0nDUGJgXMSgLCQk3phJEuONr2DCgLDdAQM= google.golang.org/grpc v1.20.1/go.mod h1:10oTOabMzJvdu6/UiuZezV6QK5dSlG84ov/aaiqXj38= google.golang.org/grpc v1.21.0/go.mod h1:oYelfM1adQP15Ek0mdvEgi9Df8B9CZIaU1084ijfRaM= +google.golang.org/grpc v1.21.1/go.mod h1:oYelfM1adQP15Ek0mdvEgi9Df8B9CZIaU1084ijfRaM= +google.golang.org/grpc v1.22.1/go.mod h1:Y5yQAOtifL1yxbo5wqy6BxZv8vAUGQwXBOALyacEbxg= +google.golang.org/grpc v1.23.0/go.mod h1:Y5yQAOtifL1yxbo5wqy6BxZv8vAUGQwXBOALyacEbxg= +google.golang.org/grpc v1.23.1/go.mod h1:Y5yQAOtifL1yxbo5wqy6BxZv8vAUGQwXBOALyacEbxg= +google.golang.org/grpc v1.24.0/go.mod h1:XDChyiUovWa60DnaeDeZmSW86xtLtjtZbwvSiRnRtcA= +google.golang.org/grpc v1.25.1/go.mod h1:c3i+UQWmh7LiEpx4sFZnkU36qjEYZ0imhYfXVyQciAY= +google.golang.org/grpc v1.26.0/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk= +google.golang.org/grpc v1.27.0/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk= +google.golang.org/grpc v1.27.1/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk= +google.golang.org/grpc v1.28.0/go.mod h1:rpkK4SK4GF4Ach/+MFLZUBavHOvF2JJB5uozKKal+60= +google.golang.org/grpc v1.28.1/go.mod h1:rpkK4SK4GF4Ach/+MFLZUBavHOvF2JJB5uozKKal+60= +google.golang.org/grpc v1.29.0/go.mod h1:itym6AZVZYACWQqET3MqgPpjcuV5QH3BxFS3IjizoKk= +google.golang.org/grpc v1.29.1/go.mod h1:itym6AZVZYACWQqET3MqgPpjcuV5QH3BxFS3IjizoKk= +google.golang.org/grpc v1.30.0/go.mod h1:N36X2cJ7JwdamYAgDz+s+rVMFjt3numwzf/HckM8pak= +google.golang.org/grpc v1.31.0/go.mod h1:N36X2cJ7JwdamYAgDz+s+rVMFjt3numwzf/HckM8pak= +google.golang.org/grpc v1.31.1/go.mod h1:N36X2cJ7JwdamYAgDz+s+rVMFjt3numwzf/HckM8pak= +google.golang.org/grpc v1.33.1/go.mod h1:fr5YgcSWrqhRRxogOsw7RzIpsmvOZ6IcH4kBYTpR3n0= +google.golang.org/grpc v1.33.2/go.mod h1:JMHMWHQWaTccqQQlmk3MJZS+GWXOdAesneDmEnv2fbc= +google.golang.org/grpc v1.34.0/go.mod h1:WotjhfgOW/POjDeRt8vscBtXq+2VjORFy659qA51WJ8= +google.golang.org/grpc v1.35.0/go.mod h1:qjiiYl8FncCW8feJPdyg3v6XW24KsRHe+dy9BAGRRjU= +google.golang.org/grpc v1.36.0/go.mod h1:qjiiYl8FncCW8feJPdyg3v6XW24KsRHe+dy9BAGRRjU= +google.golang.org/grpc v1.36.1/go.mod h1:qjiiYl8FncCW8feJPdyg3v6XW24KsRHe+dy9BAGRRjU= +google.golang.org/grpc v1.37.0/go.mod h1:NREThFqKR1f3iQ6oBuvc5LadQuXVGo9rkm5ZGrQdJfM= +google.golang.org/grpc v1.37.1/go.mod h1:NREThFqKR1f3iQ6oBuvc5LadQuXVGo9rkm5ZGrQdJfM= +google.golang.org/grpc v1.38.0/go.mod h1:NREThFqKR1f3iQ6oBuvc5LadQuXVGo9rkm5ZGrQdJfM= +google.golang.org/grpc v1.39.0/go.mod h1:PImNr+rS9TWYb2O4/emRugxiyHZ5JyHW5F+RPnDzfrE= +google.golang.org/grpc v1.39.1/go.mod h1:PImNr+rS9TWYb2O4/emRugxiyHZ5JyHW5F+RPnDzfrE= +google.golang.org/grpc v1.40.0/go.mod h1:ogyxbiOoUXAkP+4+xa6PZSE9DZgIHtSpzjDTB9KAK34= +google.golang.org/grpc v1.40.1/go.mod h1:ogyxbiOoUXAkP+4+xa6PZSE9DZgIHtSpzjDTB9KAK34= +google.golang.org/grpc v1.42.0/go.mod h1:k+4IHHFw41K8+bbowsex27ge2rCb65oeWqe4jJ590SU= +google.golang.org/grpc v1.43.0/go.mod h1:k+4IHHFw41K8+bbowsex27ge2rCb65oeWqe4jJ590SU= +google.golang.org/grpc v1.45.0 h1:NEpgUqV3Z+ZjkqMsxMg11IaDrXY4RY6CQukSGK0uI1M= +google.golang.org/grpc v1.45.0/go.mod h1:lN7owxKUQEqMfSyQikvvk5tf/6zMPsrK+ONuO11+0rQ= +google.golang.org/grpc/cmd/protoc-gen-go-grpc v1.1.0/go.mod h1:6Kw0yEErY5E/yWrBtf03jp27GLLJujG4z/JK95pnjjw= +google.golang.org/protobuf v0.0.0-20200109180630-ec00e32a8dfd/go.mod h1:DFci5gLYBciE7Vtevhsrf46CRTquxDuWsQurQQe4oz8= +google.golang.org/protobuf v0.0.0-20200221191635-4d8936d0db64/go.mod h1:kwYJMbMJ01Woi6D6+Kah6886xMZcty6N08ah7+eCXa0= +google.golang.org/protobuf v0.0.0-20200228230310-ab0ca4ff8a60/go.mod h1:cfTl7dwQJ+fmap5saPgwCLgHXTUD7jkjRqWcaiX5VyM= +google.golang.org/protobuf v1.20.1-0.20200309200217-e05f789c0967/go.mod h1:A+miEFZTKqfCUM6K7xSMQL9OKL/b6hQv+e19PK+JZNE= +google.golang.org/protobuf v1.21.0/go.mod h1:47Nbq4nVaFHyn7ilMalzfO3qCViNmqZ2kzikPIcrTAo= +google.golang.org/protobuf v1.22.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU= +google.golang.org/protobuf v1.23.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU= +google.golang.org/protobuf v1.23.1-0.20200526195155-81db48ad09cc/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU= +google.golang.org/protobuf v1.24.0/go.mod h1:r/3tXBNzIEhYS9I1OUVjXDlt8tc493IdKGjtUeSXeh4= +google.golang.org/protobuf v1.25.0/go.mod h1:9JNX74DMeImyA3h4bdi1ymwjUzf21/xIlbajtzgsN7c= +google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw= +google.golang.org/protobuf v1.26.0/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc= +google.golang.org/protobuf v1.27.1/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc= +google.golang.org/protobuf v1.28.0 h1:w43yiav+6bVFTBQFZX0r7ipe9JQ1QsbMgHwbBziscLw= +google.golang.org/protobuf v1.28.0/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I= gopkg.in/airbrake/gobrake.v2 v2.0.9/go.mod h1:/h5ZAUhDkGaJfjzjKLSjv6zCL6O0LLBxU4K+aSYdM/U= gopkg.in/alecthomas/kingpin.v2 v2.2.6/go.mod h1:FMv+mEhP44yOT+4EoQTLFTRgOQ1FBLkstjWtayDeSgw= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= -gopkg.in/check.v1 v1.0.0-20200227125254-8fa46927fb4f h1:BLraFXnmrev5lT+xlilqcH8XK9/i0At2xKjWk4p6zsU= gopkg.in/check.v1 v1.0.0-20200227125254-8fa46927fb4f/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk= +gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q= +gopkg.in/cheggaaa/pb.v1 v1.0.25/go.mod h1:V/YB90LKu/1FcN3WVnfiiE5oMCibMjukxqG/qStrOgw= +gopkg.in/cheggaaa/pb.v1 v1.0.28/go.mod h1:V/YB90LKu/1FcN3WVnfiiE5oMCibMjukxqG/qStrOgw= gopkg.in/errgo.v2 v2.1.0/go.mod h1:hNsd1EY+bozCKY1Ytp96fpM3vjJbqLJn88ws8XvfDNI= -gopkg.in/fsnotify.v1 v1.4.7 h1:xOHLXZwVvI9hhs+cLKq5+I5onOuwQLhQwiu63xxlHs4= gopkg.in/fsnotify.v1 v1.4.7/go.mod h1:Tz8NjZHkW78fSQdbUxIjBTcgA1z1m8ZHf0WmKUhAMys= +gopkg.in/gcfg.v1 v1.2.3/go.mod h1:yesOnuUOFQAhST5vPY4nbZsb/huCgGGXlipJsBn0b3o= gopkg.in/gemnasium/logrus-airbrake-hook.v2 v2.1.2/go.mod h1:Xk6kEKp8OKb+X14hQBKWaSkCsqBpgog8nAV2xsGOxlo= gopkg.in/inf.v0 v0.9.1/go.mod h1:cWUDdTG/fYaXco+Dcufb5Vnc6Gp2YChqWtbxRZE0mXw= -gopkg.in/ini.v1 v1.51.0 h1:AQvPpx3LzTDM0AjnIRlVFwFFGC+npRopjZxLJj6gdno= -gopkg.in/ini.v1 v1.51.0/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k= +gopkg.in/ini.v1 v1.63.2/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k= +gopkg.in/ini.v1 v1.66.2 h1:XfR1dOYubytKy4Shzc2LHrrGhU0lDCfDGG1yLPmpgsI= +gopkg.in/ini.v1 v1.66.2/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k= gopkg.in/resty.v1 v1.12.0/go.mod h1:mDo4pnntr5jdWRML875a/NmxYqAlA73dVijT2AXvQQo= gopkg.in/src-d/go-cli.v0 v0.0.0-20181105080154-d492247bbc0d/go.mod h1:z+K8VcOYVYcSwSjGebuDL6176A1XskgbtNl64NSg+n8= gopkg.in/src-d/go-log.v1 v1.0.1/go.mod h1:GN34hKP0g305ysm2/hctJ0Y8nWP3zxXXJ8GFabTyABE= gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7 h1:uRGJdciOHaEIrze2W8Q3AKkepLTh2hOroT7a+7czfdQ= gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7/go.mod h1:dt/ZhP58zS4L8KSrWDmTeBkI65Dw0HsyUHuEVlX15mw= +gopkg.in/warnings.v0 v0.1.2/go.mod h1:jksf8JmL6Qr/oQM2OXTHunEvvTAsrWBLb6OOjuVWRNI= gopkg.in/yaml.v2 v2.0.0-20170812160011-eb3733d160e7/go.mod h1:JAlM8MvJe8wmxCU4Bli9HhUf9+ttbYbLASfIpnQbh74= gopkg.in/yaml.v2 v2.2.1/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v2 v2.2.3/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.2.4/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= -gopkg.in/yaml.v2 v2.2.8 h1:obN1ZagJSUGI0Ek/LBmuj4SNLPfIny3KsKFopxRdj10= +gopkg.in/yaml.v2 v2.2.5/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v2 v2.2.6/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.2.8/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= -gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c h1:dUUwHk2QECo/6vqA44rthZ8ie2QXMNeKRTHCNY2nXvo= +gopkg.in/yaml.v2 v2.3.0/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v2 v2.4.0 h1:D8xgwECY7CYvx+Y2n4sBz93Jn9JRvxdiyyo8CTfuKaY= +gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ= gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= +gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b h1:h8qDotaEPuJATrMmW04NCwg7v22aHH28wwpauUhK9Oo= +gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= gotest.tools/gotestsum v0.4.2 h1:QOdtb6bnnPUuHKkR9+/QQa8e6qjpTTP7cDi7G9/10C4= gotest.tools/gotestsum v0.4.2/go.mod h1:a32lmn/7xfm0+QHj8K5NyQY1NNNNhZoAp+/OHkLs77Y= gotest.tools/v3 v3.0.2 h1:kG1BFyqVHuQoVQiR1bWGnfz/fmHvvuiSPIV7rvl360E= @@ -1159,16 +2538,28 @@ grpc.go4.org v0.0.0-20170609214715-11d0a25b4919/go.mod h1:77eQGdRu53HpSqPFJFmuJd honnef.co/go/tools v0.0.0-20180728063816-88497007e858/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= honnef.co/go/tools v0.0.0-20190106161140-3f1c8253044a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= -honnef.co/go/tools v0.0.1-2019.2.3 h1:3JgtbtFHMiCmsznwGVTUWbgGov+pVqnlf1dEJTNAXeM= +honnef.co/go/tools v0.0.0-20190418001031-e561f6794a2a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= +honnef.co/go/tools v0.0.0-20190523083050-ea95bdfd59fc/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= honnef.co/go/tools v0.0.1-2019.2.3/go.mod h1:a3bituU0lyd329TUQxRnasdCoJDkEUEAqEt0JzvZhAg= +honnef.co/go/tools v0.0.1-2020.1.3/go.mod h1:X/FiERA/W4tHapMX5mGpAtMSVEeEUOyHaw9vFzvIQ3k= +honnef.co/go/tools v0.0.1-2020.1.4/go.mod h1:X/FiERA/W4tHapMX5mGpAtMSVEeEUOyHaw9vFzvIQ3k= +honnef.co/go/tools v0.2.2 h1:MNh1AVMyVX23VUHE2O27jm6lNj3vjO5DexS4A1xvnzk= +honnef.co/go/tools v0.2.2/go.mod h1:lPVVZ2BS5TfnjLyizF7o7hv7j9/L+8cZY2hLyjP9cGY= +lukechampine.com/blake3 v1.1.6/go.mod h1:tkKEOtDkNtklkXtLNEOGNq5tcV90tJiA1vAA12R78LA= +lukechampine.com/blake3 v1.1.7 h1:GgRMhmdsuK8+ii6UZFDL8Nb+VyMwadAgcJyfYHxG6n0= +lukechampine.com/blake3 v1.1.7/go.mod h1:tkKEOtDkNtklkXtLNEOGNq5tcV90tJiA1vAA12R78LA= +mvdan.cc/gofumpt v0.3.0 h1:kTojdZo9AcEYbQYhGuLf/zszYthRdhDNDUi2JKTxas4= +mvdan.cc/gofumpt v0.3.0/go.mod h1:0+VyGZWleeIj5oostkOex+nDBA0eyavuDnDusAJ8ylo= mvdan.cc/interfacer v0.0.0-20180901003855-c20040233aed h1:WX1yoOaKQfddO/mLzdV4wptyWgoH/6hwLs7QHTixo0I= mvdan.cc/interfacer v0.0.0-20180901003855-c20040233aed/go.mod h1:Xkxe497xwlCKkIaQYRfC7CSLworTXY9RMqwhhCm+8Nc= mvdan.cc/lint v0.0.0-20170908181259-adc824a0674b h1:DxJ5nJdkhDlLok9K6qO+5290kphDJbHOQO1DFFFTeBo= mvdan.cc/lint v0.0.0-20170908181259-adc824a0674b/go.mod h1:2odslEg/xrtNQqCYg2/jCoyKnw3vv5biOc3JnIcYfL4= -mvdan.cc/unparam v0.0.0-20190720180237-d51796306d8f h1:Cq7MalBHYACRd6EesksG1Q8EoIAKOsiZviGKbOLIej4= -mvdan.cc/unparam v0.0.0-20190720180237-d51796306d8f/go.mod h1:4G1h5nDURzA3bwVMZIVpwbkw+04kSxk3rAtzlimaUJw= +mvdan.cc/unparam v0.0.0-20211214103731-d0ef000c54e5 h1:Jh3LAeMt1eGpxomyu3jVkmVZWW2MxZ1qIIV2TZ/nRio= +mvdan.cc/unparam v0.0.0-20211214103731-d0ef000c54e5/go.mod h1:b8RRCBm0eeiWR8cfN88xeq2G5SG3VKGO+5UPWi5FSOY= +rsc.io/binaryregexp v0.2.0/go.mod h1:qTv7/COck+e2FymRvadv62gMdZztPaShugOCi3I+8D8= rsc.io/quote/v3 v3.1.0/go.mod h1:yEA65RcK8LyAZtP9Kv3t0HmxON59tX3rD+tICJqUlj0= rsc.io/sampler v1.3.0/go.mod h1:T1hPZKmBbMNahiBKFy5HrXp6adAjACjK9JXDnKaTXpA= +sigs.k8s.io/yaml v1.1.0/go.mod h1:UJmg0vDUVViEyp3mgSv9WPwZCDxu4rQW1olrI1uml+o= +sourcegraph.com/sourcegraph/appdash v0.0.0-20190731080439-ebfcffb1b5c0/go.mod h1:hI742Nqp5OhwiqlzhgfbWU4mW4yO10fP+LoT9WOswdU= sourcegraph.com/sourcegraph/go-diff v0.5.0/go.mod h1:kuch7UrkMzY0X+p9CRK03kfuPQ2zzQcaEFbx8wA8rck= -sourcegraph.com/sqs/pbtypes v0.0.0-20180604144634-d3ebe8f20ae4 h1:JPJh2pk3+X4lXAkZIk2RuE/7/FoK9maXw+TNPJhVS/c= sourcegraph.com/sqs/pbtypes v0.0.0-20180604144634-d3ebe8f20ae4/go.mod h1:ketZ/q3QxT9HOBeFhu6RdvsftgpsbFHBF5Cas6cDKZ0= diff --git a/test/dependencies/graphsync-get/graphsync-get.go b/test/dependencies/graphsync-get/graphsync-get.go index e15522116f2..169647260ca 100644 --- a/test/dependencies/graphsync-get/graphsync-get.go +++ b/test/dependencies/graphsync-get/graphsync-get.go @@ -11,7 +11,7 @@ import ( "github.com/ipfs/go-cid" "github.com/ipfs/go-datastore" dssync "github.com/ipfs/go-datastore/sync" - "github.com/ipfs/go-graphsync" + graphsync "github.com/ipfs/go-graphsync" gsimpl "github.com/ipfs/go-graphsync/impl" "github.com/ipfs/go-graphsync/network" "github.com/ipfs/go-graphsync/storeutil" @@ -21,7 +21,7 @@ import ( uio "github.com/ipfs/go-unixfs/io" "github.com/ipld/go-ipld-prime" cidlink "github.com/ipld/go-ipld-prime/linking/cid" - basicnode "github.com/ipld/go-ipld-prime/node/basic" + basicnode "github.com/ipld/go-ipld-prime/node/basicnode" ipldselector "github.com/ipld/go-ipld-prime/traversal/selector" "github.com/ipld/go-ipld-prime/traversal/selector/builder" "github.com/libp2p/go-libp2p" @@ -34,13 +34,12 @@ func newGraphsync(ctx context.Context, p2p host.Host, bs blockstore.Blockstore) network := network.NewFromLibp2pHost(p2p) return gsimpl.New(ctx, network, - storeutil.LoaderForBlockstore(bs), - storeutil.StorerForBlockstore(bs), + storeutil.LinkSystemForBlockstore(bs), ), nil } var selectAll ipld.Node = func() ipld.Node { - ssb := builder.NewSelectorSpecBuilder(basicnode.Style.Any) + ssb := builder.NewSelectorSpecBuilder(basicnode.Prototype.Any) return ssb.ExploreRecursive( ipldselector.RecursionLimitDepth(100), // default max ssb.ExploreAll(ssb.ExploreRecursiveEdge()), @@ -90,13 +89,14 @@ func main() { log.Fatalf("failed to decode CID '%q': %s", os.Args[2], err) } - ctx, cancel := context.WithCancel(context.Background()) - defer cancel() - - p2p, err := libp2p.New(ctx, libp2p.NoListenAddrs) + p2p, err := libp2p.New(libp2p.NoListenAddrs) if err != nil { log.Fatal(err) } + + ctx, cancel := context.WithCancel(context.Background()) + defer cancel() + err = p2p.Connect(ctx, *ai) if err != nil { log.Fatal(err) diff --git a/test/dependencies/ma-pipe-unidir/main.go b/test/dependencies/ma-pipe-unidir/main.go index db77f5fbae4..3cf10b4de17 100644 --- a/test/dependencies/ma-pipe-unidir/main.go +++ b/test/dependencies/ma-pipe-unidir/main.go @@ -9,7 +9,7 @@ import ( "strconv" ma "github.com/multiformats/go-multiaddr" - manet "github.com/multiformats/go-multiaddr-net" + manet "github.com/multiformats/go-multiaddr/net" ) const USAGE = "ma-pipe-unidir [-l|--listen] [--pidFile=path] [-h|--help] \n" diff --git a/test/dependencies/pollEndpoint/main.go b/test/dependencies/pollEndpoint/main.go index f3c19dbaf4a..0c548d8c9f2 100644 --- a/test/dependencies/pollEndpoint/main.go +++ b/test/dependencies/pollEndpoint/main.go @@ -12,7 +12,7 @@ import ( logging "github.com/ipfs/go-log" ma "github.com/multiformats/go-multiaddr" - manet "github.com/multiformats/go-multiaddr-net" + manet "github.com/multiformats/go-multiaddr/net" ) var ( From 3d527753ff4ee476ee06be283ef8c80e7610f98b Mon Sep 17 00:00:00 2001 From: Gus Eggert Date: Wed, 4 May 2022 18:49:32 +0200 Subject: [PATCH 383/414] feat: enable Resource Manager by default --- config/swarm.go | 2 +- core/node/libp2p/rcmgr.go | 3 +- core/node/libp2p/rcmgr_metrics.go | 40 +++++++----- docs/config.md | 5 +- .../t0116-prometheus-data/prometheus_metrics | 4 ++ test/sharness/t0139-swarm-rcmgr.sh | 62 +++++++++---------- 6 files changed, 61 insertions(+), 55 deletions(-) diff --git a/config/swarm.go b/config/swarm.go index 83f42a29543..2cd4e7194cc 100644 --- a/config/swarm.go +++ b/config/swarm.go @@ -138,7 +138,7 @@ type ConnMgr struct { // ResourceMgr defines configuration options for the libp2p Network Resource Manager // type ResourceMgr struct { - // Enables the Network Resource Manager feature + // Enables the Network Resource Manager feature, default to on. Enabled Flag `json:",omitempty"` Limits *rcmgr.BasicLimiterConfig `json:",omitempty"` } diff --git a/core/node/libp2p/rcmgr.go b/core/node/libp2p/rcmgr.go index 938f5eb43f9..28d05a131b4 100644 --- a/core/node/libp2p/rcmgr.go +++ b/core/node/libp2p/rcmgr.go @@ -29,8 +29,7 @@ func ResourceManager(cfg config.SwarmConfig) func(fx.Lifecycle, repo.Repo) (netw var manager network.ResourceManager var opts Libp2pOpts - // Config Swarm.ResourceMgr.Enabled decides if we run a real manager - enabled := cfg.ResourceMgr.Enabled.WithDefault(false) + enabled := cfg.ResourceMgr.Enabled.WithDefault(true) /// ENV overrides Config (if present) switch os.Getenv("LIBP2P_RCMGR") { diff --git a/core/node/libp2p/rcmgr_metrics.go b/core/node/libp2p/rcmgr_metrics.go index 56ccfa9d62d..48c54426cfe 100644 --- a/core/node/libp2p/rcmgr_metrics.go +++ b/core/node/libp2p/rcmgr_metrics.go @@ -1,6 +1,7 @@ package libp2p import ( + "errors" "strconv" "github.com/libp2p/go-libp2p-core/network" @@ -11,6 +12,17 @@ import ( "github.com/prometheus/client_golang/prometheus" ) +func mustRegister(c prometheus.Collector) { + err := prometheus.Register(c) + are := prometheus.AlreadyRegisteredError{} + if errors.As(err, &are) { + return + } + if err != nil { + panic(err) + } +} + func createRcmgrMetrics() rcmgr.MetricsReporter { const ( direction = "direction" @@ -26,7 +38,7 @@ func createRcmgrMetrics() rcmgr.MetricsReporter { }, []string{direction, usesFD}, ) - prometheus.MustRegister(connAllowed) + mustRegister(connAllowed) connBlocked := prometheus.NewCounterVec( prometheus.CounterOpts{ @@ -35,7 +47,7 @@ func createRcmgrMetrics() rcmgr.MetricsReporter { }, []string{direction, usesFD}, ) - prometheus.MustRegister(connBlocked) + mustRegister(connBlocked) streamAllowed := prometheus.NewCounterVec( prometheus.CounterOpts{ @@ -44,7 +56,7 @@ func createRcmgrMetrics() rcmgr.MetricsReporter { }, []string{direction}, ) - prometheus.MustRegister(streamAllowed) + mustRegister(streamAllowed) streamBlocked := prometheus.NewCounterVec( prometheus.CounterOpts{ @@ -53,19 +65,19 @@ func createRcmgrMetrics() rcmgr.MetricsReporter { }, []string{direction}, ) - prometheus.MustRegister(streamBlocked) + mustRegister(streamBlocked) peerAllowed := prometheus.NewCounter(prometheus.CounterOpts{ Name: "libp2p_rcmgr_peers_allowed_total", Help: "allowed peers", }) - prometheus.MustRegister(peerAllowed) + mustRegister(peerAllowed) peerBlocked := prometheus.NewCounter(prometheus.CounterOpts{ Name: "libp2p_rcmgr_peer_blocked_total", Help: "blocked peers", }) - prometheus.MustRegister(peerBlocked) + mustRegister(peerBlocked) protocolAllowed := prometheus.NewCounterVec( prometheus.CounterOpts{ @@ -74,7 +86,7 @@ func createRcmgrMetrics() rcmgr.MetricsReporter { }, []string{protocol}, ) - prometheus.MustRegister(protocolAllowed) + mustRegister(protocolAllowed) protocolBlocked := prometheus.NewCounterVec( prometheus.CounterOpts{ @@ -83,7 +95,7 @@ func createRcmgrMetrics() rcmgr.MetricsReporter { }, []string{protocol}, ) - prometheus.MustRegister(protocolBlocked) + mustRegister(protocolBlocked) protocolPeerBlocked := prometheus.NewCounterVec( prometheus.CounterOpts{ @@ -92,7 +104,7 @@ func createRcmgrMetrics() rcmgr.MetricsReporter { }, []string{protocol}, ) - prometheus.MustRegister(protocolPeerBlocked) + mustRegister(protocolPeerBlocked) serviceAllowed := prometheus.NewCounterVec( prometheus.CounterOpts{ @@ -101,7 +113,7 @@ func createRcmgrMetrics() rcmgr.MetricsReporter { }, []string{service}, ) - prometheus.MustRegister(serviceAllowed) + mustRegister(serviceAllowed) serviceBlocked := prometheus.NewCounterVec( prometheus.CounterOpts{ @@ -110,7 +122,7 @@ func createRcmgrMetrics() rcmgr.MetricsReporter { }, []string{service}, ) - prometheus.MustRegister(serviceBlocked) + mustRegister(serviceBlocked) servicePeerBlocked := prometheus.NewCounterVec( prometheus.CounterOpts{ @@ -119,19 +131,19 @@ func createRcmgrMetrics() rcmgr.MetricsReporter { }, []string{service}, ) - prometheus.MustRegister(servicePeerBlocked) + mustRegister(servicePeerBlocked) memoryAllowed := prometheus.NewCounter(prometheus.CounterOpts{ Name: "libp2p_rcmgr_memory_allocations_allowed_total", Help: "allowed memory allocations", }) - prometheus.MustRegister(memoryAllowed) + mustRegister(memoryAllowed) memoryBlocked := prometheus.NewCounter(prometheus.CounterOpts{ Name: "libp2p_rcmgr_memory_allocations_blocked_total", Help: "blocked memory allocations", }) - prometheus.MustRegister(memoryBlocked) + mustRegister(memoryBlocked) return rcmgrMetrics{ connAllowed, diff --git a/docs/config.md b/docs/config.md index 090bcdfa9a4..0a4b6c3c1bf 100644 --- a/docs/config.md +++ b/docs/config.md @@ -1632,13 +1632,10 @@ The [libp2p Network Resource Manager](https://github.com/libp2p/go-libp2p-resour and tracking recource usage over time. #### `Swarm.ResourceMgr.Enabled` - -**EXPERIMENTAL**: this feature is disabled by default, use with caution. - Enables the libp2p Network Resource Manager and auguments the default limits using user-defined ones in `Swarm.ResourceMgr.Limits` (if present). -Default: `false` +Default: `true` Type: `flag` diff --git a/test/sharness/t0116-prometheus-data/prometheus_metrics b/test/sharness/t0116-prometheus-data/prometheus_metrics index dd358e82f4f..adffa4c1b91 100644 --- a/test/sharness/t0116-prometheus-data/prometheus_metrics +++ b/test/sharness/t0116-prometheus-data/prometheus_metrics @@ -656,6 +656,10 @@ leveldb_datastore_sync_latency_seconds_bucket leveldb_datastore_sync_latency_seconds_count leveldb_datastore_sync_latency_seconds_sum leveldb_datastore_sync_total +libp2p_rcmgr_memory_allocations_allowed_total +libp2p_rcmgr_memory_allocations_blocked_total +libp2p_rcmgr_peer_blocked_total +libp2p_rcmgr_peers_allowed_total process_cpu_seconds_total process_max_fds process_open_fds diff --git a/test/sharness/t0139-swarm-rcmgr.sh b/test/sharness/t0139-swarm-rcmgr.sh index 659f508b166..89586300476 100755 --- a/test/sharness/t0139-swarm-rcmgr.sh +++ b/test/sharness/t0139-swarm-rcmgr.sh @@ -17,40 +17,10 @@ test_expect_success 'disconnected: swarm stats requires running daemon' ' test_should_contain "missing ResourceMgr" actual ' -# swarm limit|stats should fail in online mode by default -# because Resource Manager is opt-in +# swarm limit|stats should succeed in online mode by default +# because Resource Manager is opt-out test_launch_ipfs_daemon -test_expect_success 'ResourceMgr disabled by default: swarm limit requires Swarm.ResourceMgr.Enabled' ' - test_expect_code 1 ipfs swarm limit system 2> actual && - test_should_contain "missing ResourceMgr" actual -' -test_expect_success 'ResourceMgr disabled by default: swarm stats requires Swarm.ResourceMgr.Enabled' ' - test_expect_code 1 ipfs swarm stats all 2> actual && - test_should_contain "missing ResourceMgr" actual -' - -test_kill_ipfs_daemon - -test_expect_success "setting an invalid limit should result in a failure" " - test_expect_code 1 ipfs config --json Swarm.ResourceMgr.Limits.System.Conns 'asdf' 2> actual && - test_should_contain 'failed to unmarshal' actual -" - -# swarm limit|stat should work when Swarm.ResourceMgr.Enabled -test_expect_success "test enabling resource manager" " - ipfs config --json Swarm.ResourceMgr.Enabled true && - ipfs config --json Swarm.ResourceMgr && - jq -e '.Swarm.ResourceMgr.Enabled == true' < \"$IPFS_PATH/config\" -" - -test_launch_ipfs_daemon - -test_expect_success "test setting system conns limit" " - ipfs config --json Swarm.ResourceMgr.Enabled true && - ipfs config --json Swarm.ResourceMgr.Limits.System.Conns 99999 -" - # every scope has the same fields, so we only inspect System test_expect_success 'ResourceMgr enabled: swarm limit' ' ipfs swarm limit system --enc=json | tee json && @@ -79,13 +49,18 @@ test_expect_success 'ResourceMgr enabled: swarm stats' ' # shut down the daemon, set a limit in the config, and verify that it's applied test_kill_ipfs_daemon -test_expect_success "set system conn limit" " +test_expect_success "Set system conns limit while daemon is not running" " ipfs config --json Swarm.ResourceMgr.Limits.System.Conns 99999 " +test_expect_success "Set an invalid limit, which should result in a failure" " + test_expect_code 1 ipfs config --json Swarm.ResourceMgr.Limits.System.Conns 'asdf' 2> actual && + test_should_contain 'failed to unmarshal' actual +" + test_launch_ipfs_daemon -test_expect_success 'ResourceMgr enabled: swarm limit' ' +test_expect_success 'Ensure the new system conns limit is applied' ' ipfs swarm limit system --enc=json | tee json && jq -e ".Conns == 99999" < json ' @@ -152,4 +127,23 @@ test_expect_success 'Set limit for peer scope with an invalid peer ID' ' test_kill_ipfs_daemon +# test correct behavior when resource manager is disabled +test_expect_success 'Disable resource manager' ' + ipfs config --bool Swarm.ResourceMgr.Enabled false +' + +test_launch_ipfs_daemon + +test_expect_success 'Swarm limit should fail since RM is disabled' ' + test_expect_code 1 ipfs swarm limit system 2> actual && + test_should_contain "missing ResourceMgr" actual +' + +test_expect_success 'Swarm stats should fail since RM is disabled' ' + test_expect_code 1 ipfs swarm stats all 2> actual && + test_should_contain "missing ResourceMgr" actual +' + +test_kill_ipfs_daemon + test_done From 0ab4367160a56476fdd7a79ccbda5a2e9f376879 Mon Sep 17 00:00:00 2001 From: Gus Eggert Date: Wed, 4 May 2022 20:12:32 +0200 Subject: [PATCH 384/414] docs(tracing): update env var docs for new tracing env vars This should have been updated as part of 967bd6932 --- docs/environment-variables.md | 69 +++++++++++++++++------------------ 1 file changed, 34 insertions(+), 35 deletions(-) diff --git a/docs/environment-variables.md b/docs/environment-variables.md index aa87438eb46..90206664886 100644 --- a/docs/environment-variables.md +++ b/docs/environment-variables.md @@ -147,20 +147,45 @@ and outputs it to `rcmgr.json.gz` Default: disabled (not set) # Tracing +For advanced configuration (e.g. ratio-based sampling), see also: https://github.com/open-telemetry/opentelemetry-specification/blob/main/specification/sdk-environment-variables.md -## `IPFS_TRACING` -Enables OpenTelemetry tracing. +## `OTEL_TRACES_EXPORTER` +Specifies the exporters to use as a comma-separated string. Each exporter has a set of additional environment variables used to configure it. The following values are supported: + +- `otlp` +- `jaeger` +- `zipkin` +- `file` -- appends traces to a JSON file on the filesystem + +Setting this enables OpenTelemetry tracing. **NOTE** Tracing support is experimental: releases may contain tracing-related breaking changes. -Default: false +Default: "" (no exporters) -## `IPFS_TRACING_JAEGER` -Enables the Jaeger exporter for OpenTelemetry. +## `OTLP Exporter` +Unless specified in this section, the OTLP exporter uses the environment variables documented here: https://github.com/open-telemetry/opentelemetry-specification/blob/main/specification/protocol/exporter.md -For additional Jaeger exporter configuration, see: https://github.com/open-telemetry/opentelemetry-specification/blob/main/specification/sdk-environment-variables.md#jaeger-exporter +### `OTEL_EXPORTER_OTLP_PROTOCOL` +Specifies the OTLP protocol to use, which is one of: -Default: false +- `grpc` +- `http/protobuf` + +Default: "grpc" + +## `Jaeger Exporter` + +See: https://github.com/open-telemetry/opentelemetry-specification/blob/main/specification/sdk-environment-variables.md#jaeger-exporter + +## `Zipkin Exporter` +See: https://github.com/open-telemetry/opentelemetry-specification/blob/main/specification/sdk-environment-variables.md#zipkin-exporter + +## `File Exporter` +### `OTEL_EXPORTER_FILE_PATH` +Specifies the filesystem path for the JSON file. + +Default: "$PWD/traces.json" ### How to use Jaeger UI @@ -177,6 +202,7 @@ $ docker run --rm -it --name jaeger \ -p 5778:5778 \ -p 16686:16686 \ -p 14268:14268 \ + -p 14268:14269 \ -p 14250:14250 \ -p 9411:9411 \ jaegertracing/all-in-one @@ -184,34 +210,7 @@ $ docker run --rm -it --name jaeger \ Then, in other terminal, start go-ipfs with Jaeger tracing enabled: ``` -$ IPFS_TRACING=1 IPFS_TRACING_JAEGER=1 ipfs daemon +$ OTEL_TRACES_EXPORTER=jaeger ipfs daemon ``` Finally, the [Jaeger UI](https://github.com/jaegertracing/jaeger-ui#readme) is available at http://localhost:16686 - - -## `IPFS_TRACING_OTLP_HTTP` -Enables the OTLP HTTP exporter for OpenTelemetry. - -For additional exporter configuration, see: https://github.com/open-telemetry/opentelemetry-specification/blob/main/specification/protocol/exporter.md - -Default: false - -## `IPFS_TRACING_OTLP_GRPC` -Enables the OTLP gRPC exporter for OpenTelemetry. - -For additional exporter configuration, see: https://github.com/open-telemetry/opentelemetry-specification/blob/main/specification/protocol/exporter.md - -Default: false - -## `IPFS_TRACING_FILE` -Enables the file exporter for OpenTelemetry, writing traces to the given file in JSON format. - -Example: "/var/log/ipfs-traces.json" - -Default: "" (disabled) - -## `IPFS_TRACING_RATIO` -The ratio of traces to export, as a floating point value in the interval [0, 1]. - -Default: 1.0 (export all traces) From 34aac1ee43168d18456ec8659f0024841541b0d2 Mon Sep 17 00:00:00 2001 From: Adin Schmahmann Date: Wed, 4 May 2022 11:32:38 -0400 Subject: [PATCH 385/414] chore: update deps --- go.mod | 15 +++++++-------- go.sum | 35 ++++++++++++++++++++--------------- 2 files changed, 27 insertions(+), 23 deletions(-) diff --git a/go.mod b/go.mod index 31bf59cacbc..02da160329f 100644 --- a/go.mod +++ b/go.mod @@ -29,13 +29,13 @@ require ( github.com/ipfs/go-fetcher v1.6.1 github.com/ipfs/go-filestore v1.2.0 github.com/ipfs/go-fs-lock v0.0.7 - github.com/ipfs/go-graphsync v0.11.0 + github.com/ipfs/go-graphsync v0.13.1 github.com/ipfs/go-ipfs-blockstore v1.2.0 github.com/ipfs/go-ipfs-chunker v0.0.5 github.com/ipfs/go-ipfs-cmds v0.8.1 github.com/ipfs/go-ipfs-exchange-interface v0.1.0 github.com/ipfs/go-ipfs-exchange-offline v0.2.0 - github.com/ipfs/go-ipfs-files v0.0.9 + github.com/ipfs/go-ipfs-files v0.1.1 github.com/ipfs/go-ipfs-keystore v0.0.2 github.com/ipfs/go-ipfs-pinner v0.2.1 github.com/ipfs/go-ipfs-posinfo v0.0.1 @@ -45,7 +45,7 @@ require ( github.com/ipfs/go-ipld-cbor v0.0.5 github.com/ipfs/go-ipld-format v0.4.0 github.com/ipfs/go-ipld-git v0.1.1 - github.com/ipfs/go-ipld-legacy v0.1.0 + github.com/ipfs/go-ipld-legacy v0.1.1 github.com/ipfs/go-ipns v0.1.2 github.com/ipfs/go-log v1.0.5 github.com/ipfs/go-merkledag v0.6.0 @@ -53,10 +53,10 @@ require ( github.com/ipfs/go-metrics-prometheus v0.0.2 github.com/ipfs/go-mfs v0.2.1 github.com/ipfs/go-namesys v0.5.0 - github.com/ipfs/go-path v0.2.2 + github.com/ipfs/go-path v0.3.0 github.com/ipfs/go-pinning-service-http-client v0.1.1 github.com/ipfs/go-unixfs v0.3.1 - github.com/ipfs/go-unixfsnode v1.1.3 + github.com/ipfs/go-unixfsnode v1.4.0 github.com/ipfs/go-verifcid v0.0.1 github.com/ipfs/interface-go-ipfs-core v0.7.0 github.com/ipfs/tar-utils v0.0.2 @@ -69,7 +69,6 @@ require ( github.com/jbenet/goprocess v0.1.4 github.com/libp2p/go-doh-resolver v0.4.0 github.com/libp2p/go-libp2p v0.19.1 - github.com/libp2p/go-libp2p-connmgr v0.3.2-0.20220115145817-a7820a5879c7 // indirect github.com/libp2p/go-libp2p-core v0.15.1 github.com/libp2p/go-libp2p-discovery v0.6.0 github.com/libp2p/go-libp2p-http v0.2.1 @@ -79,7 +78,7 @@ require ( github.com/libp2p/go-libp2p-mplex v0.7.0 github.com/libp2p/go-libp2p-noise v0.4.0 github.com/libp2p/go-libp2p-peerstore v0.6.0 - github.com/libp2p/go-libp2p-pubsub v0.6.0 + github.com/libp2p/go-libp2p-pubsub v0.6.1 github.com/libp2p/go-libp2p-pubsub-router v0.5.0 github.com/libp2p/go-libp2p-quic-transport v0.17.0 github.com/libp2p/go-libp2p-record v0.1.3 @@ -174,7 +173,7 @@ require ( github.com/ipfs/go-ipfs-ds-help v1.1.0 // indirect github.com/ipfs/go-ipfs-pq v0.0.2 // indirect github.com/ipfs/go-log/v2 v2.5.1 // indirect - github.com/ipfs/go-peertaskqueue v0.7.0 // indirect + github.com/ipfs/go-peertaskqueue v0.7.1 // indirect github.com/jackpal/go-nat-pmp v1.0.2 // indirect github.com/klauspost/compress v1.15.1 // indirect github.com/klauspost/cpuid/v2 v2.0.12 // indirect diff --git a/go.sum b/go.sum index f398dfc688b..c34d0696896 100644 --- a/go.sum +++ b/go.sum @@ -510,8 +510,8 @@ github.com/ipfs/go-filestore v1.2.0 h1:O2wg7wdibwxkEDcl7xkuQsPvJFRBVgVSsOJ/GP6z3 github.com/ipfs/go-filestore v1.2.0/go.mod h1:HLJrCxRXquTeEEpde4lTLMaE/MYJZD7WHLkp9z6+FF8= github.com/ipfs/go-fs-lock v0.0.7 h1:6BR3dajORFrFTkb5EpCUFIAypsoxpGpDSVUdFwzgL9U= github.com/ipfs/go-fs-lock v0.0.7/go.mod h1:Js8ka+FNYmgQRLrRXzU3CB/+Csr1BwrRilEcvYrHhhc= -github.com/ipfs/go-graphsync v0.11.0 h1:PiiD5CnoC3xEHMW8d6uBGqGcoTwiMB5d9CORIEyF6iA= -github.com/ipfs/go-graphsync v0.11.0/go.mod h1:wC+c8vGVjAHthsVIl8LKr37cUra2GOaMYcQNNmMxDqE= +github.com/ipfs/go-graphsync v0.13.1 h1:lWiP/WLycoPUYyj3IDEi1GJNP30kFuYOvimcfeuZyQs= +github.com/ipfs/go-graphsync v0.13.1/go.mod h1:y8e8G6CmZeL9Srvx1l15CtGiRdf3h5JdQuqPz/iYL0A= github.com/ipfs/go-ipfs-blockstore v0.0.1/go.mod h1:d3WClOmRQKFnJ0Jz/jj/zmksX0ma1gROTlovZKBmN08= github.com/ipfs/go-ipfs-blockstore v0.1.0/go.mod h1:5aD0AvHPi7mZc6Ci1WCAhiBQu2IsfTduLl+422H6Rqw= github.com/ipfs/go-ipfs-blockstore v0.1.4/go.mod h1:Jxm3XMVjh6R17WvxFEiyKBLUGr86HgIYJW/D/MwqeYQ= @@ -542,8 +542,8 @@ github.com/ipfs/go-ipfs-exchange-offline v0.2.0 h1:2PF4o4A7W656rC0RxuhUace997FTc github.com/ipfs/go-ipfs-exchange-offline v0.2.0/go.mod h1:HjwBeW0dvZvfOMwDP0TSKXIHf2s+ksdP4E3MLDRtLKY= github.com/ipfs/go-ipfs-files v0.0.3/go.mod h1:INEFm0LL2LWXBhNJ2PMIIb2w45hpXgPjNoE7yA8Y1d4= github.com/ipfs/go-ipfs-files v0.0.8/go.mod h1:wiN/jSG8FKyk7N0WyctKSvq3ljIa2NNTiZB55kpTdOs= -github.com/ipfs/go-ipfs-files v0.0.9 h1:OFyOfmuVDu9c5YtjSDORmwXzE6fmZikzZpzsnNkgFEg= -github.com/ipfs/go-ipfs-files v0.0.9/go.mod h1:aFv2uQ/qxWpL/6lidWvnSQmaVqCrf0TBGoUr+C1Fo84= +github.com/ipfs/go-ipfs-files v0.1.1 h1:/MbEowmpLo9PJTEQk16m9rKzUHjeP4KRU9nWJyJO324= +github.com/ipfs/go-ipfs-files v0.1.1/go.mod h1:8xkIrMWH+Y5P7HvJ4Yc5XWwIW2e52dyXUiC0tZyjDbM= github.com/ipfs/go-ipfs-keystore v0.0.2 h1:Fa9xg9IFD1VbiZtrNLzsD0GuELVHUFXCWF64kCPfEXU= github.com/ipfs/go-ipfs-keystore v0.0.2/go.mod h1:H49tRmibOEs7gLMgbOsjC4dqh1u5e0R/SWuc2ScfgSo= github.com/ipfs/go-ipfs-pinner v0.2.1 h1:kw9hiqh2p8TatILYZ3WAfQQABby7SQARdrdA+5Z5QfY= @@ -575,8 +575,9 @@ github.com/ipfs/go-ipld-format v0.4.0 h1:yqJSaJftjmjc9jEOFYlpkwOLVKv68OD27jFLlSg github.com/ipfs/go-ipld-format v0.4.0/go.mod h1:co/SdBE8h99968X0hViiw1MNlh6fvxxnHpvVLnH7jSM= github.com/ipfs/go-ipld-git v0.1.1 h1:TWGnZjS0htmEmlMFEkA3ogrNCqWjIxwr16x1OsdhG+Y= github.com/ipfs/go-ipld-git v0.1.1/go.mod h1:+VyMqF5lMcJh4rwEppV0e6g4nCCHXThLYYDpKUkJubI= -github.com/ipfs/go-ipld-legacy v0.1.0 h1:wxkkc4k8cnvIGIjPO0waJCe7SHEyFgl+yQdafdjGrpA= github.com/ipfs/go-ipld-legacy v0.1.0/go.mod h1:86f5P/srAmh9GcIcWQR9lfFLZPrIyyXQeVlOWeeWEuI= +github.com/ipfs/go-ipld-legacy v0.1.1 h1:BvD8PEuqwBHLTKqlGFTHSwrwFOMkVESEvwIYwR2cdcc= +github.com/ipfs/go-ipld-legacy v0.1.1/go.mod h1:8AyKFCjgRPsQFf15ZQgDB8Din4DML/fOmKZkkFkrIEg= github.com/ipfs/go-ipns v0.1.2 h1:O/s/0ht+4Jl9+VoxoUo0zaHjnZUS+aBQIKTuzdZ/ucI= github.com/ipfs/go-ipns v0.1.2/go.mod h1:ioQ0j02o6jdIVW+bmi18f4k2gRf0AV3kZ9KeHYHICnQ= github.com/ipfs/go-log v0.0.1/go.mod h1:kL1d2/hzSpI0thNYjiKfjanbVNU+IIGA/WnNESY9leM= @@ -591,7 +592,6 @@ github.com/ipfs/go-log/v2 v2.0.5/go.mod h1:eZs4Xt4ZUJQFM3DlanGhy7TkwwawCZcSByscw github.com/ipfs/go-log/v2 v2.1.1/go.mod h1:2v2nsGfZsvvAJz13SyFzf9ObaqwHiHxsPLEHntrv9KM= github.com/ipfs/go-log/v2 v2.1.3/go.mod h1:/8d0SH3Su5Ooc31QlL1WysJhvyOTDCjcCZ9Axpmri6g= github.com/ipfs/go-log/v2 v2.3.0/go.mod h1:QqGoj30OTpnKaG/LKTGTxoP2mmQtjVMEnK72gynbe/g= -github.com/ipfs/go-log/v2 v2.4.0/go.mod h1:nPZnh7Cj7lwS3LpRU5Mwr2ol1c2gXIEXuF6aywqrtmo= github.com/ipfs/go-log/v2 v2.5.0/go.mod h1:prSpmC1Gpllc9UYWxDiZDreBYw7zp4Iqp1kOLU9U5UI= github.com/ipfs/go-log/v2 v2.5.1 h1:1XdUzF7048prq4aBjDQQ4SL5RxftpRGdXhNRwKSAlcY= github.com/ipfs/go-log/v2 v2.5.1/go.mod h1:prSpmC1Gpllc9UYWxDiZDreBYw7zp4Iqp1kOLU9U5UI= @@ -613,22 +613,23 @@ github.com/ipfs/go-path v0.0.7/go.mod h1:6KTKmeRnBXgqrTvzFrPV3CamxcgvXX/4z79tfAd github.com/ipfs/go-path v0.0.9/go.mod h1:VpDkSBKQ9EFQOUgi54Tq/O/tGi8n1RfYNks13M3DEs8= github.com/ipfs/go-path v0.1.1/go.mod h1:vC8q4AKOtrjJz2NnllIrmr2ZbGlF5fW2OKKyhV9ggb0= github.com/ipfs/go-path v0.2.1/go.mod h1:NOScsVgxfC/eIw4nz6OiGwK42PjaSJ4Y/ZFPn1Xe07I= -github.com/ipfs/go-path v0.2.2 h1:E2FEQX7iiwKfk58Kn/33SsAkN3+1fI4d3rYbjtF2h9o= -github.com/ipfs/go-path v0.2.2/go.mod h1:NOScsVgxfC/eIw4nz6OiGwK42PjaSJ4Y/ZFPn1Xe07I= +github.com/ipfs/go-path v0.3.0 h1:tkjga3MtpXyM5v+3EbRvOHEoo+frwi4oumw5K+KYWyA= +github.com/ipfs/go-path v0.3.0/go.mod h1:NOScsVgxfC/eIw4nz6OiGwK42PjaSJ4Y/ZFPn1Xe07I= github.com/ipfs/go-peertaskqueue v0.0.4/go.mod h1:03H8fhyeMfKNFWqzYEVyMbcPUeYrqP1MX6Kd+aN+rMQ= github.com/ipfs/go-peertaskqueue v0.1.0/go.mod h1:Jmk3IyCcfl1W3jTW3YpghSwSEC6IJ3Vzz/jUmWw8Z0U= github.com/ipfs/go-peertaskqueue v0.1.1/go.mod h1:Jmk3IyCcfl1W3jTW3YpghSwSEC6IJ3Vzz/jUmWw8Z0U= github.com/ipfs/go-peertaskqueue v0.2.0/go.mod h1:5/eNrBEbtSKWCG+kQK8K8fGNixoYUnr+P7jivavs9lY= -github.com/ipfs/go-peertaskqueue v0.7.0 h1:VyO6G4sbzX80K58N60cCaHsSsypbUNs1GjO5seGNsQ0= github.com/ipfs/go-peertaskqueue v0.7.0/go.mod h1:M/akTIE/z1jGNXMU7kFB4TeSEFvj68ow0Rrb04donIU= +github.com/ipfs/go-peertaskqueue v0.7.1 h1:7PLjon3RZwRQMgOTvYccZ+mjzkmds/7YzSWKFlBAypE= +github.com/ipfs/go-peertaskqueue v0.7.1/go.mod h1:M/akTIE/z1jGNXMU7kFB4TeSEFvj68ow0Rrb04donIU= github.com/ipfs/go-pinning-service-http-client v0.1.1 h1:Bar+Vi60A0zI8GSSrumVqnbFg6qkUgZSQTX9sV5jWrA= github.com/ipfs/go-pinning-service-http-client v0.1.1/go.mod h1:i6tC2nWOnJbZZUQPgxOlrg4CX8bhQZMh4II09FxvD58= github.com/ipfs/go-unixfs v0.2.4/go.mod h1:SUdisfUjNoSDzzhGVxvCL9QO/nKdwXdr+gbMUdqcbYw= github.com/ipfs/go-unixfs v0.3.1 h1:LrfED0OGfG98ZEegO4/xiprx2O+yS+krCMQSp7zLVv8= github.com/ipfs/go-unixfs v0.3.1/go.mod h1:h4qfQYzghiIc8ZNFKiLMFWOTzrWIAtzYQ59W/pCFf1o= github.com/ipfs/go-unixfsnode v1.1.2/go.mod h1:5dcE2x03pyjHk4JjamXmunTMzz+VUtqvPwZjIEkfV6s= -github.com/ipfs/go-unixfsnode v1.1.3 h1:IyqJBGIEvcHvll1wDDVIHOEVXnE+IH6tjzTWpZ6kGiI= -github.com/ipfs/go-unixfsnode v1.1.3/go.mod h1:ZZxUM5wXBC+G0Co9FjrYTOm+UlhZTjxLfRYdWY9veZ4= +github.com/ipfs/go-unixfsnode v1.4.0 h1:9BUxHBXrbNi8mWHc6j+5C580WJqtVw9uoeEKn4tMhwA= +github.com/ipfs/go-unixfsnode v1.4.0/go.mod h1:qc7YFFZ8tABc58p62HnIYbUMwj9chhUuFWmxSokfePo= github.com/ipfs/go-verifcid v0.0.1 h1:m2HI7zIuR5TFyQ1b79Da5N9dnnCP1vcu2QqawmWlK2E= github.com/ipfs/go-verifcid v0.0.1/go.mod h1:5Hrva5KBeIog4A+UpqlaIU+DEstipcJYQQZc0g37pY0= github.com/ipfs/interface-go-ipfs-core v0.4.0/go.mod h1:UJBcU6iNennuI05amq3FQ7g0JHUkibHFAfhfUIy927o= @@ -642,6 +643,7 @@ github.com/ipld/go-car/v2 v2.1.1 h1:saaKz4nC0AdfCGHLYKeXLGn8ivoPC54fyS55uyOLKwA= github.com/ipld/go-car/v2 v2.1.1/go.mod h1:+2Yvf0Z3wzkv7NeI69i8tuZ+ft7jyjPYIWZzeVNeFcI= github.com/ipld/go-codec-dagpb v1.2.0/go.mod h1:6nBN7X7h8EOsEejZGqC7tej5drsdBAXbMHyBT+Fne5s= github.com/ipld/go-codec-dagpb v1.3.0/go.mod h1:ga4JTU3abYApDC3pZ00BC2RSvC3qfBb9MSJkMLSwnhA= +github.com/ipld/go-codec-dagpb v1.3.1/go.mod h1:ErNNglIi5KMur/MfFE/svtgQthzVvf+43MrzLbpcIZY= github.com/ipld/go-codec-dagpb v1.4.0 h1:VqADPIFng8G4vz5EQytmmcx/2gEgOHfBuw/kIuCgDAY= github.com/ipld/go-codec-dagpb v1.4.0/go.mod h1:ErNNglIi5KMur/MfFE/svtgQthzVvf+43MrzLbpcIZY= github.com/ipld/go-ipld-prime v0.9.0/go.mod h1:KvBLMr4PX1gWptgkzRjVZCrLmSGcZCb/jioOQwCqZN8= @@ -792,9 +794,8 @@ github.com/libp2p/go-libp2p-circuit v0.2.1/go.mod h1:BXPwYDN5A8z4OEY9sOfr2DUQMLQ github.com/libp2p/go-libp2p-circuit v0.4.0/go.mod h1:t/ktoFIUzM6uLQ+o1G6NuBl2ANhBKN9Bc8jRIk31MoA= github.com/libp2p/go-libp2p-circuit v0.6.0 h1:rw/HlhmUB3OktS/Ygz6+2XABOmHKzZpPUuMNUMosj8w= github.com/libp2p/go-libp2p-circuit v0.6.0/go.mod h1:kB8hY+zCpMeScyvFrKrGicRdid6vNXbunKE4rXATZ0M= +github.com/libp2p/go-libp2p-connmgr v0.2.4 h1:TMS0vc0TCBomtQJyWr7fYxcVYYhx+q/2gF++G5Jkl/w= github.com/libp2p/go-libp2p-connmgr v0.2.4/go.mod h1:YV0b/RIm8NGPnnNWM7hG9Q38OeQiQfKhHCCs1++ufn0= -github.com/libp2p/go-libp2p-connmgr v0.3.2-0.20220115145817-a7820a5879c7 h1:74g7rKhKikoMDKNtpeSjttE5ELgpmk2gD7U1nqDgoPw= -github.com/libp2p/go-libp2p-connmgr v0.3.2-0.20220115145817-a7820a5879c7/go.mod h1:RVoyPjJm0J9Vd1m6qUN2Tn7kJm4rL1Ml20pFsFgPGik= github.com/libp2p/go-libp2p-core v0.0.1/go.mod h1:g/VxnTZ/1ygHxH3dKok7Vno1VfpvGcGip57wjTU4fco= github.com/libp2p/go-libp2p-core v0.0.2/go.mod h1:9dAcntw/n46XycV4RnlBq3BpgrmyUi9LuoTNdPrbUco= github.com/libp2p/go-libp2p-core v0.0.3/go.mod h1:j+YQMNz9WNSkNezXOsahp9kwZBKBvxLpKD316QWSJXE= @@ -825,7 +826,6 @@ github.com/libp2p/go-libp2p-core v0.9.0/go.mod h1:ESsbz31oC3C1AvMJoGx26RTuCkNhmk github.com/libp2p/go-libp2p-core v0.10.0/go.mod h1:ECdxehoYosLYHgDDFa2N4yE8Y7aQRAMf0sX9mf2sbGg= github.com/libp2p/go-libp2p-core v0.11.0/go.mod h1:ECdxehoYosLYHgDDFa2N4yE8Y7aQRAMf0sX9mf2sbGg= github.com/libp2p/go-libp2p-core v0.12.0/go.mod h1:ECdxehoYosLYHgDDFa2N4yE8Y7aQRAMf0sX9mf2sbGg= -github.com/libp2p/go-libp2p-core v0.13.0/go.mod h1:ECdxehoYosLYHgDDFa2N4yE8Y7aQRAMf0sX9mf2sbGg= github.com/libp2p/go-libp2p-core v0.14.0/go.mod h1:tLasfcVdTXnixsLB0QYaT1syJOhsbrhG7q6pGrHtBg8= github.com/libp2p/go-libp2p-core v0.15.1 h1:0RY+Mi/ARK9DgG1g9xVQLb8dDaaU8tCePMtGALEfBnM= github.com/libp2p/go-libp2p-core v0.15.1/go.mod h1:agSaboYM4hzB1cWekgVReqV5M4g5M+2eNNejV+1EEhs= @@ -905,8 +905,9 @@ github.com/libp2p/go-libp2p-pnet v0.2.0 h1:J6htxttBipJujEjz1y0a5+eYoiPcFHhSYHH6n github.com/libp2p/go-libp2p-pnet v0.2.0/go.mod h1:Qqvq6JH/oMZGwqs3N1Fqhv8NVhrdYcO0BW4wssv21LA= github.com/libp2p/go-libp2p-protocol v0.0.1/go.mod h1:Af9n4PiruirSDjHycM1QuiMi/1VZNHYcK8cLgFJLZ4s= github.com/libp2p/go-libp2p-protocol v0.1.0/go.mod h1:KQPHpAabB57XQxGrXCNvbL6UEXfQqUgC/1adR2Xtflk= -github.com/libp2p/go-libp2p-pubsub v0.6.0 h1:98+RXuEWW17U6cAijK1yaTf6mw/B+n5yPA421z+dlo0= github.com/libp2p/go-libp2p-pubsub v0.6.0/go.mod h1:nJv87QM2cU0w45KPR1rZicq+FmFIOD16zmT+ep1nOmg= +github.com/libp2p/go-libp2p-pubsub v0.6.1 h1:wycbV+f4rreCoVY61Do6g/BUk0RIrbNRcYVbn+QkjGk= +github.com/libp2p/go-libp2p-pubsub v0.6.1/go.mod h1:nJv87QM2cU0w45KPR1rZicq+FmFIOD16zmT+ep1nOmg= github.com/libp2p/go-libp2p-pubsub-router v0.5.0 h1:WuYdY42DVIJ+N0qMdq2du/E9poJH+xzsXL7Uptwj9tw= github.com/libp2p/go-libp2p-pubsub-router v0.5.0/go.mod h1:TRJKskSem3C0aSb3CmRgPwq6IleVFzds6hS09fmZbGM= github.com/libp2p/go-libp2p-quic-transport v0.10.0/go.mod h1:RfJbZ8IqXIhxBRm5hqUEJqjiiY8xmEuq3HUDS993MkA= @@ -1239,6 +1240,7 @@ github.com/multiformats/go-multibase v0.0.3/go.mod h1:5+1R4eQrT3PkYZ24C3W2Ue2tPw github.com/multiformats/go-multicodec v0.2.0/go.mod h1:/y4YVwkfMyry5kFbMTbLJKErhycTIftytRV+llXdyS4= github.com/multiformats/go-multicodec v0.3.0/go.mod h1:qGGaQmioCDh+TeFOnxrbU0DaIPw8yFgAZgFG0V7p1qQ= github.com/multiformats/go-multicodec v0.3.1-0.20210902112759-1539a079fd61/go.mod h1:1Hj/eHRaVWSXiSNNfcEPcwZleTmdNP81xlxDLnWU9GQ= +github.com/multiformats/go-multicodec v0.3.1-0.20211210143421-a526f306ed2c/go.mod h1:1Hj/eHRaVWSXiSNNfcEPcwZleTmdNP81xlxDLnWU9GQ= github.com/multiformats/go-multicodec v0.4.1 h1:BSJbf+zpghcZMZrwTYBGwy0CPcVZGWiC72Cp8bBd4R4= github.com/multiformats/go-multicodec v0.4.1/go.mod h1:1Hj/eHRaVWSXiSNNfcEPcwZleTmdNP81xlxDLnWU9GQ= github.com/multiformats/go-multihash v0.0.1/go.mod h1:w/5tugSrLEbWqlcgJabL3oHFKTwfvkofsjW2Qa1ct4U= @@ -1566,6 +1568,7 @@ go.opencensus.io v0.23.0/go.mod h1:XItmlyltB5F7CS4xOC1DcqMoFqwtC6OG2xF7mCv7P7E= go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.31.0 h1:woM+Mb4d0A+Dxa3rYPenSN5ZeS9qHUvE8rlObiLRXTY= go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.31.0/go.mod h1:PFmBsWbldL1kiWZk9+0LBZz2brhByaGsvp6pRICMlPE= go.opentelemetry.io/otel v0.20.0/go.mod h1:Y3ugLH2oa81t5QO+Lty+zXf8zC9L26ax4Nzoxm/dooo= +go.opentelemetry.io/otel v1.2.0/go.mod h1:aT17Fk0Z1Nor9e0uisf98LrntPGMnk4frBO9+dkf69I= go.opentelemetry.io/otel v1.6.0/go.mod h1:bfJD2DZVw0LBxghOTlgnlI0CV3hLDu9XF/QKOUXMTQQ= go.opentelemetry.io/otel v1.6.1/go.mod h1:blzUabWHkX6LJewxvadmzafgh/wnvBSDBdOuwkAtrWQ= go.opentelemetry.io/otel v1.6.3 h1:FLOfo8f9JzFVFVyU+MSRJc2HdEAXQgm7pIv2uFKRSZE= @@ -1589,9 +1592,11 @@ go.opentelemetry.io/otel/metric v0.28.0 h1:o5YNh+jxACMODoAo1bI7OES0RUW4jAMae0Vgs go.opentelemetry.io/otel/metric v0.28.0/go.mod h1:TrzsfQAmQaB1PDcdhBauLMk7nyyg9hm+GoQq/ekE9Iw= go.opentelemetry.io/otel/oteltest v0.20.0/go.mod h1:L7bgKf9ZB7qCwT9Up7i9/pn0PWIa9FqQ2IQ8LoxiGnw= go.opentelemetry.io/otel/sdk v0.20.0/go.mod h1:g/IcepuwNsoiX5Byy2nNV0ySUF1em498m7hBWC279Yc= +go.opentelemetry.io/otel/sdk v1.2.0/go.mod h1:jNN8QtpvbsKhgaC6V5lHiejMoKD+V8uadoSafgHPx1U= go.opentelemetry.io/otel/sdk v1.6.3 h1:prSHYdwCQOX5DrsEzxowH3nLhoAzEBdZhvrR79scfLs= go.opentelemetry.io/otel/sdk v1.6.3/go.mod h1:A4iWF7HTXa+GWL/AaqESz28VuSBIcZ+0CV+IzJ5NMiQ= go.opentelemetry.io/otel/trace v0.20.0/go.mod h1:6GjCW8zgDjwGHGa6GkyeB8+/5vjT16gUEi0Nf1iBdgw= +go.opentelemetry.io/otel/trace v1.2.0/go.mod h1:N5FLswTubnxKxOJHM7XZC074qpeEdLy3CgAVsdMucK0= go.opentelemetry.io/otel/trace v1.6.0/go.mod h1:qs7BrU5cZ8dXQHBGxHMOxwME/27YH2qEp4/+tZLLwJE= go.opentelemetry.io/otel/trace v1.6.1/go.mod h1:RkFRM1m0puWIq10oxImnGEduNBzxiN7TXluRBtE+5j0= go.opentelemetry.io/otel/trace v1.6.3 h1:IqN4L+5b0mPNjdXIiZ90Ni4Bl5BRkDQywePLWemd9bc= From 8ec5718c56c559e5e0d9a31a406953bf0382864d Mon Sep 17 00:00:00 2001 From: Adin Schmahmann Date: Tue, 3 May 2022 14:11:30 -0400 Subject: [PATCH 386/414] chore: build with go 1.18.1 --- .circleci/main.yml | 10 +++++----- .github/workflows/golang-analysis.yml | 2 +- Dockerfile | 2 +- snap/snapcraft.yaml | 2 +- 4 files changed, 8 insertions(+), 8 deletions(-) diff --git a/.circleci/main.yml b/.circleci/main.yml index 8e3265dec9c..a3bfb6db088 100644 --- a/.circleci/main.yml +++ b/.circleci/main.yml @@ -36,7 +36,7 @@ default_environment: &default_environment executors: golang: docker: - - image: cimg/go:1.17.9 + - image: cimg/go:1.18.1 working_directory: ~/ipfs/go-ipfs environment: <<: *default_environment @@ -61,7 +61,7 @@ executors: E2E_IPFSD_TYPE: go dockerizer: docker: - - image: cimg/go:1.17.9 + - image: cimg/go:1.18.1 environment: IMAGE_NAME: ipfs/go-ipfs WIP_IMAGE_TAG: wip @@ -161,8 +161,8 @@ jobs: - run: sudo apt update - run: | mkdir ~/localgo && cd ~/localgo - wget https://golang.org/dl/go1.17.9.linux-amd64.tar.gz - tar xfz go1.17.9.linux-amd64.tar.gz + wget https://golang.org/dl/go1.18.1.linux-amd64.tar.gz + tar xfz go1.18.1.linux-amd64.tar.gz echo "export PATH=$(pwd)/go/bin:\$PATH" >> ~/.bashrc - run: go version - run: sudo apt install socat net-tools @@ -228,7 +228,7 @@ jobs: - *store_gomod interop: docker: - - image: cimg/go:1.17.9-node + - image: cimg/go:1.18.1-node parallelism: 4 resource_class: large steps: diff --git a/.github/workflows/golang-analysis.yml b/.github/workflows/golang-analysis.yml index 12cd73078b5..d9a57faa424 100644 --- a/.github/workflows/golang-analysis.yml +++ b/.github/workflows/golang-analysis.yml @@ -11,7 +11,7 @@ jobs: submodules: recursive - uses: actions/setup-go@v2 with: - go-version: "1.17.x" + go-version: "1.18.x" - name: Check that go.mod is tidy uses: protocol/multiple-go-modules@v1.2 with: diff --git a/Dockerfile b/Dockerfile index 4f7725f289a..0df0477aecb 100644 --- a/Dockerfile +++ b/Dockerfile @@ -1,5 +1,5 @@ # Note: when updating the go minor version here, also update the go-channel in snap/snapcraft.yml -FROM golang:1.17.9-buster +FROM golang:1.18.1-buster LABEL maintainer="Steven Allen " # Install deps diff --git a/snap/snapcraft.yaml b/snap/snapcraft.yaml index 5852fa8846b..c9d73395f61 100644 --- a/snap/snapcraft.yaml +++ b/snap/snapcraft.yaml @@ -29,7 +29,7 @@ parts: source-tag: master plugin: go # keep me up to date with the go version that go-ipfs expects to be built with. - go-channel: 1.17/stable + go-channel: 1.18/stable go-importpath: github.com/ipfs/go-ipfs build-packages: - build-essential From ff832cb9922a774d69cf1a4db880a37251ec12ba Mon Sep 17 00:00:00 2001 From: Adin Schmahmann Date: Wed, 4 May 2022 10:54:52 -0400 Subject: [PATCH 387/414] docker: disable buildvcs for docker builds --- Dockerfile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Dockerfile b/Dockerfile index 0df0477aecb..81d43825270 100644 --- a/Dockerfile +++ b/Dockerfile @@ -25,7 +25,7 @@ ARG IPFS_PLUGINS # Also: fix getting HEAD commit hash via git rev-parse. RUN cd $SRC_DIR \ && mkdir -p .git/objects \ - && make build GOTAGS=openssl IPFS_PLUGINS=$IPFS_PLUGINS + && GOFLAGS=-buildvcs=false make build GOTAGS=openssl IPFS_PLUGINS=$IPFS_PLUGINS # Get su-exec, a very minimal tool for dropping privileges, # and tini, a very minimal init daemon for containers From 6d2f790f7686bb18bfce7ba25e1ca1472fbb9b63 Mon Sep 17 00:00:00 2001 From: Adin Schmahmann Date: Wed, 4 May 2022 11:07:45 -0400 Subject: [PATCH 388/414] chore: update example deps --- docs/examples/go-ipfs-as-a-library/go.mod | 187 +++++---- docs/examples/go-ipfs-as-a-library/go.sum | 464 ++++++++++++++++----- docs/examples/go-ipfs-as-a-library/main.go | 2 +- 3 files changed, 460 insertions(+), 193 deletions(-) diff --git a/docs/examples/go-ipfs-as-a-library/go.mod b/docs/examples/go-ipfs-as-a-library/go.mod index c332efc8c8e..9d574ed0450 100644 --- a/docs/examples/go-ipfs-as-a-library/go.mod +++ b/docs/examples/go-ipfs-as-a-library/go.mod @@ -3,12 +3,11 @@ module github.com/ipfs/go-ipfs/examples/go-ipfs-as-a-library go 1.17 require ( - github.com/ipfs/go-ipfs v0.11.0 - github.com/ipfs/go-ipfs-config v0.18.0 - github.com/ipfs/go-ipfs-files v0.0.9 - github.com/ipfs/interface-go-ipfs-core v0.5.2 - github.com/libp2p/go-libp2p-core v0.11.0 - github.com/multiformats/go-multiaddr v0.4.1 + github.com/ipfs/go-ipfs v0.12.3-0.20220504184349-34aac1ee4316 + github.com/ipfs/go-ipfs-files v0.1.1 + github.com/ipfs/interface-go-ipfs-core v0.7.0 + github.com/libp2p/go-libp2p-core v0.15.1 + github.com/multiformats/go-multiaddr v0.5.0 ) require ( @@ -17,42 +16,51 @@ require ( github.com/Stebalien/go-bitfield v0.0.1 // indirect github.com/alecthomas/units v0.0.0-20210927113745-59d0afb8317a // indirect github.com/alexbrainman/goissue34681 v0.0.0-20191006012335-3fc7a47baff5 // indirect - github.com/benbjohnson/clock v1.1.0 // indirect + github.com/benbjohnson/clock v1.3.0 // indirect github.com/beorn7/perks v1.0.1 // indirect github.com/blang/semver/v4 v4.0.0 // indirect github.com/btcsuite/btcd v0.22.0-beta // indirect github.com/cenkalti/backoff v2.2.1+incompatible // indirect + github.com/cenkalti/backoff/v4 v4.1.2 // indirect github.com/ceramicnetwork/go-dag-jose v0.1.0 // indirect github.com/cespare/xxhash v1.1.0 // indirect - github.com/cespare/xxhash/v2 v2.1.1 // indirect + github.com/cespare/xxhash/v2 v2.1.2 // indirect github.com/cheekybits/genny v1.0.0 // indirect + github.com/containerd/cgroups v1.0.3 // indirect + github.com/coreos/go-systemd/v22 v22.3.2 // indirect github.com/crackcomm/go-gitignore v0.0.0-20170627025303-887ab5e44cc3 // indirect github.com/cskr/pubsub v1.0.2 // indirect github.com/davidlazar/go-crypto v0.0.0-20200604182044-b73af7476f6c // indirect github.com/dgraph-io/badger v1.6.2 // indirect github.com/dgraph-io/ristretto v0.0.2 // indirect + github.com/docker/go-units v0.4.0 // indirect github.com/dustin/go-humanize v1.0.0 // indirect + github.com/elastic/gosigar v0.14.2 // indirect github.com/facebookgo/atomicfile v0.0.0-20151019160806-2de1f203e7d5 // indirect github.com/flynn/noise v1.0.0 // indirect github.com/francoispqt/gojay v1.2.13 // indirect github.com/fsnotify/fsnotify v1.5.1 // indirect + github.com/go-logr/logr v1.2.3 // indirect + github.com/go-logr/stdr v1.2.2 // indirect github.com/go-task/slim-sprig v0.0.0-20210107165309-348f09dbbbc0 // indirect + github.com/godbus/dbus/v5 v5.1.0 // indirect github.com/gogo/protobuf v1.3.2 // indirect github.com/golang/protobuf v1.5.2 // indirect - github.com/golang/snappy v0.0.0-20180518054509-2e65f85255db // indirect + github.com/golang/snappy v0.0.4 // indirect github.com/google/gopacket v1.1.19 // indirect github.com/google/uuid v1.3.0 // indirect - github.com/gorilla/websocket v1.4.2 // indirect + github.com/gorilla/websocket v1.5.0 // indirect + github.com/grpc-ecosystem/grpc-gateway/v2 v2.7.0 // indirect github.com/hannahhoward/go-pubsub v0.0.0-20200423002714-8d62886cc36e // indirect github.com/hashicorp/errwrap v1.0.0 // indirect github.com/hashicorp/go-multierror v1.1.1 // indirect github.com/hashicorp/golang-lru v0.5.4 // indirect - github.com/huin/goupnp v1.0.2 // indirect + github.com/huin/goupnp v1.0.3 // indirect github.com/ipfs/bbloom v0.0.4 // indirect github.com/ipfs/go-bitfield v1.0.0 // indirect - github.com/ipfs/go-bitswap v0.5.1 // indirect + github.com/ipfs/go-bitswap v0.6.0 // indirect github.com/ipfs/go-block-format v0.0.3 // indirect - github.com/ipfs/go-blockservice v0.2.1 // indirect + github.com/ipfs/go-blockservice v0.3.0 // indirect github.com/ipfs/go-cid v0.1.0 // indirect github.com/ipfs/go-cidutil v0.0.2 // indirect github.com/ipfs/go-datastore v0.5.1 // indirect @@ -61,15 +69,15 @@ require ( github.com/ipfs/go-ds-leveldb v0.5.0 // indirect github.com/ipfs/go-ds-measure v0.2.0 // indirect github.com/ipfs/go-fetcher v1.6.1 // indirect - github.com/ipfs/go-filestore v0.1.0 // indirect + github.com/ipfs/go-filestore v1.2.0 // indirect github.com/ipfs/go-fs-lock v0.0.7 // indirect - github.com/ipfs/go-graphsync v0.11.0 // indirect - github.com/ipfs/go-ipfs-blockstore v0.2.1 // indirect + github.com/ipfs/go-graphsync v0.13.1 // indirect + github.com/ipfs/go-ipfs-blockstore v1.2.0 // indirect github.com/ipfs/go-ipfs-chunker v0.0.5 // indirect github.com/ipfs/go-ipfs-delay v0.0.1 // indirect - github.com/ipfs/go-ipfs-ds-help v0.1.1 // indirect + github.com/ipfs/go-ipfs-ds-help v1.1.0 // indirect github.com/ipfs/go-ipfs-exchange-interface v0.1.0 // indirect - github.com/ipfs/go-ipfs-exchange-offline v0.1.1 // indirect + github.com/ipfs/go-ipfs-exchange-offline v0.2.0 // indirect github.com/ipfs/go-ipfs-keystore v0.0.2 // indirect github.com/ipfs/go-ipfs-pinner v0.2.1 // indirect github.com/ipfs/go-ipfs-posinfo v0.0.1 // indirect @@ -78,108 +86,114 @@ require ( github.com/ipfs/go-ipfs-routing v0.2.1 // indirect github.com/ipfs/go-ipfs-util v0.0.2 // indirect github.com/ipfs/go-ipld-cbor v0.0.5 // indirect - github.com/ipfs/go-ipld-format v0.2.0 // indirect + github.com/ipfs/go-ipld-format v0.4.0 // indirect github.com/ipfs/go-ipld-git v0.1.1 // indirect - github.com/ipfs/go-ipld-legacy v0.1.0 // indirect + github.com/ipfs/go-ipld-legacy v0.1.1 // indirect github.com/ipfs/go-ipns v0.1.2 // indirect github.com/ipfs/go-log v1.0.5 // indirect - github.com/ipfs/go-log/v2 v2.3.0 // indirect - github.com/ipfs/go-merkledag v0.5.1 // indirect + github.com/ipfs/go-log/v2 v2.5.1 // indirect + github.com/ipfs/go-merkledag v0.6.0 // indirect github.com/ipfs/go-metrics-interface v0.0.1 // indirect github.com/ipfs/go-mfs v0.2.1 // indirect - github.com/ipfs/go-namesys v0.4.0 // indirect - github.com/ipfs/go-path v0.2.1 // indirect - github.com/ipfs/go-peertaskqueue v0.7.0 // indirect + github.com/ipfs/go-namesys v0.5.0 // indirect + github.com/ipfs/go-path v0.3.0 // indirect + github.com/ipfs/go-peertaskqueue v0.7.1 // indirect github.com/ipfs/go-unixfs v0.3.1 // indirect - github.com/ipfs/go-unixfsnode v1.1.3 // indirect + github.com/ipfs/go-unixfsnode v1.4.0 // indirect github.com/ipfs/go-verifcid v0.0.1 // indirect - github.com/ipld/go-codec-dagpb v1.3.0 // indirect - github.com/ipld/go-ipld-prime v0.14.2 // indirect + github.com/ipld/go-codec-dagpb v1.4.0 // indirect + github.com/ipld/go-ipld-prime v0.16.0 // indirect github.com/jackpal/go-nat-pmp v1.0.2 // indirect github.com/jbenet/go-temp-err-catcher v0.1.0 // indirect github.com/jbenet/goprocess v0.1.4 // indirect - github.com/klauspost/compress v1.11.7 // indirect - github.com/klauspost/cpuid/v2 v2.0.9 // indirect + github.com/klauspost/compress v1.15.1 // indirect + github.com/klauspost/cpuid/v2 v2.0.12 // indirect github.com/koron/go-ssdp v0.0.2 // indirect - github.com/libp2p/go-addr-util v0.1.0 // indirect github.com/libp2p/go-buffer-pool v0.0.2 // indirect github.com/libp2p/go-cidranger v1.1.0 // indirect github.com/libp2p/go-conn-security-multistream v0.3.0 // indirect - github.com/libp2p/go-doh-resolver v0.3.1 // indirect + github.com/libp2p/go-doh-resolver v0.4.0 // indirect github.com/libp2p/go-eventbus v0.2.1 // indirect github.com/libp2p/go-flow-metrics v0.0.3 // indirect - github.com/libp2p/go-libp2p v0.16.0 // indirect - github.com/libp2p/go-libp2p-asn-util v0.1.0 // indirect - github.com/libp2p/go-libp2p-autonat v0.6.0 // indirect - github.com/libp2p/go-libp2p-blankhost v0.2.0 // indirect - github.com/libp2p/go-libp2p-connmgr v0.2.4 // indirect + github.com/libp2p/go-libp2p v0.19.1 // indirect + github.com/libp2p/go-libp2p-asn-util v0.2.0 // indirect + github.com/libp2p/go-libp2p-blankhost v0.3.0 // indirect github.com/libp2p/go-libp2p-discovery v0.6.0 // indirect github.com/libp2p/go-libp2p-kad-dht v0.15.0 // indirect github.com/libp2p/go-libp2p-kbucket v0.4.7 // indirect github.com/libp2p/go-libp2p-loggables v0.1.0 // indirect - github.com/libp2p/go-libp2p-mplex v0.4.1 // indirect + github.com/libp2p/go-libp2p-mplex v0.7.0 // indirect github.com/libp2p/go-libp2p-nat v0.1.0 // indirect - github.com/libp2p/go-libp2p-noise v0.3.0 // indirect - github.com/libp2p/go-libp2p-peerstore v0.4.0 // indirect + github.com/libp2p/go-libp2p-noise v0.4.0 // indirect + github.com/libp2p/go-libp2p-peerstore v0.6.0 // indirect github.com/libp2p/go-libp2p-pnet v0.2.0 // indirect - github.com/libp2p/go-libp2p-pubsub v0.6.0 // indirect + github.com/libp2p/go-libp2p-pubsub v0.6.1 // indirect github.com/libp2p/go-libp2p-pubsub-router v0.5.0 // indirect - github.com/libp2p/go-libp2p-quic-transport v0.15.0 // indirect + github.com/libp2p/go-libp2p-quic-transport v0.17.0 // indirect github.com/libp2p/go-libp2p-record v0.1.3 // indirect + github.com/libp2p/go-libp2p-resource-manager v0.3.0 // indirect github.com/libp2p/go-libp2p-routing-helpers v0.2.3 // indirect - github.com/libp2p/go-libp2p-swarm v0.8.0 // indirect - github.com/libp2p/go-libp2p-tls v0.3.1 // indirect - github.com/libp2p/go-libp2p-transport-upgrader v0.5.0 // indirect + github.com/libp2p/go-libp2p-swarm v0.10.2 // indirect + github.com/libp2p/go-libp2p-tls v0.4.1 // indirect + github.com/libp2p/go-libp2p-transport-upgrader v0.7.1 // indirect github.com/libp2p/go-libp2p-xor v0.0.0-20210714161855-5c005aca55db // indirect - github.com/libp2p/go-libp2p-yamux v0.6.0 // indirect - github.com/libp2p/go-maddr-filter v0.1.0 // indirect - github.com/libp2p/go-mplex v0.3.0 // indirect - github.com/libp2p/go-msgio v0.1.0 // indirect + github.com/libp2p/go-libp2p-yamux v0.9.1 // indirect + github.com/libp2p/go-mplex v0.7.0 // indirect + github.com/libp2p/go-msgio v0.2.0 // indirect github.com/libp2p/go-nat v0.1.0 // indirect - github.com/libp2p/go-netroute v0.1.6 // indirect + github.com/libp2p/go-netroute v0.2.0 // indirect github.com/libp2p/go-openssl v0.0.7 // indirect github.com/libp2p/go-reuseport v0.1.0 // indirect github.com/libp2p/go-reuseport-transport v0.1.0 // indirect - github.com/libp2p/go-sockaddr v0.1.1 // indirect - github.com/libp2p/go-stream-muxer-multistream v0.3.0 // indirect - github.com/libp2p/go-tcp-transport v0.4.0 // indirect - github.com/libp2p/go-ws-transport v0.5.0 // indirect - github.com/libp2p/go-yamux/v2 v2.3.0 // indirect + github.com/libp2p/go-stream-muxer-multistream v0.4.0 // indirect + github.com/libp2p/go-tcp-transport v0.5.1 // indirect + github.com/libp2p/go-ws-transport v0.6.0 // indirect + github.com/libp2p/go-yamux/v3 v3.1.1 // indirect github.com/libp2p/zeroconf/v2 v2.1.1 // indirect - github.com/lucas-clemente/quic-go v0.24.0 // indirect - github.com/marten-seemann/qtls-go1-16 v0.1.4 // indirect - github.com/marten-seemann/qtls-go1-17 v0.1.0 // indirect + github.com/lucas-clemente/quic-go v0.27.0 // indirect + github.com/marten-seemann/qtls-go1-16 v0.1.5 // indirect + github.com/marten-seemann/qtls-go1-17 v0.1.1 // indirect + github.com/marten-seemann/qtls-go1-18 v0.1.1 // indirect github.com/marten-seemann/tcp v0.0.0-20210406111302-dfbc87cc63fd // indirect - github.com/mattn/go-isatty v0.0.13 // indirect + github.com/mattn/go-isatty v0.0.14 // indirect github.com/matttproud/golang_protobuf_extensions v1.0.1 // indirect - github.com/miekg/dns v1.1.43 // indirect + github.com/miekg/dns v1.1.48 // indirect github.com/mikioh/tcpinfo v0.0.0-20190314235526-30a79bb1804b // indirect github.com/mikioh/tcpopt v0.0.0-20190314235656-172688c1accc // indirect github.com/minio/blake2b-simd v0.0.0-20160723061019-3f5f724cb5b1 // indirect github.com/minio/sha256-simd v1.0.0 // indirect github.com/mitchellh/go-homedir v1.1.0 // indirect github.com/mr-tron/base58 v1.2.0 // indirect - github.com/multiformats/go-base32 v0.0.3 // indirect + github.com/multiformats/go-base32 v0.0.4 // indirect github.com/multiformats/go-base36 v0.1.0 // indirect github.com/multiformats/go-multiaddr-dns v0.3.1 // indirect github.com/multiformats/go-multiaddr-fmt v0.1.0 // indirect github.com/multiformats/go-multibase v0.0.3 // indirect - github.com/multiformats/go-multicodec v0.3.0 // indirect + github.com/multiformats/go-multicodec v0.4.1 // indirect github.com/multiformats/go-multihash v0.1.0 // indirect - github.com/multiformats/go-multistream v0.2.2 // indirect + github.com/multiformats/go-multistream v0.3.0 // indirect github.com/multiformats/go-varint v0.0.6 // indirect github.com/nxadm/tail v1.4.8 // indirect - github.com/onsi/ginkgo v1.16.4 // indirect + github.com/onsi/ginkgo v1.16.5 // indirect + github.com/opencontainers/runtime-spec v1.0.2 // indirect github.com/opentracing/opentracing-go v1.2.0 // indirect + github.com/openzipkin/zipkin-go v0.4.0 // indirect + github.com/pbnjay/memory v0.0.0-20210728143218-7b4eea64cf58 // indirect github.com/pkg/errors v0.9.1 // indirect github.com/polydawn/refmt v0.0.0-20201211092308-30ac6d18308e // indirect - github.com/prometheus/client_golang v1.11.0 // indirect + github.com/prometheus/client_golang v1.12.1 // indirect github.com/prometheus/client_model v0.2.0 // indirect - github.com/prometheus/common v0.30.0 // indirect + github.com/prometheus/common v0.33.0 // indirect github.com/prometheus/procfs v0.7.3 // indirect + github.com/raulk/clock v1.1.0 // indirect + github.com/raulk/go-watchdog v1.2.0 // indirect github.com/spacemonkeygo/spacelog v0.0.0-20180420211403-2296661a0572 // indirect github.com/spaolacci/murmur3 v1.1.0 // indirect github.com/syndtr/goleveldb v1.0.0 // indirect + github.com/tidwall/gjson v1.14.0 // indirect + github.com/tidwall/match v1.1.1 // indirect + github.com/tidwall/pretty v1.2.0 // indirect + github.com/wI2L/jsondiff v0.2.0 // indirect github.com/whyrusleeping/base32 v0.0.0-20170828182744-c30ac30633cc // indirect github.com/whyrusleeping/cbor-gen v0.0.0-20210219115102-f37d292932f2 // indirect github.com/whyrusleeping/chunker v0.0.0-20181014151217-fe64bd25879f // indirect @@ -188,24 +202,35 @@ require ( github.com/whyrusleeping/multiaddr-filter v0.0.0-20160516205228-e903e4adabd7 // indirect github.com/whyrusleeping/timecache v0.0.0-20160911033111-cfcb2f1abfee // indirect go.opencensus.io v0.23.0 // indirect - go.opentelemetry.io/otel v0.20.0 // indirect - go.opentelemetry.io/otel/metric v0.20.0 // indirect - go.opentelemetry.io/otel/trace v0.20.0 // indirect + go.opentelemetry.io/otel v1.6.3 // indirect + go.opentelemetry.io/otel/exporters/jaeger v1.6.3 // indirect + go.opentelemetry.io/otel/exporters/otlp/internal/retry v1.6.3 // indirect + go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.6.3 // indirect + go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.6.3 // indirect + go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp v1.6.3 // indirect + go.opentelemetry.io/otel/exporters/stdout/stdouttrace v1.6.3 // indirect + go.opentelemetry.io/otel/exporters/zipkin v1.6.3 // indirect + go.opentelemetry.io/otel/sdk v1.6.3 // indirect + go.opentelemetry.io/otel/trace v1.6.3 // indirect + go.opentelemetry.io/proto/otlp v0.15.0 // indirect go.uber.org/atomic v1.9.0 // indirect - go.uber.org/dig v1.12.0 // indirect - go.uber.org/fx v1.15.0 // indirect - go.uber.org/multierr v1.7.0 // indirect - go.uber.org/zap v1.19.1 // indirect + go.uber.org/dig v1.14.0 // indirect + go.uber.org/fx v1.16.0 // indirect + go.uber.org/multierr v1.8.0 // indirect + go.uber.org/zap v1.21.0 // indirect go4.org v0.0.0-20200411211856-f5505b9728dd // indirect - golang.org/x/crypto v0.0.0-20210921155107-089bfa567519 // indirect - golang.org/x/mod v0.4.2 // indirect - golang.org/x/net v0.0.0-20210813160813-60bc85c4be6d // indirect + golang.org/x/crypto v0.0.0-20220411220226-7b82a4e95df4 // indirect + golang.org/x/mod v0.6.0-dev.0.20220106191415-9b9b3d81d5e3 // indirect + golang.org/x/net v0.0.0-20220418201149-a630d4f3e7a2 // indirect golang.org/x/sync v0.0.0-20210220032951-036812b2e83c // indirect - golang.org/x/sys v0.0.0-20211025112917-711f33c9992c // indirect - golang.org/x/tools v0.1.5 // indirect - golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1 // indirect - google.golang.org/protobuf v1.27.1 // indirect + golang.org/x/sys v0.0.0-20220412211240-33da011f77ad // indirect + golang.org/x/text v0.3.7 // indirect + golang.org/x/tools v0.1.10 // indirect + golang.org/x/xerrors v0.0.0-20220411194840-2f41105eb62f // indirect + google.golang.org/genproto v0.0.0-20211118181313-81c1377c94b1 // indirect + google.golang.org/grpc v1.45.0 // indirect + google.golang.org/protobuf v1.28.0 // indirect gopkg.in/square/go-jose.v2 v2.5.1 // indirect gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7 // indirect - lukechampine.com/blake3 v1.1.6 // indirect + lukechampine.com/blake3 v1.1.7 // indirect ) diff --git a/docs/examples/go-ipfs-as-a-library/go.sum b/docs/examples/go-ipfs-as-a-library/go.sum index fc17b80c9eb..6b9a1421255 100644 --- a/docs/examples/go-ipfs-as-a-library/go.sum +++ b/docs/examples/go-ipfs-as-a-library/go.sum @@ -37,6 +37,7 @@ cloud.google.com/go/storage v1.10.0/go.mod h1:FLPqc6j+Ki4BU591ie1oL6qBQGu2Bl/tZ9 contrib.go.opencensus.io/exporter/prometheus v0.4.0/go.mod h1:o7cosnyfuPVK0tB8q0QmaQNhGnptITnPQB+z1+qeFB0= dmitri.shuralyov.com/app/changes v0.0.0-20180602232624-0a106ad413e3/go.mod h1:Yl+fi1br7+Rr3LqpNJf1/uxUdtRUV+Tnj0o93V2B9MU= dmitri.shuralyov.com/gpu/mtl v0.0.0-20190408044501-666a987793e9/go.mod h1:H6x//7gZCb22OMCxBHrMx7a5I7Hp++hsVxbQ4BYO7hU= +dmitri.shuralyov.com/gpu/mtl v0.0.0-20201218220906-28db891af037/go.mod h1:H6x//7gZCb22OMCxBHrMx7a5I7Hp++hsVxbQ4BYO7hU= dmitri.shuralyov.com/html/belt v0.0.0-20180602232347-f7d459c86be0/go.mod h1:JLBrvjyP0v+ecvNYvCpyZgu5/xkfAUhi6wJj28eUfSU= dmitri.shuralyov.com/service/change v0.0.0-20181023043359-a85b471d5412/go.mod h1:a1inKt/atXimZ4Mv927x+r7UpyzRUf4emIoiiSC2TN4= dmitri.shuralyov.com/state v0.0.0-20180228185332-28bcc343414c/go.mod h1:0PRwlb0D6DFvNNtx+9ybjezNCa8XF0xaYcETyp6rHWU= @@ -52,7 +53,9 @@ github.com/Kubuxu/go-os-helper v0.0.1/go.mod h1:N8B+I7vPCT80IcP58r50u4+gEEcsZETF github.com/OneOfOne/xxhash v1.2.2 h1:KMrpdQIwFcEqXDklaen+P1axHaj9BSKzvpUUfnHldSE= github.com/OneOfOne/xxhash v1.2.2/go.mod h1:HSdplMjZKSmBqAxg5vPj2TmRDmfkzw+cTzAElWljhcU= github.com/Shopify/sarama v1.19.0/go.mod h1:FVkBWblsNy7DGZRfXLU0O9RCGt5g3g3yEuWXgklEdEo= +github.com/Shopify/sarama v1.30.0/go.mod h1:zujlQQx1kzHsh4jfV1USnptCQrHAEZ2Hk8fTKCulPVs= github.com/Shopify/toxiproxy v2.1.4+incompatible/go.mod h1:OXgGpZ6Cli1/URJOF1DMxUHB2q5Ap20/P/eIdh4G0pI= +github.com/Shopify/toxiproxy/v2 v2.1.6-0.20210914104332-15ea381dcdae/go.mod h1:/cvHQkZ1fst0EmZnA5dFtiQdWCNCFYzb+uE2vqVgvx0= github.com/Stebalien/go-bitfield v0.0.1 h1:X3kbSSPUaJK60wV2hjOPZwmpljr6VGCqdq4cBLhbQBo= github.com/Stebalien/go-bitfield v0.0.1/go.mod h1:GNjFpasyUVkHMsfEOk8EFLJ9syQ6SI+XWrX9Wf2XH0s= github.com/VividCortex/gohistogram v1.0.0/go.mod h1:Pf5mBqqDxYaXu3hDrrU+w6nw50o/4+TcAqDqk/vUH7g= @@ -81,8 +84,9 @@ github.com/aws/aws-sdk-go v1.27.0/go.mod h1:KmX6BPdI08NWTb3/sm4ZGu5ShLoqVDhKgpiN github.com/aws/aws-sdk-go-v2 v0.18.0/go.mod h1:JWVYvqSMppoMJC0x5wdwiImzgXTI9FuZwxzkQq9wy+g= github.com/benbjohnson/clock v1.0.2/go.mod h1:bGMdMPoPVvcYyt1gHDf4J2KE153Yf9BuiUKYMaxlTDM= github.com/benbjohnson/clock v1.0.3/go.mod h1:bGMdMPoPVvcYyt1gHDf4J2KE153Yf9BuiUKYMaxlTDM= -github.com/benbjohnson/clock v1.1.0 h1:Q92kusRqC1XV2MjkWETPvjJVqKetz1OzxZB7mHJLju8= github.com/benbjohnson/clock v1.1.0/go.mod h1:J11/hYXuz8f4ySSvYwY0FKfm+ezbsZBKZxNJlLklBHA= +github.com/benbjohnson/clock v1.3.0 h1:ip6w0uFQkncKQ979AypyG0ER7mqUSBdKLOgAle/AT8A= +github.com/benbjohnson/clock v1.3.0/go.mod h1:J11/hYXuz8f4ySSvYwY0FKfm+ezbsZBKZxNJlLklBHA= github.com/beorn7/perks v0.0.0-20180321164747-3a771d992973/go.mod h1:Dwedo/Wpr24TaqPxmxbtue+5NUziq4I4S80YR8gNf3Q= github.com/beorn7/perks v1.0.0/go.mod h1:KWe93zE9D1o94FZ5RNwFwVgaQK1VOXiVxmqh+CedLV8= github.com/beorn7/perks v1.0.1 h1:VlbKKnNfV8bJzeqoa4cOKqO6bYr3WgKZxO8Z16+hsOM= @@ -115,26 +119,38 @@ github.com/buger/jsonparser v0.0.0-20181115193947-bf1c66bbce23/go.mod h1:bbYlZJ7 github.com/casbin/casbin/v2 v2.1.2/go.mod h1:YcPU1XXisHhLzuxH9coDNf2FbKpjGlbCg3n9yuLkIJQ= github.com/cenkalti/backoff v2.2.1+incompatible h1:tNowT99t7UNflLxfYYSlKYsBpXdEet03Pg2g16Swow4= github.com/cenkalti/backoff v2.2.1+incompatible/go.mod h1:90ReRw6GdpyfrHakVjL/QHaoyV4aDUVVkXQJJJ3NXXM= +github.com/cenkalti/backoff/v4 v4.1.2 h1:6Yo7N8UP2K6LWZnW94DLVSSrbobcWdVzAYOisuDPIFo= +github.com/cenkalti/backoff/v4 v4.1.2/go.mod h1:scbssz8iZGpm3xbr14ovlUdkxfGXNInqkPWOWmG2CLw= github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU= github.com/ceramicnetwork/go-dag-jose v0.1.0 h1:yJ/HVlfKpnD3LdYP03AHyTvbm3BpPiz2oZiOeReJRdU= github.com/ceramicnetwork/go-dag-jose v0.1.0/go.mod h1:qYA1nYt0X8u4XoMAVoOV3upUVKtrxy/I670Dg5F0wjI= github.com/cespare/xxhash v1.1.0 h1:a6HrQnmkObjyL+Gs60czilIUGqrzKutQD6XZog3p+ko= github.com/cespare/xxhash v1.1.0/go.mod h1:XrSqR1VqqWfGrhpAt58auRo0WTKS1nRRg3ghfAqPWnc= -github.com/cespare/xxhash/v2 v2.1.1 h1:6MnRN8NT7+YBpUIWxHtefFZOKTAPgGjpQSxqLNn0+qY= github.com/cespare/xxhash/v2 v2.1.1/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= +github.com/cespare/xxhash/v2 v2.1.2 h1:YRXhKfTDauu4ajMg1TPgFO5jnlC2HCbmLXMcTG5cbYE= +github.com/cespare/xxhash/v2 v2.1.2/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= github.com/cheekybits/genny v1.0.0 h1:uGGa4nei+j20rOSeDeP5Of12XVm7TGUd4dJA9RDitfE= github.com/cheekybits/genny v1.0.0/go.mod h1:+tQajlRqAUrPI7DOSpB0XAqZYtQakVtB7wXkRAgjxjQ= github.com/cheggaaa/pb v1.0.29/go.mod h1:W40334L7FMC5JKWldsTWbdGjLo0RxUKK73K+TuPxX30= github.com/chzyer/logex v1.1.10/go.mod h1:+Ywpsq7O8HXn0nuIou7OrIPyXbp3wmkHB+jjWRnGsAI= github.com/chzyer/readline v0.0.0-20180603132655-2972be24d48e/go.mod h1:nSuG5e5PlCu98SY8svDHJxuZscDgtXS6KTTbou5AhLI= github.com/chzyer/test v0.0.0-20180213035817-a1ea475d72b1/go.mod h1:Q3SI9o4m/ZMnBNeIyt5eFwwo7qiLfzFZmjNmxjkiQlU= +github.com/cilium/ebpf v0.2.0/go.mod h1:To2CFviqOWL/M0gIMsvSMlqe7em/l1ALkX1PyjrX2Qs= +github.com/cilium/ebpf v0.4.0/go.mod h1:4tRaxcgiL706VnOzHOdBlY8IEAIdxINsQBcU4xJJXRs= github.com/clbanning/x2j v0.0.0-20191024224557-825249438eec/go.mod h1:jMjuTZXRI4dUb/I5gc9Hdhagfvm9+RyrPryS/auMzxE= github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw= github.com/cncf/udpa/go v0.0.0-20191209042840-269d4d468f6f/go.mod h1:M8M6+tZqaGXZJjfX53e64911xZQV5JYwmTeXPW+k8Sc= github.com/cncf/udpa/go v0.0.0-20201120205902-5459f2c99403/go.mod h1:WmhPx2Nbnhtbo57+VJT5O0JRkEi1Wbu0z5j0R8u5Hbk= +github.com/cncf/udpa/go v0.0.0-20210930031921-04548b0d99d4/go.mod h1:6pvJx4me5XPnfI9Z40ddWsdw2W/uZgQLFXToKeRcDiI= github.com/cncf/xds/go v0.0.0-20210312221358-fbca930ec8ed/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs= +github.com/cncf/xds/go v0.0.0-20210805033703-aa0b78936158/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs= +github.com/cncf/xds/go v0.0.0-20210922020428-25de7278fc84/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs= +github.com/cncf/xds/go v0.0.0-20211011173535-cb28da3451f1/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs= github.com/cockroachdb/datadriven v0.0.0-20190809214429-80d97fb3cbaa/go.mod h1:zn76sxSg3SzpJ0PPJaLDCu+Bu0Lg3sKTORVIj19EIF8= github.com/codahale/hdrhistogram v0.0.0-20161010025455-3a0bb77429bd/go.mod h1:sE/e/2PUdi/liOCUjSTXgM1o87ZssimdTWN964YiIeI= +github.com/containerd/cgroups v0.0.0-20201119153540-4cbc285b3327/go.mod h1:ZJeTFisyysqgcCdecO57Dj79RfL0LNeGiFUqLYQRYLE= +github.com/containerd/cgroups v1.0.3 h1:ADZftAkglvCiD44c77s5YmMqaP2pzVCFZvBmAlBdAP4= +github.com/containerd/cgroups v1.0.3/go.mod h1:/ofk34relqNjSGyqPrmEULrO4Sc8LJhvJmWbUCUKqj8= github.com/coreos/etcd v3.3.10+incompatible/go.mod h1:uF7uidLiAD3TWHmW31ZFd/JWoc32PjwdhPthX9715RE= github.com/coreos/go-etcd v2.0.0+incompatible/go.mod h1:Jez6KQU2B/sWsbdaef3ED8NzMklzPG4d5KIOhIy30Tk= github.com/coreos/go-semver v0.2.0/go.mod h1:nnelYz7RCh+5ahJtPPxZlU+153eP4D4r3EedlOD2RNk= @@ -143,11 +159,16 @@ github.com/coreos/go-semver v0.3.0 h1:wkHLiw0WNATZnSG7epLsujiMCgPAc9xhjJ4tgnAxmf github.com/coreos/go-semver v0.3.0/go.mod h1:nnelYz7RCh+5ahJtPPxZlU+153eP4D4r3EedlOD2RNk= github.com/coreos/go-systemd v0.0.0-20180511133405-39ca1b05acc7/go.mod h1:F5haX7vjVVG0kc13fIWeqUViNPyEJxv/OmvnBo0Yme4= github.com/coreos/go-systemd v0.0.0-20181012123002-c6f51f82210d/go.mod h1:F5haX7vjVVG0kc13fIWeqUViNPyEJxv/OmvnBo0Yme4= +github.com/coreos/go-systemd v0.0.0-20190321100706-95778dfbb74e h1:Wf6HqHfScWJN9/ZjdUKyjop4mf3Qdd+1TvvltAvM3m8= +github.com/coreos/go-systemd v0.0.0-20190321100706-95778dfbb74e/go.mod h1:F5haX7vjVVG0kc13fIWeqUViNPyEJxv/OmvnBo0Yme4= github.com/coreos/go-systemd/v22 v22.0.0/go.mod h1:xO0FLkIi5MaZafQlIrOotqXZ90ih+1atmu1JpKERPPk= +github.com/coreos/go-systemd/v22 v22.1.0/go.mod h1:xO0FLkIi5MaZafQlIrOotqXZ90ih+1atmu1JpKERPPk= +github.com/coreos/go-systemd/v22 v22.3.2 h1:D9/bQk5vlXQFZ6Kwuu6zaiXJ9oTPe68++AzAJc1DzSI= github.com/coreos/go-systemd/v22 v22.3.2/go.mod h1:Y58oyj3AT4RCenI/lSvhwexgC+NSVTIJ3seZv2GcEnc= github.com/coreos/pkg v0.0.0-20160727233714-3ac0863d7acf/go.mod h1:E3G3o1h8I7cfcXa63jLwjI0eiQQMgzzUDFVpN/nH/eA= github.com/cpuguy83/go-md2man v1.0.10/go.mod h1:SmD6nW6nTyfqj6ABTjUi3V3JVMnlJmwcJI5acqYI6dE= github.com/cpuguy83/go-md2man/v2 v2.0.0-20190314233015-f79a8a8ca69d/go.mod h1:maD7wRr/U5Z6m/iR4s+kqSMx2CaBsrgA7czyZG/E6dU= +github.com/cpuguy83/go-md2man/v2 v2.0.0/go.mod h1:maD7wRr/U5Z6m/iR4s+kqSMx2CaBsrgA7czyZG/E6dU= github.com/crackcomm/go-gitignore v0.0.0-20170627025303-887ab5e44cc3 h1:HVTnpeuvF6Owjd5mniCL8DEXo7uYXdQEmOP4FJbV5tg= github.com/crackcomm/go-gitignore v0.0.0-20170627025303-887ab5e44cc3/go.mod h1:p1d6YEZWvFzEh4KLyvBcVSnrfNDDvK2zfK/4x2v/4pE= github.com/creack/pty v1.1.7/go.mod h1:lj5s0c3V2DBrqTV7llrYr5NG6My20zk30Fl46Y7DoTY= @@ -174,13 +195,19 @@ github.com/dgrijalva/jwt-go v3.2.0+incompatible/go.mod h1:E3ru+11k8xSBh+hMPgOLZm github.com/dgryski/go-farm v0.0.0-20190104051053-3adb47b1fb0f/go.mod h1:SqUrOPUnsFjfmXRMNPybcSiG0BgUW2AuFH8PAnS2iTw= github.com/dgryski/go-farm v0.0.0-20190423205320-6a90982ecee2 h1:tdlZCpZ/P9DhczCTSixgIKmwPv6+wP5DGjqLYw5SUiA= github.com/dgryski/go-farm v0.0.0-20190423205320-6a90982ecee2/go.mod h1:SqUrOPUnsFjfmXRMNPybcSiG0BgUW2AuFH8PAnS2iTw= +github.com/docker/go-units v0.4.0 h1:3uh0PgVws3nIA0Q+MwDC8yjEPf9zjRfZZWXZYDct3Tw= +github.com/docker/go-units v0.4.0/go.mod h1:fgPhTUdO+D/Jk86RDLlptpiXQzgHJF7gydDDbaIK4Dk= github.com/dustin/go-humanize v0.0.0-20171111073723-bb3d318650d4/go.mod h1:HtrtbFcZ19U5GC7JDqmcUSB87Iq5E25KnS6fMYU6eOk= github.com/dustin/go-humanize v1.0.0 h1:VSnTsYCnlFHaM2/igO1h6X3HA71jcobQuxemgkq4zYo= github.com/dustin/go-humanize v1.0.0/go.mod h1:HtrtbFcZ19U5GC7JDqmcUSB87Iq5E25KnS6fMYU6eOk= github.com/eapache/go-resiliency v1.1.0/go.mod h1:kFI+JgMyC7bLPUVY133qvEBtVayf5mFgVsvEsIPBvNs= +github.com/eapache/go-resiliency v1.2.0/go.mod h1:kFI+JgMyC7bLPUVY133qvEBtVayf5mFgVsvEsIPBvNs= github.com/eapache/go-xerial-snappy v0.0.0-20180814174437-776d5712da21/go.mod h1:+020luEh2TKB4/GOp8oxxtq0Daoen/Cii55CzbTV6DU= github.com/eapache/queue v1.1.0/go.mod h1:6eCeP0CKFpHLu8blIFXhExK/dRa7WDZfr6jVFPTqq+I= github.com/edsrzf/mmap-go v1.0.0/go.mod h1:YO35OhQPt3KJa3ryjFM5Bs14WD66h8eGKpfaBNrHW5M= +github.com/elastic/gosigar v0.12.0/go.mod h1:iXRIGg2tLnu7LBdpqzyQfGDEidKCfWcCMS0WKyPWoMs= +github.com/elastic/gosigar v0.14.2 h1:Dg80n8cr90OZ7x+bAax/QjoW/XqTI11RmA79ZwIm9/4= +github.com/elastic/gosigar v0.14.2/go.mod h1:iXRIGg2tLnu7LBdpqzyQfGDEidKCfWcCMS0WKyPWoMs= github.com/elgris/jsondiff v0.0.0-20160530203242-765b5c24c302/go.mod h1:qBlWZqWeVx9BjvqBsnC/8RUlAYpIFmPvgROcw0n1scE= github.com/envoyproxy/go-control-plane v0.6.9/go.mod h1:SBwIajubJHhxtWwsL9s8ss4safvEdbitLhGGK48rN6g= github.com/envoyproxy/go-control-plane v0.9.0/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4= @@ -188,22 +215,26 @@ github.com/envoyproxy/go-control-plane v0.9.1-0.20191026205805-5f8ba28d4473/go.m github.com/envoyproxy/go-control-plane v0.9.4/go.mod h1:6rpuAdCZL397s3pYoYcLgu1mIlRU8Am5FuJP05cCM98= github.com/envoyproxy/go-control-plane v0.9.9-0.20201210154907-fd9021fe5dad/go.mod h1:cXg6YxExXjJnVBQHBLXeUAgxn2UodCpnH306RInaBQk= github.com/envoyproxy/go-control-plane v0.9.9-0.20210512163311-63b5d3c536b0/go.mod h1:hliV/p42l8fGbc6Y9bQ70uLwIvmJyVE5k4iMKlh8wCQ= +github.com/envoyproxy/go-control-plane v0.9.10-0.20210907150352-cf90f659a021/go.mod h1:AFq3mo9L8Lqqiid3OhADV3RfLJnjiw63cSpi+fDTRC0= github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c= github.com/facebookgo/atomicfile v0.0.0-20151019160806-2de1f203e7d5 h1:BBso6MBKW8ncyZLv37o+KNyy0HrrHgfnOaGQC2qvN+A= github.com/facebookgo/atomicfile v0.0.0-20151019160806-2de1f203e7d5/go.mod h1:JpoxHjuQauoxiFMl1ie8Xc/7TfLuMZ5eOCONd1sUBHg= github.com/fatih/color v1.7.0/go.mod h1:Zm6kSWBoL9eyXnKyktHP6abPY2pDugNf5KwzbycvMj4= github.com/fatih/color v1.9.0/go.mod h1:eQcE1qtQxscV5RaZvpXrrb8Drkc3/DdQ+uUYCNjL+zU= +github.com/felixge/httpsnoop v1.0.2/go.mod h1:m8KPJKqk1gH5J9DgRY2ASl2lWCfGKXixSwevea8zH2U= github.com/flynn/go-shlex v0.0.0-20150515145356-3f9db97f8568/go.mod h1:xEzjJPgXI435gkrCt3MPfRiAkVrwSbHsst4LCFVfpJc= github.com/flynn/noise v0.0.0-20180327030543-2492fe189ae6/go.mod h1:1i71OnUq3iUe1ma7Lr6yG6/rjvM3emb6yoL7xLFzcVQ= github.com/flynn/noise v1.0.0 h1:DlTHqmzmvcEiKj+4RYo/imoswx/4r6iBlCMfVtrMXpQ= github.com/flynn/noise v1.0.0/go.mod h1:xbMo+0i6+IGbYdJhF31t2eR1BIU0CYc12+BNAKwUTag= +github.com/fortytw2/leaktest v1.3.0/go.mod h1:jDsjWgpAGjm2CA7WthBh/CdZYEPF31XHquHwclZch5g= github.com/francoispqt/gojay v1.2.13 h1:d2m3sFjloqoIUQU3TsHBgj6qg/BVGlTBeHDUmyJnXKk= github.com/francoispqt/gojay v1.2.13/go.mod h1:ehT5mTG4ua4581f1++1WLG0vPdaA9HaiDsoyrBGkyDY= github.com/franela/goblin v0.0.0-20200105215937-c9ffbefa60db/go.mod h1:7dvUGVsVBjqR7JHJk0brhHOZYGmfBYOrK0ZhYMEtBr4= github.com/franela/goreq v0.0.0-20171204163338-bcd34c9993f8/go.mod h1:ZhphrRTfi2rbfLwlschooIH4+wKKDR4Pdxhh+TRoA20= github.com/frankban/quicktest v1.11.3/go.mod h1:wRf/ReqHper53s+kmmSZizM8NamnL3IM0I9ntUbOk+k= -github.com/frankban/quicktest v1.14.0 h1:+cqqvzZV87b4adx/5ayVOaYZ2CrvM4ejQvUdBzPPUss= github.com/frankban/quicktest v1.14.0/go.mod h1:NeW+ay9A/U67EYXNFA1nPE8e/tnQv/09mUdL/ijj8og= +github.com/frankban/quicktest v1.14.2 h1:SPb1KFFmM+ybpEjPUhCCkZOM5xlovT5UbrMvWnXyBns= +github.com/frankban/quicktest v1.14.2/go.mod h1:mgiwOwqx65TmIk1wJ6Q7wvnVMocbUorkibMOrVTHZps= github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo= github.com/fsnotify/fsnotify v1.4.9/go.mod h1:znqG4EE+3YCdAaPaxE2ZRY/06pZUdp0tY4IgpuI1SZQ= github.com/fsnotify/fsnotify v1.5.1 h1:mZcQUHVQUQWoPXXtuf9yuEXKudkV2sx1E06UadKWpgI= @@ -211,7 +242,6 @@ github.com/fsnotify/fsnotify v1.5.1/go.mod h1:T3375wBYaZdLLcVNkcVbzGHY7f1l/uK5T5 github.com/gabriel-vasile/mimetype v1.4.0/go.mod h1:fA8fi6KUiG7MgQQ+mEWotXoEOvmxRtOJlERCzSmRvr8= github.com/ghodss/yaml v1.0.0/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04= github.com/gliderlabs/ssh v0.1.1/go.mod h1:U7qILu1NlMHj9FlMhZLlkCdDnU1DBEAqr0aevW3Awn0= -github.com/go-bindata/go-bindata/v3 v3.1.3/go.mod h1:1/zrpXsLD8YDIbhZRqXzm1Ghc7NhEvIN9+Z6R5/xH4I= github.com/go-check/check v0.0.0-20180628173108-788fd7840127/go.mod h1:9ES+weclKsC9YodN5RgxqK/VD9HM9JsCSh7rNhMZE98= github.com/go-errors/errors v1.0.1/go.mod h1:f4zRHt4oKfwPJE5k8C9vpYG+aDHdBFUsgrm6/TyX73Q= github.com/go-gl/glfw v0.0.0-20190409004039-e6da0acd62b1/go.mod h1:vR7hzQXu2zJy9AVAgeJqvqgH9Q5CA+iKCZ2gyEVpxRU= @@ -221,15 +251,25 @@ github.com/go-kit/kit v0.8.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2 github.com/go-kit/kit v0.9.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as= github.com/go-kit/kit v0.10.0/go.mod h1:xUsJbQ/Fp4kEt7AFgCuvyX4a71u8h9jB8tj/ORgOZ7o= github.com/go-kit/log v0.1.0/go.mod h1:zbhenjAZHb184qTLMA9ZjW7ThYL0H2mk7Q6pNt4vbaY= +github.com/go-kit/log v0.2.0/go.mod h1:NwTd00d/i8cPZ3xOwwiv2PO5MOcx78fFErGNcVmBjv0= github.com/go-logfmt/logfmt v0.3.0/go.mod h1:Qt1PoO58o5twSAckw1HlFXLmHsOX5/0LbT9GBnD5lWE= github.com/go-logfmt/logfmt v0.4.0/go.mod h1:3RMwSq7FuexP4Kalkev3ejPJsZTpXXBr9+V4qmtdjCk= github.com/go-logfmt/logfmt v0.5.0/go.mod h1:wCYkCAKZfumFQihp8CzCvQ3paCTfi41vtzG1KdI/P7A= +github.com/go-logfmt/logfmt v0.5.1/go.mod h1:WYhtIu8zTZfxdn5+rREduYbwxfcBr/Vr6KEVveWlfTs= +github.com/go-logr/logr v0.4.0/go.mod h1:z6/tIYblkpsD+a4lm/fGIIU9mZ+XfAiaFtq7xTgseGU= +github.com/go-logr/logr v1.2.2/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A= +github.com/go-logr/logr v1.2.3 h1:2DntVwHkVopvECVRSlL5PSo9eG+cAkDCuckLubN+rq0= +github.com/go-logr/logr v1.2.3/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A= +github.com/go-logr/stdr v1.2.2 h1:hSWxHoqTgW2S2qGc0LTAI563KZ5YKYRhT3MFKZMbjag= +github.com/go-logr/stdr v1.2.2/go.mod h1:mMo/vtBO5dYbehREoey6XUKy/eSumjCCveDpRre4VKE= github.com/go-sql-driver/mysql v1.4.0/go.mod h1:zAC/RDZ24gD3HViQzih4MyKcchzm+sOG5ZlKdlhCg5w= github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY= github.com/go-task/slim-sprig v0.0.0-20210107165309-348f09dbbbc0 h1:p104kn46Q8WdvHunIJ9dAyjPVtrBPhSr3KT2yUst43I= github.com/go-task/slim-sprig v0.0.0-20210107165309-348f09dbbbc0/go.mod h1:fyg7847qk6SyHyPtNmDHnmrv/HOrqktSC+C9fM+CJOE= github.com/godbus/dbus/v5 v5.0.3/go.mod h1:xhWf0FNVPg57R7Z0UbKHbJfkEywrmjJnf7w5xrFpKfA= github.com/godbus/dbus/v5 v5.0.4/go.mod h1:xhWf0FNVPg57R7Z0UbKHbJfkEywrmjJnf7w5xrFpKfA= +github.com/godbus/dbus/v5 v5.1.0 h1:4KLkAxT3aOY8Li4FRJe/KvhoNFFxo0m6fNuFUO8QJUk= +github.com/godbus/dbus/v5 v5.1.0/go.mod h1:xhWf0FNVPg57R7Z0UbKHbJfkEywrmjJnf7w5xrFpKfA= github.com/gogo/googleapis v1.1.0/go.mod h1:gf4bu3Q80BeJ6H1S1vYPm8/ELATdvryBaNFGgqEef3s= github.com/gogo/protobuf v1.1.1/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ= github.com/gogo/protobuf v1.2.0/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ= @@ -239,6 +279,8 @@ github.com/gogo/protobuf v1.3.1/go.mod h1:SlYgWuQ5SjCEi6WLHjHCa1yvBfUnHcTbrrZtXP github.com/gogo/protobuf v1.3.2 h1:Ov1cvc58UF3b5XjBnZv7+opcTcQFZebYjWzi34vdm4Q= github.com/gogo/protobuf v1.3.2/go.mod h1:P1XiOD3dCwIKUDQYPy72D8LYyHL2YPYrpS2s69NZV8Q= github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q= +github.com/golang/glog v1.0.0 h1:nfP3RFugxnNRyKgeWd4oI1nYvXpxrx8ck8ZrcizshdQ= +github.com/golang/glog v1.0.0/go.mod h1:EWib/APOK0SL3dFbYqvxE3UYd8E6s1ouQ7iEp/0LWV4= github.com/golang/groupcache v0.0.0-20160516000752-02826c3e7903/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= github.com/golang/groupcache v0.0.0-20190702054246-869f871628b6/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= github.com/golang/groupcache v0.0.0-20191027212112-611e8accdfc9/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= @@ -274,8 +316,9 @@ github.com/golang/protobuf v1.4.3/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw github.com/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaSAoJOfIk= github.com/golang/protobuf v1.5.2 h1:ROPKBNFfQgOUMifHyP+KYbvpjbdoFNs+aK7DXlji0Tw= github.com/golang/protobuf v1.5.2/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY= -github.com/golang/snappy v0.0.0-20180518054509-2e65f85255db h1:woRePGFeVFfLKN/pOkfl+p/TAqKOfFu+7KPlMVpok/w= github.com/golang/snappy v0.0.0-20180518054509-2e65f85255db/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q= +github.com/golang/snappy v0.0.4 h1:yAGX7huGHXlcLOEtBnF4w7FQwA26wojNCwOYAEhLjQM= +github.com/golang/snappy v0.0.4/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q= github.com/google/btree v0.0.0-20180813153112-4030bb1f1f0c/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ= github.com/google/btree v1.0.0/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ= github.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5aqRK0M= @@ -285,11 +328,13 @@ github.com/google/go-cmp v0.4.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/ github.com/google/go-cmp v0.4.1/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/go-cmp v0.5.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/go-cmp v0.5.1/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= +github.com/google/go-cmp v0.5.2/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/go-cmp v0.5.3/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/go-cmp v0.5.4/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= -github.com/google/go-cmp v0.5.6 h1:BKbKCqvP6I+rmFHt06ZmyQtvB8xAkWdhFyr0ZUNZcxQ= github.com/google/go-cmp v0.5.6/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= +github.com/google/go-cmp v0.5.7 h1:81/ik6ipDQS2aGcBfIN5dHDB36BwrStyeAQquSYCV4o= +github.com/google/go-cmp v0.5.7/go.mod h1:n+brtR0CgQNWTVd5ZUFpTBC8YFBDLK/h/bpaJ8/DtOE= github.com/google/go-github v17.0.0+incompatible/go.mod h1:zLgOLi98H3fifZn+44m+umXrS52loVEgC2AApnigrVQ= github.com/google/go-querystring v1.0.0/go.mod h1:odCYkC5MyYFN7vkCjXpyrEuKhc/BUO6wN/zVPAxq5ck= github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= @@ -322,17 +367,24 @@ github.com/gopherjs/gopherjs v0.0.0-20190430165422-3e4dfb77656c/go.mod h1:wJfORR github.com/gorilla/context v1.1.1/go.mod h1:kBGZzfjB9CEq2AlWe17Uuf7NDRt0dE0s8S51q0aT7Yg= github.com/gorilla/mux v1.6.2/go.mod h1:1lud6UwP+6orDFRuTfBEV8e9/aOM/c4fVVCaMa2zaAs= github.com/gorilla/mux v1.7.3/go.mod h1:1lud6UwP+6orDFRuTfBEV8e9/aOM/c4fVVCaMa2zaAs= +github.com/gorilla/mux v1.8.0/go.mod h1:DVbg23sWSpFRCP0SfiEN6jmj59UnW/n46BH5rLB71So= +github.com/gorilla/securecookie v1.1.1/go.mod h1:ra0sb63/xPlUeL+yeDciTfxMRAA+MP+HVt/4epWDjd4= +github.com/gorilla/sessions v1.2.1/go.mod h1:dk2InVEVJ0sfLlnXv9EAgkf6ecYs/i80K/zI+bUmuGM= github.com/gorilla/websocket v0.0.0-20170926233335-4201258b820c/go.mod h1:E7qHFY5m1UJ88s3WnNqhKjPHQ0heANvMoAMk2YaljkQ= github.com/gorilla/websocket v1.4.0/go.mod h1:E7qHFY5m1UJ88s3WnNqhKjPHQ0heANvMoAMk2YaljkQ= github.com/gorilla/websocket v1.4.1/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE= -github.com/gorilla/websocket v1.4.2 h1:+/TMaTYc4QFitKJxsQ7Yye35DkWvkdLcvGKqM+x0Ufc= github.com/gorilla/websocket v1.4.2/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE= +github.com/gorilla/websocket v1.5.0 h1:PPwGk2jz7EePpoHN/+ClbZu8SPxiqlu12wZP/3sWmnc= +github.com/gorilla/websocket v1.5.0/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE= github.com/gregjones/httpcache v0.0.0-20180305231024-9cad4c3443a7/go.mod h1:FecbI9+v66THATjSRHfNgh1IVFe/9kFxbXtjV0ctIMA= github.com/grpc-ecosystem/go-grpc-middleware v1.0.1-0.20190118093823-f849b5445de4/go.mod h1:FiyG127CGDf3tlThmgyCl78X/SZQqEOJBCDaAfeWzPs= github.com/grpc-ecosystem/go-grpc-prometheus v1.2.0/go.mod h1:8NvIoxWQoOIhqOTXgfV/d3M/q6VIi02HzZEHgUlZvzk= github.com/grpc-ecosystem/grpc-gateway v1.5.0/go.mod h1:RSKVYQBd5MCa4OVpNdGskqpgL2+G+NZTnrVHpWWfpdw= github.com/grpc-ecosystem/grpc-gateway v1.9.5/go.mod h1:vNeuVxBJEsws4ogUvrchl83t/GYV9WGTSLVdBhOQFDY= +github.com/grpc-ecosystem/grpc-gateway v1.16.0 h1:gmcG1KaJ57LophUzW0Hy8NmPhnMZb4M0+kPpLofRdBo= github.com/grpc-ecosystem/grpc-gateway v1.16.0/go.mod h1:BDjrQk3hbvj6Nolgz8mAMFbcEtjT1g+wF4CSlocrBnw= +github.com/grpc-ecosystem/grpc-gateway/v2 v2.7.0 h1:BZHcxBETFHIdVyhyEfOvn/RdU/QGdLI4y34qQGjGWO0= +github.com/grpc-ecosystem/grpc-gateway/v2 v2.7.0/go.mod h1:hgWBS7lorOAVIJEQMi4ZsPv9hVvWI6+ch50m39Pf2Ks= github.com/gxed/hashland/keccakpg v0.0.1/go.mod h1:kRzw3HkwxFU1mpmPP8v1WyQzwdGfmKFJ6tItnhQ67kU= github.com/gxed/hashland/murmur3 v0.0.1/go.mod h1:KjXop02n4/ckmZSnY2+HKcLud/tcmvhST0bie/0lS48= github.com/hannahhoward/cbor-gen-for v0.0.0-20200817222906-ea96cece81f1/go.mod h1:jvfsLIxk0fY/2BKSQ1xf2406AKA5dwMmKKv0ADcOfN8= @@ -354,6 +406,7 @@ github.com/hashicorp/go-sockaddr v1.0.0/go.mod h1:7Xibr9yA9JjQq1JpNB2Vw7kxv8xerX github.com/hashicorp/go-syslog v1.0.0/go.mod h1:qPfqrKkXGihmCqbJM2mZgkZGvKG1dFdvsLplgctolz4= github.com/hashicorp/go-uuid v1.0.0/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro= github.com/hashicorp/go-uuid v1.0.1/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro= +github.com/hashicorp/go-uuid v1.0.2/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro= github.com/hashicorp/go-version v1.2.0/go.mod h1:fltr4n8CU8Ke44wwGCBoEymUuxUHl09ZGVZPK5anwXA= github.com/hashicorp/go.net v0.0.1/go.mod h1:hjKkEWcCURg++eb33jQU7oqQcI9XDCnUzHA0oac0k90= github.com/hashicorp/golang-lru v0.5.0/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8= @@ -368,8 +421,9 @@ github.com/hashicorp/serf v0.8.2/go.mod h1:6hOLApaqBFA1NXqRQAsxw9QxuDEvNxSQRwA/J github.com/hpcloud/tail v1.0.0/go.mod h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpOxQnU= github.com/hudl/fargo v1.3.0/go.mod h1:y3CKSmjA+wD2gak7sUSXTAoopbhU08POFhmITJgmKTg= github.com/huin/goupnp v1.0.0/go.mod h1:n9v9KO1tAxYH82qOn+UTIFQDmx5n1Zxd/ClZDMX7Bnc= -github.com/huin/goupnp v1.0.2 h1:RfGLP+h3mvisuWEyybxNq5Eft3NWhHLPeUN72kpKZoI= github.com/huin/goupnp v1.0.2/go.mod h1:0dxJBVBHqTMjIUMkESDTNgOOx/Mw5wYIfyFmdzSamkM= +github.com/huin/goupnp v1.0.3 h1:N8No57ls+MnjlB+JPiCVSOyy/ot7MJTqlo7rn+NYSqQ= +github.com/huin/goupnp v1.0.3/go.mod h1:ZxNlw5WqJj6wSsRK5+YfflQGXYfccj5VgQsMNixHM7Y= github.com/huin/goutil v0.0.0-20170803182201-1ca381bf3150/go.mod h1:PpLOETDnJ0o3iZrZfqZzyLl6l7F3c6L1oWn7OICBi6o= github.com/ianlancetaylor/demangle v0.0.0-20181102032728-5e5cf60278f6/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc= github.com/inconshreveable/mousetrap v1.0.0/go.mod h1:PxqpIevigyE2G7u3NXJIT2ANytuPF1OarO4DADm73n8= @@ -384,8 +438,9 @@ github.com/ipfs/go-bitswap v0.1.0/go.mod h1:FFJEf18E9izuCqUtHxbWEvq+reg7o4CW5wSA github.com/ipfs/go-bitswap v0.1.2/go.mod h1:qxSWS4NXGs7jQ6zQvoPY3+NmOfHHG47mhkiLzBpJQIs= github.com/ipfs/go-bitswap v0.1.8/go.mod h1:TOWoxllhccevbWFUR2N7B1MTSVVge1s6XSMiCSA4MzM= github.com/ipfs/go-bitswap v0.3.4/go.mod h1:4T7fvNv/LmOys+21tnLzGKncMeeXUYUd1nUiJ2teMvI= -github.com/ipfs/go-bitswap v0.5.1 h1:721YAEDBnLIrvcIMkCHCdqp34hA8jwL9yKMkyJpSpco= github.com/ipfs/go-bitswap v0.5.1/go.mod h1:P+ckC87ri1xFLvk74NlXdP0Kj9RmWAh4+H78sC6Qopo= +github.com/ipfs/go-bitswap v0.6.0 h1:f2rc6GZtoSFhEIzQmddgGiel9xntj02Dg0ZNf2hSC+w= +github.com/ipfs/go-bitswap v0.6.0/go.mod h1:Hj3ZXdOC5wBJvENtdqsixmzzRukqd8EHLxZLZc3mzRA= github.com/ipfs/go-block-format v0.0.1/go.mod h1:DK/YYcsSUIVAFNwo/KZCdIIbpN0ROH/baNLgayt4pFc= github.com/ipfs/go-block-format v0.0.2/go.mod h1:AWR46JfpcObNfg3ok2JHDUfdiHRgWhJgCQF+KIgOPJY= github.com/ipfs/go-block-format v0.0.3 h1:r8t66QstRp/pd/or4dpnbVfXT5Gt7lOqRvC+/dDTpMc= @@ -393,9 +448,9 @@ github.com/ipfs/go-block-format v0.0.3/go.mod h1:4LmD4ZUw0mhO+JSKdpWwrzATiEfM7WW github.com/ipfs/go-blockservice v0.0.7/go.mod h1:EOfb9k/Y878ZTRY/CH0x5+ATtaipfbRhbvNSdgc/7So= github.com/ipfs/go-blockservice v0.1.0/go.mod h1:hzmMScl1kXHg3M2BjTymbVPjv627N7sYcvYaKbop39M= github.com/ipfs/go-blockservice v0.1.4/go.mod h1:OTZhFpkgY48kNzbgyvcexW9cHrpjBYIjSR0KoDOFOLU= -github.com/ipfs/go-blockservice v0.1.7/go.mod h1:GmS+BAt4hrwBKkzE11AFDQUrnvqjwFatGS2MY7wOjEM= -github.com/ipfs/go-blockservice v0.2.1 h1:NJ4j/cwEfIg60rzAWcCIxRtOwbf6ZPK49MewNxObCPQ= github.com/ipfs/go-blockservice v0.2.1/go.mod h1:k6SiwmgyYgs4M/qt+ww6amPeUH9EISLRBnvUurKJhi8= +github.com/ipfs/go-blockservice v0.3.0 h1:cDgcZ+0P0Ih3sl8+qjFr2sVaMdysg/YZpLj5WJ8kiiw= +github.com/ipfs/go-blockservice v0.3.0/go.mod h1:P5ppi8IHDC7O+pA0AlGTF09jruB2h+oP3wVVaZl8sfk= github.com/ipfs/go-cid v0.0.1/go.mod h1:GHWU/WuQdMPmIosc4Yn1bcCT7dSeX4lBafM7iqUPQvM= github.com/ipfs/go-cid v0.0.2/go.mod h1:GHWU/WuQdMPmIosc4Yn1bcCT7dSeX4lBafM7iqUPQvM= github.com/ipfs/go-cid v0.0.3/go.mod h1:GHWU/WuQdMPmIosc4Yn1bcCT7dSeX4lBafM7iqUPQvM= @@ -442,44 +497,45 @@ github.com/ipfs/go-ds-measure v0.2.0/go.mod h1:SEUD/rE2PwRa4IQEC5FuNAmjJCyYObZr9 github.com/ipfs/go-fetcher v1.5.0/go.mod h1:5pDZ0393oRF/fHiLmtFZtpMNBQfHOYNPtryWedVuSWE= github.com/ipfs/go-fetcher v1.6.1 h1:UFuRVYX5AIllTiRhi5uK/iZkfhSpBCGX7L70nSZEmK8= github.com/ipfs/go-fetcher v1.6.1/go.mod h1:27d/xMV8bodjVs9pugh/RCjjK2OZ68UgAMspMdingNo= -github.com/ipfs/go-filestore v0.1.0 h1:qxvDVTzGrbQElddMmkwsJwJn+fDwWb3pHQHtKc1H0a8= -github.com/ipfs/go-filestore v0.1.0/go.mod h1:0KTrzoJnJ3sJDEDM09Vq8nz8H475rRyeq4i0n/bpF00= +github.com/ipfs/go-filestore v1.2.0 h1:O2wg7wdibwxkEDcl7xkuQsPvJFRBVgVSsOJ/GP6z3yU= +github.com/ipfs/go-filestore v1.2.0/go.mod h1:HLJrCxRXquTeEEpde4lTLMaE/MYJZD7WHLkp9z6+FF8= github.com/ipfs/go-fs-lock v0.0.7 h1:6BR3dajORFrFTkb5EpCUFIAypsoxpGpDSVUdFwzgL9U= github.com/ipfs/go-fs-lock v0.0.7/go.mod h1:Js8ka+FNYmgQRLrRXzU3CB/+Csr1BwrRilEcvYrHhhc= -github.com/ipfs/go-graphsync v0.11.0 h1:PiiD5CnoC3xEHMW8d6uBGqGcoTwiMB5d9CORIEyF6iA= -github.com/ipfs/go-graphsync v0.11.0/go.mod h1:wC+c8vGVjAHthsVIl8LKr37cUra2GOaMYcQNNmMxDqE= -github.com/ipfs/go-ipfs v0.11.0 h1:gAYt27NOnYJII9Kv9oiwEhURtQM+e4423WMzfllvefc= -github.com/ipfs/go-ipfs v0.11.0/go.mod h1:g68Thu2Ho11AWoHsN34P5fSK7iA6OWWRy3T/g8HLixc= +github.com/ipfs/go-graphsync v0.13.1 h1:lWiP/WLycoPUYyj3IDEi1GJNP30kFuYOvimcfeuZyQs= +github.com/ipfs/go-graphsync v0.13.1/go.mod h1:y8e8G6CmZeL9Srvx1l15CtGiRdf3h5JdQuqPz/iYL0A= +github.com/ipfs/go-ipfs v0.12.3-0.20220504184349-34aac1ee4316 h1:Q/CuIOQOFkWVhsqmYydZ/C5KN82wCV+JPeK5XR5pNzY= +github.com/ipfs/go-ipfs v0.12.3-0.20220504184349-34aac1ee4316/go.mod h1:ujgVaB9pWbXPYZ7oGGogJOB9sU+fPXqk+7iRaBURojQ= github.com/ipfs/go-ipfs-blockstore v0.0.1/go.mod h1:d3WClOmRQKFnJ0Jz/jj/zmksX0ma1gROTlovZKBmN08= github.com/ipfs/go-ipfs-blockstore v0.1.0/go.mod h1:5aD0AvHPi7mZc6Ci1WCAhiBQu2IsfTduLl+422H6Rqw= github.com/ipfs/go-ipfs-blockstore v0.1.4/go.mod h1:Jxm3XMVjh6R17WvxFEiyKBLUGr86HgIYJW/D/MwqeYQ= -github.com/ipfs/go-ipfs-blockstore v0.1.6/go.mod h1:Jxm3XMVjh6R17WvxFEiyKBLUGr86HgIYJW/D/MwqeYQ= -github.com/ipfs/go-ipfs-blockstore v0.2.1 h1:624eIDnkZWNdWbp/N8aDBOUtSY0YW75aJu+vbxnNlkA= github.com/ipfs/go-ipfs-blockstore v0.2.1/go.mod h1:jGesd8EtCM3/zPgx+qr0/feTXGUeRai6adgwC+Q+JvE= +github.com/ipfs/go-ipfs-blockstore v1.1.2/go.mod h1:w51tNR9y5+QXB0wkNcHt4O2aSZjTdqaEWaQdSxEyUOY= +github.com/ipfs/go-ipfs-blockstore v1.2.0 h1:n3WTeJ4LdICWs/0VSfjHrlqpPpl6MZ+ySd3j8qz0ykw= +github.com/ipfs/go-ipfs-blockstore v1.2.0/go.mod h1:eh8eTFLiINYNSNawfZOC7HOxNTxpB1PFuA5E1m/7exE= github.com/ipfs/go-ipfs-blocksutil v0.0.1 h1:Eh/H4pc1hsvhzsQoMEP3Bke/aW5P5rVM1IWFJMcGIPQ= github.com/ipfs/go-ipfs-blocksutil v0.0.1/go.mod h1:Yq4M86uIOmxmGPUHv/uI7uKqZNtLb449gwKqXjIsnRk= github.com/ipfs/go-ipfs-chunker v0.0.1/go.mod h1:tWewYK0we3+rMbOh7pPFGDyypCtvGcBFymgY4rSDLAw= github.com/ipfs/go-ipfs-chunker v0.0.5 h1:ojCf7HV/m+uS2vhUGWcogIIxiO5ubl5O57Q7NapWLY8= github.com/ipfs/go-ipfs-chunker v0.0.5/go.mod h1:jhgdF8vxRHycr00k13FM8Y0E+6BoalYeobXmUyTreP8= -github.com/ipfs/go-ipfs-cmds v0.6.0/go.mod h1:ZgYiWVnCk43ChwoH8hAmI1IRbuVtq3GSTHwtRB/Kqhk= -github.com/ipfs/go-ipfs-config v0.18.0 h1:Ta1aNGNEq6RIvzbw7dqzCVZJKb7j+Dd35JFnAOCpT8g= -github.com/ipfs/go-ipfs-config v0.18.0/go.mod h1:wz2lKzOjgJeYJa6zx8W9VT7mz+iSd0laBMqS/9wmX6A= +github.com/ipfs/go-ipfs-cmds v0.8.1/go.mod h1:y0bflH6m4g6ary4HniYt98UqbrVnRxmRarzeMdLIUn0= github.com/ipfs/go-ipfs-delay v0.0.0-20181109222059-70721b86a9a8/go.mod h1:8SP1YXK1M1kXuc4KJZINY3TQQ03J2rwBG9QfXmbRPrw= github.com/ipfs/go-ipfs-delay v0.0.1 h1:r/UXYyRcddO6thwOnhiznIAiSvxMECGgtv35Xs1IeRQ= github.com/ipfs/go-ipfs-delay v0.0.1/go.mod h1:8SP1YXK1M1kXuc4KJZINY3TQQ03J2rwBG9QfXmbRPrw= github.com/ipfs/go-ipfs-ds-help v0.0.1/go.mod h1:gtP9xRaZXqIQRh1HRpp595KbBEdgqWFxefeVKOV8sxo= -github.com/ipfs/go-ipfs-ds-help v0.1.1 h1:IW/bXGeaAZV2VH0Kuok+Ohva/zHkHmeLFBxC1k7mNPc= github.com/ipfs/go-ipfs-ds-help v0.1.1/go.mod h1:SbBafGJuGsPI/QL3j9Fc5YPLeAu+SzOkI0gFwAg+mOs= +github.com/ipfs/go-ipfs-ds-help v1.1.0 h1:yLE2w9RAsl31LtfMt91tRZcrx+e61O5mDxFRR994w4Q= +github.com/ipfs/go-ipfs-ds-help v1.1.0/go.mod h1:YR5+6EaebOhfcqVCyqemItCLthrpVNot+rsOU/5IatU= github.com/ipfs/go-ipfs-exchange-interface v0.0.1/go.mod h1:c8MwfHjtQjPoDyiy9cFquVtVHkO9b9Ob3FG91qJnWCM= github.com/ipfs/go-ipfs-exchange-interface v0.1.0 h1:TiMekCrOGQuWYtZO3mf4YJXDIdNgnKWZ9IE3fGlnWfo= github.com/ipfs/go-ipfs-exchange-interface v0.1.0/go.mod h1:ych7WPlyHqFvCi/uQI48zLZuAWVP5iTQPXEfVaw5WEI= github.com/ipfs/go-ipfs-exchange-offline v0.0.1/go.mod h1:WhHSFCVYX36H/anEKQboAzpUws3x7UeEGkzQc3iNkM0= -github.com/ipfs/go-ipfs-exchange-offline v0.1.1 h1:mEiXWdbMN6C7vtDG21Fphx8TGCbZPpQnz/496w/PL4g= github.com/ipfs/go-ipfs-exchange-offline v0.1.1/go.mod h1:vTiBRIbzSwDD0OWm+i3xeT0mO7jG2cbJYatp3HPk5XY= +github.com/ipfs/go-ipfs-exchange-offline v0.2.0 h1:2PF4o4A7W656rC0RxuhUace997FTcDTcIQ6NoEtyjAI= +github.com/ipfs/go-ipfs-exchange-offline v0.2.0/go.mod h1:HjwBeW0dvZvfOMwDP0TSKXIHf2s+ksdP4E3MLDRtLKY= github.com/ipfs/go-ipfs-files v0.0.3/go.mod h1:INEFm0LL2LWXBhNJ2PMIIb2w45hpXgPjNoE7yA8Y1d4= github.com/ipfs/go-ipfs-files v0.0.8/go.mod h1:wiN/jSG8FKyk7N0WyctKSvq3ljIa2NNTiZB55kpTdOs= -github.com/ipfs/go-ipfs-files v0.0.9 h1:OFyOfmuVDu9c5YtjSDORmwXzE6fmZikzZpzsnNkgFEg= -github.com/ipfs/go-ipfs-files v0.0.9/go.mod h1:aFv2uQ/qxWpL/6lidWvnSQmaVqCrf0TBGoUr+C1Fo84= +github.com/ipfs/go-ipfs-files v0.1.1 h1:/MbEowmpLo9PJTEQk16m9rKzUHjeP4KRU9nWJyJO324= +github.com/ipfs/go-ipfs-files v0.1.1/go.mod h1:8xkIrMWH+Y5P7HvJ4Yc5XWwIW2e52dyXUiC0tZyjDbM= github.com/ipfs/go-ipfs-keystore v0.0.2 h1:Fa9xg9IFD1VbiZtrNLzsD0GuELVHUFXCWF64kCPfEXU= github.com/ipfs/go-ipfs-keystore v0.0.2/go.mod h1:H49tRmibOEs7gLMgbOsjC4dqh1u5e0R/SWuc2ScfgSo= github.com/ipfs/go-ipfs-pinner v0.2.1 h1:kw9hiqh2p8TatILYZ3WAfQQABby7SQARdrdA+5Z5QfY= @@ -505,12 +561,15 @@ github.com/ipfs/go-ipld-cbor v0.0.5 h1:ovz4CHKogtG2KB/h1zUp5U0c/IzZrL435rCh5+K/5 github.com/ipfs/go-ipld-cbor v0.0.5/go.mod h1:BkCduEx3XBCO6t2Sfo5BaHzuok7hbhdMm9Oh8B2Ftq4= github.com/ipfs/go-ipld-format v0.0.1/go.mod h1:kyJtbkDALmFHv3QR6et67i35QzO3S0dCDnkOJhcZkms= github.com/ipfs/go-ipld-format v0.0.2/go.mod h1:4B6+FM2u9OJ9zCV+kSbgFAZlOrv1Hqbf0INGQgiKf9k= -github.com/ipfs/go-ipld-format v0.2.0 h1:xGlJKkArkmBvowr+GMCX0FEZtkro71K1AwiKnL37mwA= github.com/ipfs/go-ipld-format v0.2.0/go.mod h1:3l3C1uKoadTPbeNfrDi+xMInYKlx2Cvg1BuydPSdzQs= +github.com/ipfs/go-ipld-format v0.3.0/go.mod h1:co/SdBE8h99968X0hViiw1MNlh6fvxxnHpvVLnH7jSM= +github.com/ipfs/go-ipld-format v0.4.0 h1:yqJSaJftjmjc9jEOFYlpkwOLVKv68OD27jFLlSghBlQ= +github.com/ipfs/go-ipld-format v0.4.0/go.mod h1:co/SdBE8h99968X0hViiw1MNlh6fvxxnHpvVLnH7jSM= github.com/ipfs/go-ipld-git v0.1.1 h1:TWGnZjS0htmEmlMFEkA3ogrNCqWjIxwr16x1OsdhG+Y= github.com/ipfs/go-ipld-git v0.1.1/go.mod h1:+VyMqF5lMcJh4rwEppV0e6g4nCCHXThLYYDpKUkJubI= -github.com/ipfs/go-ipld-legacy v0.1.0 h1:wxkkc4k8cnvIGIjPO0waJCe7SHEyFgl+yQdafdjGrpA= github.com/ipfs/go-ipld-legacy v0.1.0/go.mod h1:86f5P/srAmh9GcIcWQR9lfFLZPrIyyXQeVlOWeeWEuI= +github.com/ipfs/go-ipld-legacy v0.1.1 h1:BvD8PEuqwBHLTKqlGFTHSwrwFOMkVESEvwIYwR2cdcc= +github.com/ipfs/go-ipld-legacy v0.1.1/go.mod h1:8AyKFCjgRPsQFf15ZQgDB8Din4DML/fOmKZkkFkrIEg= github.com/ipfs/go-ipns v0.1.2 h1:O/s/0ht+4Jl9+VoxoUo0zaHjnZUS+aBQIKTuzdZ/ucI= github.com/ipfs/go-ipns v0.1.2/go.mod h1:ioQ0j02o6jdIVW+bmi18f4k2gRf0AV3kZ9KeHYHICnQ= github.com/ipfs/go-log v0.0.1/go.mod h1:kL1d2/hzSpI0thNYjiKfjanbVNU+IIGA/WnNESY9leM= @@ -524,56 +583,67 @@ github.com/ipfs/go-log/v2 v2.0.3/go.mod h1:O7P1lJt27vWHhOwQmcFEvlmo49ry2VY2+JfBW github.com/ipfs/go-log/v2 v2.0.5/go.mod h1:eZs4Xt4ZUJQFM3DlanGhy7TkwwawCZcSByscwkWG+dw= github.com/ipfs/go-log/v2 v2.1.1/go.mod h1:2v2nsGfZsvvAJz13SyFzf9ObaqwHiHxsPLEHntrv9KM= github.com/ipfs/go-log/v2 v2.1.3/go.mod h1:/8d0SH3Su5Ooc31QlL1WysJhvyOTDCjcCZ9Axpmri6g= -github.com/ipfs/go-log/v2 v2.3.0 h1:31Re/cPqFHpsRHgyVwjWADPoF0otB1WrjTy8ZFYwEZU= github.com/ipfs/go-log/v2 v2.3.0/go.mod h1:QqGoj30OTpnKaG/LKTGTxoP2mmQtjVMEnK72gynbe/g= +github.com/ipfs/go-log/v2 v2.5.0/go.mod h1:prSpmC1Gpllc9UYWxDiZDreBYw7zp4Iqp1kOLU9U5UI= +github.com/ipfs/go-log/v2 v2.5.1 h1:1XdUzF7048prq4aBjDQQ4SL5RxftpRGdXhNRwKSAlcY= +github.com/ipfs/go-log/v2 v2.5.1/go.mod h1:prSpmC1Gpllc9UYWxDiZDreBYw7zp4Iqp1kOLU9U5UI= github.com/ipfs/go-merkledag v0.0.6/go.mod h1:QYPdnlvkOg7GnQRofu9XZimC5ZW5Wi3bKys/4GQQfto= github.com/ipfs/go-merkledag v0.2.3/go.mod h1:SQiXrtSts3KGNmgOzMICy5c0POOpUNQLvB3ClKnBAlk= github.com/ipfs/go-merkledag v0.3.2/go.mod h1:fvkZNNZixVW6cKSZ/JfLlON5OlgTXNdRLz0p6QG/I2M= -github.com/ipfs/go-merkledag v0.4.0/go.mod h1:XshXBkhyeS63YNGisLL1uDSfuTyrQIxVUOg3ojR5MOE= -github.com/ipfs/go-merkledag v0.5.1 h1:tr17GPP5XtPhvPPiWtu20tSGZiZDuTaJRXBLcr79Umk= github.com/ipfs/go-merkledag v0.5.1/go.mod h1:cLMZXx8J08idkp5+id62iVftUQV+HlYJ3PIhDfZsjA4= +github.com/ipfs/go-merkledag v0.6.0 h1:oV5WT2321tS4YQVOPgIrWHvJ0lJobRTerU+i9nmUCuA= +github.com/ipfs/go-merkledag v0.6.0/go.mod h1:9HSEwRd5sV+lbykiYP+2NC/3o6MZbKNaa4hfNcH5iH0= github.com/ipfs/go-metrics-interface v0.0.1 h1:j+cpbjYvu4R8zbleSs36gvB7jR+wsL2fGD6n0jO4kdg= github.com/ipfs/go-metrics-interface v0.0.1/go.mod h1:6s6euYU4zowdslK0GKHmqaIZ3j/b/tL7HTWtJ4VPgWY= github.com/ipfs/go-metrics-prometheus v0.0.2/go.mod h1:ELLU99AQQNi+zX6GCGm2lAgnzdSH3u5UVlCdqSXnEks= github.com/ipfs/go-mfs v0.2.1 h1:5jz8+ukAg/z6jTkollzxGzhkl3yxm022Za9f2nL5ab8= github.com/ipfs/go-mfs v0.2.1/go.mod h1:Woj80iuw4ajDnIP6+seRaoHpPsc9hmL0pk/nDNDWP88= -github.com/ipfs/go-namesys v0.4.0 h1:Gxg4kEWxVcHuUJl60KMNs1k8AiVB3luXbz8ZJkSGacs= -github.com/ipfs/go-namesys v0.4.0/go.mod h1:jpJwzodyP8DZdWN6DShRjVZw6gaqMr4nQLBSxU5cR6E= +github.com/ipfs/go-namesys v0.5.0 h1:vZEkdqxRiSnxBBJrvYTkwHYBFgibGUSpNtg9BHRyN+o= +github.com/ipfs/go-namesys v0.5.0/go.mod h1:zZOme8KDAUYDl4f5MnWSiTRhoxcM7kLkZIyps/HV/S0= github.com/ipfs/go-path v0.0.7/go.mod h1:6KTKmeRnBXgqrTvzFrPV3CamxcgvXX/4z79tfAd2Sno= github.com/ipfs/go-path v0.0.9/go.mod h1:VpDkSBKQ9EFQOUgi54Tq/O/tGi8n1RfYNks13M3DEs8= github.com/ipfs/go-path v0.1.1/go.mod h1:vC8q4AKOtrjJz2NnllIrmr2ZbGlF5fW2OKKyhV9ggb0= -github.com/ipfs/go-path v0.2.1 h1:R0JYCu0JBnfa6A3C42nzsNPxtKU5/fnUPhWSuzcJHws= github.com/ipfs/go-path v0.2.1/go.mod h1:NOScsVgxfC/eIw4nz6OiGwK42PjaSJ4Y/ZFPn1Xe07I= +github.com/ipfs/go-path v0.3.0 h1:tkjga3MtpXyM5v+3EbRvOHEoo+frwi4oumw5K+KYWyA= +github.com/ipfs/go-path v0.3.0/go.mod h1:NOScsVgxfC/eIw4nz6OiGwK42PjaSJ4Y/ZFPn1Xe07I= github.com/ipfs/go-peertaskqueue v0.0.4/go.mod h1:03H8fhyeMfKNFWqzYEVyMbcPUeYrqP1MX6Kd+aN+rMQ= github.com/ipfs/go-peertaskqueue v0.1.0/go.mod h1:Jmk3IyCcfl1W3jTW3YpghSwSEC6IJ3Vzz/jUmWw8Z0U= github.com/ipfs/go-peertaskqueue v0.1.1/go.mod h1:Jmk3IyCcfl1W3jTW3YpghSwSEC6IJ3Vzz/jUmWw8Z0U= github.com/ipfs/go-peertaskqueue v0.2.0/go.mod h1:5/eNrBEbtSKWCG+kQK8K8fGNixoYUnr+P7jivavs9lY= -github.com/ipfs/go-peertaskqueue v0.7.0 h1:VyO6G4sbzX80K58N60cCaHsSsypbUNs1GjO5seGNsQ0= github.com/ipfs/go-peertaskqueue v0.7.0/go.mod h1:M/akTIE/z1jGNXMU7kFB4TeSEFvj68ow0Rrb04donIU= -github.com/ipfs/go-pinning-service-http-client v0.1.0/go.mod h1:tcCKmlkWWH9JUUkKs8CrOZBanacNc1dmKLfjlyXAMu4= +github.com/ipfs/go-peertaskqueue v0.7.1 h1:7PLjon3RZwRQMgOTvYccZ+mjzkmds/7YzSWKFlBAypE= +github.com/ipfs/go-peertaskqueue v0.7.1/go.mod h1:M/akTIE/z1jGNXMU7kFB4TeSEFvj68ow0Rrb04donIU= +github.com/ipfs/go-pinning-service-http-client v0.1.1/go.mod h1:i6tC2nWOnJbZZUQPgxOlrg4CX8bhQZMh4II09FxvD58= github.com/ipfs/go-unixfs v0.2.4/go.mod h1:SUdisfUjNoSDzzhGVxvCL9QO/nKdwXdr+gbMUdqcbYw= github.com/ipfs/go-unixfs v0.3.1 h1:LrfED0OGfG98ZEegO4/xiprx2O+yS+krCMQSp7zLVv8= github.com/ipfs/go-unixfs v0.3.1/go.mod h1:h4qfQYzghiIc8ZNFKiLMFWOTzrWIAtzYQ59W/pCFf1o= github.com/ipfs/go-unixfsnode v1.1.2/go.mod h1:5dcE2x03pyjHk4JjamXmunTMzz+VUtqvPwZjIEkfV6s= -github.com/ipfs/go-unixfsnode v1.1.3 h1:IyqJBGIEvcHvll1wDDVIHOEVXnE+IH6tjzTWpZ6kGiI= -github.com/ipfs/go-unixfsnode v1.1.3/go.mod h1:ZZxUM5wXBC+G0Co9FjrYTOm+UlhZTjxLfRYdWY9veZ4= +github.com/ipfs/go-unixfsnode v1.4.0 h1:9BUxHBXrbNi8mWHc6j+5C580WJqtVw9uoeEKn4tMhwA= +github.com/ipfs/go-unixfsnode v1.4.0/go.mod h1:qc7YFFZ8tABc58p62HnIYbUMwj9chhUuFWmxSokfePo= github.com/ipfs/go-verifcid v0.0.1 h1:m2HI7zIuR5TFyQ1b79Da5N9dnnCP1vcu2QqawmWlK2E= github.com/ipfs/go-verifcid v0.0.1/go.mod h1:5Hrva5KBeIog4A+UpqlaIU+DEstipcJYQQZc0g37pY0= github.com/ipfs/interface-go-ipfs-core v0.4.0/go.mod h1:UJBcU6iNennuI05amq3FQ7g0JHUkibHFAfhfUIy927o= -github.com/ipfs/interface-go-ipfs-core v0.5.2 h1:m1/5U+WpOK2ZE7Qzs5iIu80QM1ZA3aWYi2Ilwpi+tdg= -github.com/ipfs/interface-go-ipfs-core v0.5.2/go.mod h1:lNBJrdXHtWS46evMPBdWtDQMDsrKcGbxCOGoKLkztOE= +github.com/ipfs/interface-go-ipfs-core v0.7.0 h1:7tb+2upz8oCcjIyjo1atdMk+P+u7wPmI+GksBlLE8js= +github.com/ipfs/interface-go-ipfs-core v0.7.0/go.mod h1:lF27E/nnSPbylPqKVXGZghal2hzifs3MmjyiEjnc9FY= github.com/ipfs/tar-utils v0.0.2/go.mod h1:4qlnRWgTVljIMhSG2SqRYn66NT+3wrv/kZt9V+eqxDM= +github.com/ipld/go-car v0.3.2 h1:V9wt/80FNfbMRWSD98W5br6fyjUAyVgI2lDOTZX16Lg= github.com/ipld/go-car v0.3.2/go.mod h1:WEjynkVt04dr0GwJhry0KlaTeSDEiEYyMPOxDBQ17KE= +github.com/ipld/go-car/v2 v2.1.1 h1:saaKz4nC0AdfCGHLYKeXLGn8ivoPC54fyS55uyOLKwA= +github.com/ipld/go-car/v2 v2.1.1/go.mod h1:+2Yvf0Z3wzkv7NeI69i8tuZ+ft7jyjPYIWZzeVNeFcI= github.com/ipld/go-codec-dagpb v1.2.0/go.mod h1:6nBN7X7h8EOsEejZGqC7tej5drsdBAXbMHyBT+Fne5s= -github.com/ipld/go-codec-dagpb v1.3.0 h1:czTcaoAuNNyIYWs6Qe01DJ+sEX7B+1Z0LcXjSatMGe8= github.com/ipld/go-codec-dagpb v1.3.0/go.mod h1:ga4JTU3abYApDC3pZ00BC2RSvC3qfBb9MSJkMLSwnhA= +github.com/ipld/go-codec-dagpb v1.3.1/go.mod h1:ErNNglIi5KMur/MfFE/svtgQthzVvf+43MrzLbpcIZY= +github.com/ipld/go-codec-dagpb v1.4.0 h1:VqADPIFng8G4vz5EQytmmcx/2gEgOHfBuw/kIuCgDAY= +github.com/ipld/go-codec-dagpb v1.4.0/go.mod h1:ErNNglIi5KMur/MfFE/svtgQthzVvf+43MrzLbpcIZY= github.com/ipld/go-ipld-prime v0.9.0/go.mod h1:KvBLMr4PX1gWptgkzRjVZCrLmSGcZCb/jioOQwCqZN8= github.com/ipld/go-ipld-prime v0.9.1-0.20210324083106-dc342a9917db/go.mod h1:KvBLMr4PX1gWptgkzRjVZCrLmSGcZCb/jioOQwCqZN8= github.com/ipld/go-ipld-prime v0.11.0/go.mod h1:+WIAkokurHmZ/KwzDOMUuoeJgaRQktHtEaLglS3ZeV8= github.com/ipld/go-ipld-prime v0.12.3/go.mod h1:PaeLYq8k6dJLmDUSLrzkEpoGV4PEfe/1OtFN/eALOc8= +github.com/ipld/go-ipld-prime v0.14.0/go.mod h1:9ASQLwUFLptCov6lIYc70GRB4V7UTyLD0IJtrDJe6ZM= github.com/ipld/go-ipld-prime v0.14.1/go.mod h1:QcE4Y9n/ZZr8Ijg5bGPT0GqYWgZ1704nH0RDcQtgTP0= -github.com/ipld/go-ipld-prime v0.14.2 h1:P5fO2usnisXwrN/1sR5exCgEvINg/w/27EuYPKB/zx8= -github.com/ipld/go-ipld-prime v0.14.2/go.mod h1:QcE4Y9n/ZZr8Ijg5bGPT0GqYWgZ1704nH0RDcQtgTP0= +github.com/ipld/go-ipld-prime v0.16.0 h1:RS5hhjB/mcpeEPJvfyj0qbOj/QL+/j05heZ0qa97dVo= +github.com/ipld/go-ipld-prime v0.16.0/go.mod h1:axSCuOCBPqrH+gvXr2w9uAOulJqBPhHPT2PjoiiU1qA= +github.com/ipld/go-ipld-prime/storage/bsadapter v0.0.0-20211210234204-ce2a1c70cd73/go.mod h1:2PJ0JgxyB08t0b2WKrcuqI3di0V+5n6RS/LTUJhkoxY= github.com/jackpal/gateway v1.0.5/go.mod h1:lTpwd4ACLXmpyiCTRtfiNyVnUmqT9RivzCDQetPfnjA= github.com/jackpal/go-nat-pmp v1.0.1/go.mod h1:QPH045xvCAeXUZOxsnwmrtiCoxIr9eob+4orBN1SBKc= github.com/jackpal/go-nat-pmp v1.0.2 h1:KzKSgb7qkJvOUTqYl9/Hg/me3pWgBmERKrTGD7BdWus= @@ -590,6 +660,12 @@ github.com/jbenet/goprocess v0.0.0-20160826012719-b497e2f366b8/go.mod h1:Ly/wlsj github.com/jbenet/goprocess v0.1.3/go.mod h1:5yspPrukOVuOLORacaBi858NqyClJPQxYZlqdZVfqY4= github.com/jbenet/goprocess v0.1.4 h1:DRGOFReOMqqDNXwW70QkacFW0YN9QnwLV0Vqk+3oU0o= github.com/jbenet/goprocess v0.1.4/go.mod h1:5yspPrukOVuOLORacaBi858NqyClJPQxYZlqdZVfqY4= +github.com/jcmturner/aescts/v2 v2.0.0/go.mod h1:AiaICIRyfYg35RUkr8yESTqvSy7csK90qZ5xfvvsoNs= +github.com/jcmturner/dnsutils/v2 v2.0.0/go.mod h1:b0TnjGOvI/n42bZa+hmXL+kFJZsFT7G4t3HTlQ184QM= +github.com/jcmturner/gofork v1.0.0/go.mod h1:MK8+TM0La+2rjBD4jE12Kj1pCCxK7d2LK/UM3ncEo0o= +github.com/jcmturner/goidentity/v6 v6.0.1/go.mod h1:X1YW3bgtvwAXju7V3LCIMpY0Gbxyjn/mY9zx4tFonSg= +github.com/jcmturner/gokrb5/v8 v8.4.2/go.mod h1:sb+Xq/fTY5yktf/VxLsE3wlfPqQjp0aWNYyvBVK62bc= +github.com/jcmturner/rpc/v2 v2.0.3/go.mod h1:VUJYCIDm3PVOEHw8sgt091/20OJjskO/YJki3ELg/Hc= github.com/jellevandenhooff/dkim v0.0.0-20150330215556-f50fe3d243e1/go.mod h1:E0B/fFc00Y+Rasa88328GlI/XbtyysCtTHZS8h7IrBU= github.com/jessevdk/go-flags v0.0.0-20141203071132-1679536dcc89/go.mod h1:4FA24M0QyGHXBuZZK/XkWh8h0e1EYbRYJSGM75WSRxI= github.com/jessevdk/go-flags v1.4.0/go.mod h1:4FA24M0QyGHXBuZZK/XkWh8h0e1EYbRYJSGM75WSRxI= @@ -602,6 +678,7 @@ github.com/json-iterator/go v1.1.7/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/u github.com/json-iterator/go v1.1.8/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4= github.com/json-iterator/go v1.1.10/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4= github.com/json-iterator/go v1.1.11/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4= +github.com/json-iterator/go v1.1.12/go.mod h1:e30LSqwooZae/UwlEbR2852Gd8hjQvJoHmT4TnhNGBo= github.com/jstemmer/go-junit-report v0.0.0-20190106144839-af01ea7f8024/go.mod h1:6v2b51hI/fHJwM22ozAgKL4VKDeJcHhJFhtBdhmNjmU= github.com/jstemmer/go-junit-report v0.9.1/go.mod h1:Brl9GWCQeLvo8nXZwPNNblvFj/XSXhF0NWZEnDohbsk= github.com/jtolds/gls v4.2.1+incompatible/go.mod h1:QJZ7F/aHp+rZTRtaJ1ow/lLfFfVYBRgL+9YlvaHOwJU= @@ -615,12 +692,15 @@ github.com/kisielk/errcheck v1.2.0/go.mod h1:/BMXB+zMLi60iA8Vv6Ksmxu/1UDYcXs4uQL github.com/kisielk/errcheck v1.5.0/go.mod h1:pFxgyoBC7bSaBwPgfKdkLd5X25qrDl4LWUI2bnpBCr8= github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck= github.com/kkdai/bstream v0.0.0-20161212061736-f391b8402d23/go.mod h1:J+Gs4SYgM6CZQHDETBtE9HaSEkGmuNXF86RwHhHUvq4= -github.com/klauspost/compress v1.11.7 h1:0hzRabrMN4tSTvMfnL3SCv1ZGeAP23ynzodBgaHeMeg= github.com/klauspost/compress v1.11.7/go.mod h1:aoV0uJVorq1K+umq18yTdKaF57EivdYsUV+/s2qKfXs= +github.com/klauspost/compress v1.13.6/go.mod h1:/3/Vjq9QcHkK5uEr5lBEmyoZ1iFhe47etQ6QUkpK6sk= +github.com/klauspost/compress v1.15.1 h1:y9FcTHGyrebwfP0ZZqFiaxTaiDnUrGkJkI+f583BL1A= +github.com/klauspost/compress v1.15.1/go.mod h1:/3/Vjq9QcHkK5uEr5lBEmyoZ1iFhe47etQ6QUkpK6sk= github.com/klauspost/cpuid/v2 v2.0.4/go.mod h1:FInQzS24/EEf25PyTYn52gqo7WaD8xa0213Md/qVLRg= github.com/klauspost/cpuid/v2 v2.0.6/go.mod h1:FInQzS24/EEf25PyTYn52gqo7WaD8xa0213Md/qVLRg= -github.com/klauspost/cpuid/v2 v2.0.9 h1:lgaqFMSdTdQYdZ04uHyN2d/eKdOMyi2YLSvlQIBFYa4= github.com/klauspost/cpuid/v2 v2.0.9/go.mod h1:FInQzS24/EEf25PyTYn52gqo7WaD8xa0213Md/qVLRg= +github.com/klauspost/cpuid/v2 v2.0.12 h1:p9dKCg8i4gmOxtv35DvrYoWqYzQrvEVdjQ762Y0OqZE= +github.com/klauspost/cpuid/v2 v2.0.12/go.mod h1:g2LTdtYhdyuGPqyWyv7qRAmj1WBqxuObKfj5c0PQa7c= github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= github.com/konsorten/go-windows-terminal-sequences v1.0.3/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= github.com/koron/go-ssdp v0.0.0-20180514024734-4a0ed625a78b/go.mod h1:5Ky9EC2xfoUKUor0Hjgi2BJhCSXJfMOFlmyYrVKGQMk= @@ -640,7 +720,6 @@ github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY= github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE= github.com/libp2p/go-addr-util v0.0.1/go.mod h1:4ac6O7n9rIAKB1dnd+s8IbbMXkt+oBpzX4/+RACcnlQ= github.com/libp2p/go-addr-util v0.0.2/go.mod h1:Ecd6Fb3yIuLzq4bD7VcywcVSBtefcAwnUISBM3WG15E= -github.com/libp2p/go-addr-util v0.1.0 h1:acKsntI33w2bTU7tC9a0SaPimJGfSI0bFKC18ChxeVI= github.com/libp2p/go-addr-util v0.1.0/go.mod h1:6I3ZYuFr2O/9D+SoyM0zEw0EF3YkldtTX406BpdQMqw= github.com/libp2p/go-buffer-pool v0.0.1/go.mod h1:xtyIz9PMobb13WaxR6Zo1Pd1zXJKYg0a8KiIvDp3TzQ= github.com/libp2p/go-buffer-pool v0.0.2 h1:QNK2iAFa8gjAe1SPz6mHSMuCcjs+X1wlHzeOSqcmlfs= @@ -654,8 +733,8 @@ github.com/libp2p/go-conn-security-multistream v0.2.0/go.mod h1:hZN4MjlNetKD3Rq5 github.com/libp2p/go-conn-security-multistream v0.2.1/go.mod h1:cR1d8gA0Hr59Fj6NhaTpFhJZrjSYuNmhpT2r25zYR70= github.com/libp2p/go-conn-security-multistream v0.3.0 h1:9UCIKlBL1hC9u7nkMXpD1nkc/T53PKMAn3/k9ivBAVc= github.com/libp2p/go-conn-security-multistream v0.3.0/go.mod h1:EEP47t4fw/bTelVmEzIDqSe69hO/ip52xBEhZMLWAHM= -github.com/libp2p/go-doh-resolver v0.3.1 h1:1wbVGkB4Tdj4WEvjAuYknOPyt4vSSDn9thnj13pKPaY= -github.com/libp2p/go-doh-resolver v0.3.1/go.mod h1:y5go1ZppAq9N2eppbX0xON01CyPBeUg2yS6BTssssog= +github.com/libp2p/go-doh-resolver v0.4.0 h1:gUBa1f1XsPwtpE1du0O+nnZCUqtG7oYi7Bb+0S7FQqw= +github.com/libp2p/go-doh-resolver v0.4.0/go.mod h1:v1/jwsFusgsWIGX/c6vCRrnJ60x7bhTiq/fs2qt0cAg= github.com/libp2p/go-eventbus v0.1.0/go.mod h1:vROgu5cs5T7cv7POWlWxBaVLxfSegC5UGQf8A2eEmx4= github.com/libp2p/go-eventbus v0.2.1 h1:VanAdErQnpTioN2TowqNcOijf6YwhuODe4pPKSDpxGc= github.com/libp2p/go-eventbus v0.2.1/go.mod h1:jc2S4SoEVPP48H9Wpzm5aiGwUCBMfGhVhhBjyhhCJs8= @@ -672,14 +751,15 @@ github.com/libp2p/go-libp2p v0.7.4/go.mod h1:oXsBlTLF1q7pxr+9w6lqzS1ILpyHsaBPniV github.com/libp2p/go-libp2p v0.8.1/go.mod h1:QRNH9pwdbEBpx5DTJYg+qxcVaDMAz3Ee/qDKwXujH5o= github.com/libp2p/go-libp2p v0.12.0/go.mod h1:FpHZrfC1q7nA8jitvdjKBDF31hguaC676g/nT9PgQM0= github.com/libp2p/go-libp2p v0.13.0/go.mod h1:pM0beYdACRfHO1WcJlp65WXyG2A6NqYM+t2DTVAJxMo= -github.com/libp2p/go-libp2p v0.14.0/go.mod h1:dsQrWLAoIn+GkHPN/U+yypizkHiB9tnv79Os+kSgQ4Q= github.com/libp2p/go-libp2p v0.14.3/go.mod h1:d12V4PdKbpL0T1/gsUNN8DfgMuRPDX8bS2QxCZlwRH0= github.com/libp2p/go-libp2p v0.14.4/go.mod h1:EIRU0Of4J5S8rkockZM7eJp2S0UrCyi55m2kJVru3rM= -github.com/libp2p/go-libp2p v0.16.0 h1:aTxzQPllnW+nyC9mY8xaS20BbcrSYMt1HCkjZRHvdGY= github.com/libp2p/go-libp2p v0.16.0/go.mod h1:ump42BsirwAWxKzsCiFnTtN1Yc+DuPu76fyMX364/O4= +github.com/libp2p/go-libp2p v0.19.1 h1:ysBA1vDxhvgy9WmXpDeuk082EakewbJAwfU+ApdTG6I= +github.com/libp2p/go-libp2p v0.19.1/go.mod h1:Ki9jJXLO2YqrTIFxofV7Twyd3INWPT97+r8hGt7XPjI= github.com/libp2p/go-libp2p-asn-util v0.0.0-20200825225859-85005c6cf052/go.mod h1:nRMRTab+kZuk0LnKZpxhOVH/ndsdr2Nr//Zltc/vwgo= -github.com/libp2p/go-libp2p-asn-util v0.1.0 h1:rABPCO77SjdbJ/eJ/ynIo8vWICy1VEnL5JAxJbQLo1E= github.com/libp2p/go-libp2p-asn-util v0.1.0/go.mod h1:wu+AnM9Ii2KgO5jMmS1rz9dvzTdj8BXqsPR9HR0XB7I= +github.com/libp2p/go-libp2p-asn-util v0.2.0 h1:rg3+Os8jbnO5DxkC7K/Utdi+DkY3q/d1/1q+8WeNAsw= +github.com/libp2p/go-libp2p-asn-util v0.2.0/go.mod h1:WoaWxbHKBymSN41hWSq/lGKJEca7TNm58+gGJi2WsLI= github.com/libp2p/go-libp2p-autonat v0.0.6/go.mod h1:uZneLdOkZHro35xIhpbtTzLlgYturpu4J5+0cZK3MqE= github.com/libp2p/go-libp2p-autonat v0.1.0/go.mod h1:1tLf2yXxiE/oKGtDwPYWTSYG3PtvYlJmg7NeVtPRqH8= github.com/libp2p/go-libp2p-autonat v0.1.1/go.mod h1:OXqkeGOY2xJVWKAGV2inNF5aKN/djNA3fdpCWloIudE= @@ -688,19 +768,20 @@ github.com/libp2p/go-libp2p-autonat v0.2.1/go.mod h1:MWtAhV5Ko1l6QBsHQNSuM6b1sRk github.com/libp2p/go-libp2p-autonat v0.2.2/go.mod h1:HsM62HkqZmHR2k1xgX34WuWDzk/nBwNHoeyyT4IWV6A= github.com/libp2p/go-libp2p-autonat v0.4.0/go.mod h1:YxaJlpr81FhdOv3W3BTconZPfhaYivRdf53g+S2wobk= github.com/libp2p/go-libp2p-autonat v0.4.2/go.mod h1:YxaJlpr81FhdOv3W3BTconZPfhaYivRdf53g+S2wobk= -github.com/libp2p/go-libp2p-autonat v0.6.0 h1:+vbQ1pMzMGjE/RJopiQKK2FRjdCKHPNPrkPm8u+luQU= github.com/libp2p/go-libp2p-autonat v0.6.0/go.mod h1:bFC6kY8jwzNNWoqc8iGE57vsfwyJ/lP4O4DOV1e0B2o= github.com/libp2p/go-libp2p-blankhost v0.0.1/go.mod h1:Ibpbw/7cPPYwFb7PACIWdvxxv0t0XCCI10t7czjAjTc= github.com/libp2p/go-libp2p-blankhost v0.1.1/go.mod h1:pf2fvdLJPsC1FsVrNP3DUUvMzUts2dsLLBEpo1vW1ro= github.com/libp2p/go-libp2p-blankhost v0.1.4/go.mod h1:oJF0saYsAXQCSfDq254GMNmLNz6ZTHTOvtF4ZydUvwU= -github.com/libp2p/go-libp2p-blankhost v0.2.0 h1:3EsGAi0CBGcZ33GwRuXEYJLLPoVWyXJ1bcJzAJjINkk= github.com/libp2p/go-libp2p-blankhost v0.2.0/go.mod h1:eduNKXGTioTuQAUcZ5epXi9vMl+t4d8ugUBRQ4SqaNQ= +github.com/libp2p/go-libp2p-blankhost v0.3.0 h1:kTnLArltMabZlzY63pgGDA4kkUcLkBFSM98zBssn/IY= +github.com/libp2p/go-libp2p-blankhost v0.3.0/go.mod h1:urPC+7U01nCGgJ3ZsV8jdwTp6Ji9ID0dMTvq+aJ+nZU= github.com/libp2p/go-libp2p-circuit v0.0.9/go.mod h1:uU+IBvEQzCu953/ps7bYzC/D/R0Ho2A9LfKVVCatlqU= github.com/libp2p/go-libp2p-circuit v0.1.0/go.mod h1:Ahq4cY3V9VJcHcn1SBXjr78AbFkZeIRmfunbA7pmFh8= github.com/libp2p/go-libp2p-circuit v0.1.4/go.mod h1:CY67BrEjKNDhdTk8UgBX1Y/H5c3xkAcs3gnksxY7osU= github.com/libp2p/go-libp2p-circuit v0.2.1/go.mod h1:BXPwYDN5A8z4OEY9sOfr2DUQMLQvKt/6oku45YUmjIo= -github.com/libp2p/go-libp2p-circuit v0.4.0 h1:eqQ3sEYkGTtybWgr6JLqJY6QLtPWRErvFjFDfAOO1wc= github.com/libp2p/go-libp2p-circuit v0.4.0/go.mod h1:t/ktoFIUzM6uLQ+o1G6NuBl2ANhBKN9Bc8jRIk31MoA= +github.com/libp2p/go-libp2p-circuit v0.6.0 h1:rw/HlhmUB3OktS/Ygz6+2XABOmHKzZpPUuMNUMosj8w= +github.com/libp2p/go-libp2p-circuit v0.6.0/go.mod h1:kB8hY+zCpMeScyvFrKrGicRdid6vNXbunKE4rXATZ0M= github.com/libp2p/go-libp2p-connmgr v0.2.4 h1:TMS0vc0TCBomtQJyWr7fYxcVYYhx+q/2gF++G5Jkl/w= github.com/libp2p/go-libp2p-connmgr v0.2.4/go.mod h1:YV0b/RIm8NGPnnNWM7hG9Q38OeQiQfKhHCCs1++ufn0= github.com/libp2p/go-libp2p-core v0.0.1/go.mod h1:g/VxnTZ/1ygHxH3dKok7Vno1VfpvGcGip57wjTU4fco= @@ -731,8 +812,11 @@ github.com/libp2p/go-libp2p-core v0.8.5/go.mod h1:FfewUH/YpvWbEB+ZY9AQRQ4TAD8sJB github.com/libp2p/go-libp2p-core v0.8.6/go.mod h1:dgHr0l0hIKfWpGpqAMbpo19pen9wJfdCGv51mTmdpmM= github.com/libp2p/go-libp2p-core v0.9.0/go.mod h1:ESsbz31oC3C1AvMJoGx26RTuCkNhmkSRCqZ0kQtJ2/8= github.com/libp2p/go-libp2p-core v0.10.0/go.mod h1:ECdxehoYosLYHgDDFa2N4yE8Y7aQRAMf0sX9mf2sbGg= -github.com/libp2p/go-libp2p-core v0.11.0 h1:75jAgdA+IChNa+/mZXogfmrGkgwxkVvxmIC7pV+F6sI= github.com/libp2p/go-libp2p-core v0.11.0/go.mod h1:ECdxehoYosLYHgDDFa2N4yE8Y7aQRAMf0sX9mf2sbGg= +github.com/libp2p/go-libp2p-core v0.12.0/go.mod h1:ECdxehoYosLYHgDDFa2N4yE8Y7aQRAMf0sX9mf2sbGg= +github.com/libp2p/go-libp2p-core v0.14.0/go.mod h1:tLasfcVdTXnixsLB0QYaT1syJOhsbrhG7q6pGrHtBg8= +github.com/libp2p/go-libp2p-core v0.15.1 h1:0RY+Mi/ARK9DgG1g9xVQLb8dDaaU8tCePMtGALEfBnM= +github.com/libp2p/go-libp2p-core v0.15.1/go.mod h1:agSaboYM4hzB1cWekgVReqV5M4g5M+2eNNejV+1EEhs= github.com/libp2p/go-libp2p-crypto v0.0.1/go.mod h1:yJkNyDmO341d5wwXxDUGO0LykUVT72ImHNUqh5D/dBE= github.com/libp2p/go-libp2p-crypto v0.0.2/go.mod h1:eETI5OUfBnvARGOHrJz2eWNyTUxEGZnBxMcbUjfIj4I= github.com/libp2p/go-libp2p-crypto v0.1.0/go.mod h1:sPUokVISZiy+nNuTTH/TY+leRSxnFj/2GLjtOTW90hI= @@ -767,8 +851,10 @@ github.com/libp2p/go-libp2p-mplex v0.2.2/go.mod h1:74S9eum0tVQdAfFiKxAyKzNdSuLqw github.com/libp2p/go-libp2p-mplex v0.2.3/go.mod h1:CK3p2+9qH9x+7ER/gWWDYJ3QW5ZxWDkm+dVvjfuG3ek= github.com/libp2p/go-libp2p-mplex v0.3.0/go.mod h1:l9QWxRbbb5/hQMECEb908GbS9Sm2UAR2KFZKUJEynEs= github.com/libp2p/go-libp2p-mplex v0.4.0/go.mod h1:yCyWJE2sc6TBTnFpjvLuEJgTSw/u+MamvzILKdX7asw= -github.com/libp2p/go-libp2p-mplex v0.4.1 h1:/pyhkP1nLwjG3OM+VuaNJkQT/Pqq73WzB3aDN3Fx1sc= github.com/libp2p/go-libp2p-mplex v0.4.1/go.mod h1:cmy+3GfqfM1PceHTLL7zQzAAYaryDu6iPSC+CIb094g= +github.com/libp2p/go-libp2p-mplex v0.5.0/go.mod h1:eLImPJLkj3iG5t5lq68w3Vm5NAQ5BcKwrrb2VmOYb3M= +github.com/libp2p/go-libp2p-mplex v0.7.0 h1:ONTTvHIUaFCwyPO4FRkpe4OFQJq1bDkWQLbhWiD1A44= +github.com/libp2p/go-libp2p-mplex v0.7.0/go.mod h1:SeeXUXh7ZkfxnmsepnFgMPEhfEyACujuTM9k1TkErpc= github.com/libp2p/go-libp2p-nat v0.0.4/go.mod h1:N9Js/zVtAXqaeT99cXgTV9e75KpnWCvVOiGzlcHmBbY= github.com/libp2p/go-libp2p-nat v0.0.5/go.mod h1:1qubaE5bTZMJE+E/uu2URroMbzdubFz1ChgiN79yKPE= github.com/libp2p/go-libp2p-nat v0.0.6/go.mod h1:iV59LVhB3IkFvS6S6sauVTSOrNEANnINbI/fkaLimiw= @@ -781,8 +867,9 @@ github.com/libp2p/go-libp2p-netutil v0.1.0 h1:zscYDNVEcGxyUpMd0JReUZTrpMfia8PmLK github.com/libp2p/go-libp2p-netutil v0.1.0/go.mod h1:3Qv/aDqtMLTUyQeundkKsA+YCThNdbQD54k3TqjpbFU= github.com/libp2p/go-libp2p-noise v0.1.1/go.mod h1:QDFLdKX7nluB7DEnlVPbz7xlLHdwHFA9HiohJRr3vwM= github.com/libp2p/go-libp2p-noise v0.2.0/go.mod h1:IEbYhBBzGyvdLBoxxULL/SGbJARhUeqlO8lVSREYu2Q= -github.com/libp2p/go-libp2p-noise v0.3.0 h1:NCVH7evhVt9njbTQshzT7N1S3Q6fjj9M11FCgfH5+cA= github.com/libp2p/go-libp2p-noise v0.3.0/go.mod h1:JNjHbociDJKHD64KTkzGnzqJ0FEV5gHJa6AB00kbCNQ= +github.com/libp2p/go-libp2p-noise v0.4.0 h1:khcMsGhHNdGqKE5LDLrnHwZvdGVMsrnD4GTkTWkwmLU= +github.com/libp2p/go-libp2p-noise v0.4.0/go.mod h1:BzzY5pyzCYSyJbQy9oD8z5oP2idsafjt4/X42h9DjZU= github.com/libp2p/go-libp2p-peer v0.0.1/go.mod h1:nXQvOBbwVqoP+T5Y5nCjeH4sP9IX/J0AMzcDUVruVoo= github.com/libp2p/go-libp2p-peer v0.1.1/go.mod h1:jkF12jGB4Gk/IOo+yomm+7oLWxF278F7UnrYUQ1Q8es= github.com/libp2p/go-libp2p-peer v0.2.0/go.mod h1:RCffaCvUyW2CJmG2gAWVqwePwW7JMgxjsHm7+J5kjWY= @@ -797,26 +884,33 @@ github.com/libp2p/go-libp2p-peerstore v0.2.2/go.mod h1:NQxhNjWxf1d4w6PihR8btWIRj github.com/libp2p/go-libp2p-peerstore v0.2.6/go.mod h1:ss/TWTgHZTMpsU/oKVVPQCGuDHItOpf2W8RxAi50P2s= github.com/libp2p/go-libp2p-peerstore v0.2.7/go.mod h1:ss/TWTgHZTMpsU/oKVVPQCGuDHItOpf2W8RxAi50P2s= github.com/libp2p/go-libp2p-peerstore v0.2.8/go.mod h1:gGiPlXdz7mIHd2vfAsHzBNAMqSDkt2UBFwgcITgw1lA= -github.com/libp2p/go-libp2p-peerstore v0.4.0 h1:DOhRJLnM9Dc9lIXi3rPDZBf789LXy1BrzwIs7Tj0cKA= github.com/libp2p/go-libp2p-peerstore v0.4.0/go.mod h1:rDJUFyzEWPpXpEwywkcTYYzDHlwza8riYMaUzaN6hX0= +github.com/libp2p/go-libp2p-peerstore v0.6.0 h1:HJminhQSGISBIRb93N6WK3t6Fa8OOTnHd/VBjL4mY5A= +github.com/libp2p/go-libp2p-peerstore v0.6.0/go.mod h1:DGEmKdXrcYpK9Jha3sS7MhqYdInxJy84bIPtSu65bKc= github.com/libp2p/go-libp2p-pnet v0.2.0 h1:J6htxttBipJujEjz1y0a5+eYoiPcFHhSYHH6na5f0/k= github.com/libp2p/go-libp2p-pnet v0.2.0/go.mod h1:Qqvq6JH/oMZGwqs3N1Fqhv8NVhrdYcO0BW4wssv21LA= github.com/libp2p/go-libp2p-protocol v0.0.1/go.mod h1:Af9n4PiruirSDjHycM1QuiMi/1VZNHYcK8cLgFJLZ4s= github.com/libp2p/go-libp2p-protocol v0.1.0/go.mod h1:KQPHpAabB57XQxGrXCNvbL6UEXfQqUgC/1adR2Xtflk= -github.com/libp2p/go-libp2p-pubsub v0.6.0 h1:98+RXuEWW17U6cAijK1yaTf6mw/B+n5yPA421z+dlo0= github.com/libp2p/go-libp2p-pubsub v0.6.0/go.mod h1:nJv87QM2cU0w45KPR1rZicq+FmFIOD16zmT+ep1nOmg= +github.com/libp2p/go-libp2p-pubsub v0.6.1 h1:wycbV+f4rreCoVY61Do6g/BUk0RIrbNRcYVbn+QkjGk= +github.com/libp2p/go-libp2p-pubsub v0.6.1/go.mod h1:nJv87QM2cU0w45KPR1rZicq+FmFIOD16zmT+ep1nOmg= github.com/libp2p/go-libp2p-pubsub-router v0.5.0 h1:WuYdY42DVIJ+N0qMdq2du/E9poJH+xzsXL7Uptwj9tw= github.com/libp2p/go-libp2p-pubsub-router v0.5.0/go.mod h1:TRJKskSem3C0aSb3CmRgPwq6IleVFzds6hS09fmZbGM= github.com/libp2p/go-libp2p-quic-transport v0.10.0/go.mod h1:RfJbZ8IqXIhxBRm5hqUEJqjiiY8xmEuq3HUDS993MkA= github.com/libp2p/go-libp2p-quic-transport v0.11.2/go.mod h1:wlanzKtIh6pHrq+0U3p3DY9PJfGqxMgPaGKaK5LifwQ= github.com/libp2p/go-libp2p-quic-transport v0.13.0/go.mod h1:39/ZWJ1TW/jx1iFkKzzUg00W6tDJh73FC0xYudjr7Hc= -github.com/libp2p/go-libp2p-quic-transport v0.15.0 h1:DR0mP6kcieowikBprWkcNtbquRKOPWb5dLZ4ahDZujk= github.com/libp2p/go-libp2p-quic-transport v0.15.0/go.mod h1:wv4uGwjcqe8Mhjj7N/Ic0aKjA+/10UnMlSzLO0yRpYQ= +github.com/libp2p/go-libp2p-quic-transport v0.16.0/go.mod h1:1BXjVMzr+w7EkPfiHkKnwsWjPjtfaNT0q8RS3tGDvEQ= +github.com/libp2p/go-libp2p-quic-transport v0.17.0 h1:yFh4Gf5MlToAYLuw/dRvuzYd1EnE2pX3Lq1N6KDiWRQ= +github.com/libp2p/go-libp2p-quic-transport v0.17.0/go.mod h1:x4pw61P3/GRCcSLypcQJE/Q2+E9f4X+5aRcZLXf20LM= github.com/libp2p/go-libp2p-record v0.0.1/go.mod h1:grzqg263Rug/sRex85QrDOLntdFAymLDLm7lxMgU79Q= github.com/libp2p/go-libp2p-record v0.1.0/go.mod h1:ujNc8iuE5dlKWVy6wuL6dd58t0n7xI4hAIl8pE6wu5Q= github.com/libp2p/go-libp2p-record v0.1.2/go.mod h1:pal0eNcT5nqZaTV7UGhqeGqxFgGdsU/9W//C8dqjQDk= github.com/libp2p/go-libp2p-record v0.1.3 h1:R27hoScIhQf/A8XJZ8lYpnqh9LatJ5YbHs28kCIfql0= github.com/libp2p/go-libp2p-record v0.1.3/go.mod h1:yNUff/adKIfPnYQXgp6FQmNu3gLJ6EMg7+/vv2+9pY4= +github.com/libp2p/go-libp2p-resource-manager v0.2.1/go.mod h1:K+eCkiapf+ey/LADO4TaMpMTP9/Qde/uLlrnRqV4PLQ= +github.com/libp2p/go-libp2p-resource-manager v0.3.0 h1:2+cYxUNi33tcydsVLt6K5Fv2E3OTiVeafltecAj15E0= +github.com/libp2p/go-libp2p-resource-manager v0.3.0/go.mod h1:K+eCkiapf+ey/LADO4TaMpMTP9/Qde/uLlrnRqV4PLQ= github.com/libp2p/go-libp2p-routing v0.0.1/go.mod h1:N51q3yTr4Zdr7V8Jt2JIktVU+3xBBylx1MZeVA6t1Ys= github.com/libp2p/go-libp2p-routing-helpers v0.2.3 h1:xY61alxJ6PurSi+MXbywZpelvuU4U4p/gPTxjqCqTzY= github.com/libp2p/go-libp2p-routing-helpers v0.2.3/go.mod h1:795bh+9YeoFl99rMASoiVgHdi5bjack0N1+AFAdbvBw= @@ -835,8 +929,10 @@ github.com/libp2p/go-libp2p-swarm v0.3.1/go.mod h1:hdv95GWCTmzkgeJpP+GK/9D9puJeg github.com/libp2p/go-libp2p-swarm v0.4.0/go.mod h1:XVFcO52VoLoo0eitSxNQWYq4D6sydGOweTOAjJNraCw= github.com/libp2p/go-libp2p-swarm v0.5.0/go.mod h1:sU9i6BoHE0Ve5SKz3y9WfKrh8dUat6JknzUehFx8xW4= github.com/libp2p/go-libp2p-swarm v0.5.3/go.mod h1:NBn7eNW2lu568L7Ns9wdFrOhgRlkRnIDg0FLKbuu3i8= -github.com/libp2p/go-libp2p-swarm v0.8.0 h1:nRHNRhi86L7jhka02N4MoV+PSFFPoJFkHNQwCTFxNhw= github.com/libp2p/go-libp2p-swarm v0.8.0/go.mod h1:sOMp6dPuqco0r0GHTzfVheVBh6UEL0L1lXUZ5ot2Fvc= +github.com/libp2p/go-libp2p-swarm v0.10.0/go.mod h1:71ceMcV6Rg/0rIQ97rsZWMzto1l9LnNquef+efcRbmA= +github.com/libp2p/go-libp2p-swarm v0.10.2 h1:UaXf+CTq6Ns1N2V1EgqJ9Q3xaRsiN7ImVlDMpirMAWw= +github.com/libp2p/go-libp2p-swarm v0.10.2/go.mod h1:Pdkq0QU5a+qu+oyqIV3bknMsnzk9lnNyKvB9acJ5aZs= github.com/libp2p/go-libp2p-testing v0.0.1/go.mod h1:gvchhf3FQOtBdr+eFUABet5a4MBLK8jM3V4Zghvmi+E= github.com/libp2p/go-libp2p-testing v0.0.2/go.mod h1:gvchhf3FQOtBdr+eFUABet5a4MBLK8jM3V4Zghvmi+E= github.com/libp2p/go-libp2p-testing v0.0.3/go.mod h1:gvchhf3FQOtBdr+eFUABet5a4MBLK8jM3V4Zghvmi+E= @@ -847,12 +943,16 @@ github.com/libp2p/go-libp2p-testing v0.1.2-0.20200422005655-8775583591d8/go.mod github.com/libp2p/go-libp2p-testing v0.3.0/go.mod h1:efZkql4UZ7OVsEfaxNHZPzIehtsBXMrXnCfJIgDti5g= github.com/libp2p/go-libp2p-testing v0.4.0/go.mod h1:Q+PFXYoiYFN5CAEG2w3gLPEzotlKsNSbKQ/lImlOWF0= github.com/libp2p/go-libp2p-testing v0.4.2/go.mod h1:Q+PFXYoiYFN5CAEG2w3gLPEzotlKsNSbKQ/lImlOWF0= -github.com/libp2p/go-libp2p-testing v0.5.0 h1:bTjC29TTQ/ODq0ld3+0KLq3irdA5cAH3OMbRi0/QsvE= github.com/libp2p/go-libp2p-testing v0.5.0/go.mod h1:QBk8fqIL1XNcno/l3/hhaIEn4aLRijpYOR+zVjjlh+A= +github.com/libp2p/go-libp2p-testing v0.7.0/go.mod h1:OLbdn9DbgdMwv00v+tlp1l3oe2Cl+FAjoWIA2pa0X6E= +github.com/libp2p/go-libp2p-testing v0.9.0/go.mod h1:Td7kbdkWqYTJYQGTwzlgXwaqldraIanyjuRiAbK/XQU= +github.com/libp2p/go-libp2p-testing v0.9.2 h1:dCpODRtRaDZKF8HXT9qqqgON+OMEB423Knrgeod8j84= +github.com/libp2p/go-libp2p-testing v0.9.2/go.mod h1:Td7kbdkWqYTJYQGTwzlgXwaqldraIanyjuRiAbK/XQU= github.com/libp2p/go-libp2p-tls v0.1.3/go.mod h1:wZfuewxOndz5RTnCAxFliGjvYSDA40sKitV4c50uI1M= github.com/libp2p/go-libp2p-tls v0.3.0/go.mod h1:fwF5X6PWGxm6IDRwF3V8AVCCj/hOd5oFlg+wo2FxJDY= -github.com/libp2p/go-libp2p-tls v0.3.1 h1:lsE2zYte+rZCEOHF72J1Fg3XK3dGQyKvI6i5ehJfEp0= github.com/libp2p/go-libp2p-tls v0.3.1/go.mod h1:fwF5X6PWGxm6IDRwF3V8AVCCj/hOd5oFlg+wo2FxJDY= +github.com/libp2p/go-libp2p-tls v0.4.1 h1:1ByJUbyoMXvYXDoW6lLsMxqMViQNXmt+CfQqlnCpY+M= +github.com/libp2p/go-libp2p-tls v0.4.1/go.mod h1:EKCixHEysLNDlLUoKxv+3f/Lp90O2EXNjTr0UQDnrIw= github.com/libp2p/go-libp2p-transport v0.0.1/go.mod h1:UzbUs9X+PHOSw7S3ZmeOxfnwaQY5vGDzZmKPod3N3tk= github.com/libp2p/go-libp2p-transport v0.0.5/go.mod h1:StoY3sx6IqsP6XKoabsPnHCwqKXWUMWU7Rfcsubee/A= github.com/libp2p/go-libp2p-transport-upgrader v0.0.4/go.mod h1:RGq+tupk+oj7PzL2kn/m1w6YXxcIAYJYeI90h6BGgUc= @@ -863,8 +963,10 @@ github.com/libp2p/go-libp2p-transport-upgrader v0.4.0/go.mod h1:J4ko0ObtZSmgn5BX github.com/libp2p/go-libp2p-transport-upgrader v0.4.2/go.mod h1:NR8ne1VwfreD5VIWIU62Agt/J18ekORFU/j1i2y8zvk= github.com/libp2p/go-libp2p-transport-upgrader v0.4.3/go.mod h1:bpkldbOWXMrXhpZbSV1mQxTrefOg2Fi+k1ClDSA4ppw= github.com/libp2p/go-libp2p-transport-upgrader v0.4.6/go.mod h1:JE0WQuQdy+uLZ5zOaI3Nw9dWGYJIA7mywEtP2lMvnyk= -github.com/libp2p/go-libp2p-transport-upgrader v0.5.0 h1:7SDl3O2+AYOgfE40Mis83ClpfGNkNA6m4FwhbOHs+iI= github.com/libp2p/go-libp2p-transport-upgrader v0.5.0/go.mod h1:Rc+XODlB3yce7dvFV4q/RmyJGsFcCZRkeZMu/Zdg0mo= +github.com/libp2p/go-libp2p-transport-upgrader v0.7.0/go.mod h1:GIR2aTRp1J5yjVlkUoFqMkdobfob6RnAwYg/RZPhrzg= +github.com/libp2p/go-libp2p-transport-upgrader v0.7.1 h1:MSMe+tUfxpC9GArTz7a4G5zQKQgGh00Vio87d3j3xIg= +github.com/libp2p/go-libp2p-transport-upgrader v0.7.1/go.mod h1:GIR2aTRp1J5yjVlkUoFqMkdobfob6RnAwYg/RZPhrzg= github.com/libp2p/go-libp2p-xor v0.0.0-20210714161855-5c005aca55db h1:EDoDKW8ZAHd6SIDeo+thU51PyQppqLYkBxx0ObvFj/w= github.com/libp2p/go-libp2p-xor v0.0.0-20210714161855-5c005aca55db/go.mod h1:LSTM5yRnjGZbWNTA/hRwq2gGFrvRIbQJscoIL/u6InY= github.com/libp2p/go-libp2p-yamux v0.1.2/go.mod h1:xUoV/RmYkg6BW/qGxA9XJyg+HzXFYkeXbnhjmnYzKp8= @@ -878,14 +980,15 @@ github.com/libp2p/go-libp2p-yamux v0.2.8/go.mod h1:/t6tDqeuZf0INZMTgd0WxIRbtK2Ez github.com/libp2p/go-libp2p-yamux v0.4.0/go.mod h1:+DWDjtFMzoAwYLVkNZftoucn7PelNoy5nm3tZ3/Zw30= github.com/libp2p/go-libp2p-yamux v0.5.0/go.mod h1:AyR8k5EzyM2QN9Bbdg6X1SkVVuqLwTGf0L4DFq9g6po= github.com/libp2p/go-libp2p-yamux v0.5.1/go.mod h1:dowuvDu8CRWmr0iqySMiSxK+W0iL5cMVO9S94Y6gkv4= -github.com/libp2p/go-libp2p-yamux v0.5.3/go.mod h1:Vy3TMonBAfTMXHWopsMc8iX/XGRYrRlpUaMzaeuHV/s= github.com/libp2p/go-libp2p-yamux v0.5.4/go.mod h1:tfrXbyaTqqSU654GTvK3ocnSZL3BuHoeTSqhcel1wsE= -github.com/libp2p/go-libp2p-yamux v0.6.0 h1:TKayW983n92JhCGdCo7ej7eEb+DQ0VYfKNOxlN/1kNQ= github.com/libp2p/go-libp2p-yamux v0.6.0/go.mod h1:MRhd6mAYnFRnSISp4M8i0ClV/j+mWHo2mYLifWGw33k= +github.com/libp2p/go-libp2p-yamux v0.8.0/go.mod h1:yTkPgN2ib8FHyU1ZcVD7aelzyAqXXwEPbyx+aSKm9h8= +github.com/libp2p/go-libp2p-yamux v0.8.1/go.mod h1:rUozF8Jah2dL9LLGyBaBeTQeARdwhefMCTQVQt6QobE= +github.com/libp2p/go-libp2p-yamux v0.9.1 h1:oplewiRix8s45SOrI30rCPZG5mM087YZp+VYhXAh4+c= +github.com/libp2p/go-libp2p-yamux v0.9.1/go.mod h1:wRc6wvyxQINFcKe7daL4BeQ02Iyp+wxyC8WCNfngBrA= github.com/libp2p/go-maddr-filter v0.0.1/go.mod h1:6eT12kSQMA9x2pvFQa+xesMKUBlj9VImZbj3B9FBH/Q= github.com/libp2p/go-maddr-filter v0.0.4/go.mod h1:6eT12kSQMA9x2pvFQa+xesMKUBlj9VImZbj3B9FBH/Q= github.com/libp2p/go-maddr-filter v0.0.5/go.mod h1:Jk+36PMfIqCJhAnaASRH83bdAvfDRp/w6ENFaC9bG+M= -github.com/libp2p/go-maddr-filter v0.1.0 h1:4ACqZKw8AqiuJfwFGq1CYDFugfXTOos+qQ3DETkhtCE= github.com/libp2p/go-maddr-filter v0.1.0/go.mod h1:VzZhTXkMucEGGEOSKddrwGiOv0tUhgnKqNEmIAz/bPU= github.com/libp2p/go-mplex v0.0.3/go.mod h1:pK5yMLmOoBR1pNCqDlA2GQrdAVTMkqFalaTWe7l4Yd0= github.com/libp2p/go-mplex v0.0.4/go.mod h1:pK5yMLmOoBR1pNCqDlA2GQrdAVTMkqFalaTWe7l4Yd0= @@ -893,14 +996,17 @@ github.com/libp2p/go-mplex v0.1.0/go.mod h1:SXgmdki2kwCUlCCbfGLEgHjC4pFqhTp0ZoV6 github.com/libp2p/go-mplex v0.1.1/go.mod h1:Xgz2RDCi3co0LeZfgjm4OgUF15+sVR8SRcu3SFXI1lk= github.com/libp2p/go-mplex v0.1.2/go.mod h1:Xgz2RDCi3co0LeZfgjm4OgUF15+sVR8SRcu3SFXI1lk= github.com/libp2p/go-mplex v0.2.0/go.mod h1:0Oy/A9PQlwBytDRp4wSkFnzHYDKcpLot35JQ6msjvYQ= -github.com/libp2p/go-mplex v0.3.0 h1:U1T+vmCYJaEoDJPV1aq31N56hS+lJgb397GsylNSgrU= github.com/libp2p/go-mplex v0.3.0/go.mod h1:0Oy/A9PQlwBytDRp4wSkFnzHYDKcpLot35JQ6msjvYQ= +github.com/libp2p/go-mplex v0.4.0/go.mod h1:y26Lx+wNVtMYMaPu300Cbot5LkEZ4tJaNYeHeT9dh6E= +github.com/libp2p/go-mplex v0.7.0 h1:BDhFZdlk5tbr0oyFq/xv/NPGfjbnrsDam1EvutpBDbY= +github.com/libp2p/go-mplex v0.7.0/go.mod h1:rW8ThnRcYWft/Jb2jeORBmPd6xuG3dGxWN/W168L9EU= github.com/libp2p/go-msgio v0.0.2/go.mod h1:63lBBgOTDKQL6EWazRMCwXsEeEeK9O2Cd+0+6OOuipQ= github.com/libp2p/go-msgio v0.0.3/go.mod h1:63lBBgOTDKQL6EWazRMCwXsEeEeK9O2Cd+0+6OOuipQ= github.com/libp2p/go-msgio v0.0.4/go.mod h1:63lBBgOTDKQL6EWazRMCwXsEeEeK9O2Cd+0+6OOuipQ= github.com/libp2p/go-msgio v0.0.6/go.mod h1:4ecVB6d9f4BDSL5fqvPiC4A3KivjWn+Venn/1ALLMWA= -github.com/libp2p/go-msgio v0.1.0 h1:8Q7g/528ivAlfXTFWvWhVjTE8XG8sDTkRUKPYh9+5Q8= github.com/libp2p/go-msgio v0.1.0/go.mod h1:eNlv2vy9V2X/kNldcZ+SShFE++o2Yjxwx6RAYsmgJnE= +github.com/libp2p/go-msgio v0.2.0 h1:W6shmB+FeynDrUVl2dgFQvzfBZcXiyqY4VmpQLu9FqU= +github.com/libp2p/go-msgio v0.2.0/go.mod h1:dBVM1gW3Jk9XqHkU4eKdGvVHdLa51hoGfll6jMJMSlY= github.com/libp2p/go-nat v0.0.3/go.mod h1:88nUEt0k0JD45Bk93NIwDqjlhiOwOoV36GchpcVc1yI= github.com/libp2p/go-nat v0.0.4/go.mod h1:Nmw50VAvKuk38jUBcmNh6p9lUJLoODbJRvYAa/+KSDo= github.com/libp2p/go-nat v0.0.5/go.mod h1:B7NxsVNPZmRLvMOwiEO1scOSyjA56zxYAGv1yQgRkEU= @@ -909,8 +1015,9 @@ github.com/libp2p/go-nat v0.1.0/go.mod h1:X7teVkwRHNInVNWQiO/tAiAVRwSr5zoRz4YSTC github.com/libp2p/go-netroute v0.1.2/go.mod h1:jZLDV+1PE8y5XxBySEBgbuVAXbhtuHSdmLPL2n9MKbk= github.com/libp2p/go-netroute v0.1.3/go.mod h1:jZLDV+1PE8y5XxBySEBgbuVAXbhtuHSdmLPL2n9MKbk= github.com/libp2p/go-netroute v0.1.5/go.mod h1:V1SR3AaECRkEQCoFFzYwVYWvYIEtlxx89+O3qcpCl4A= -github.com/libp2p/go-netroute v0.1.6 h1:ruPJStbYyXVYGQ81uzEDzuvbYRLKRrLvTYd33yomC38= github.com/libp2p/go-netroute v0.1.6/go.mod h1:AqhkMh0VuWmfgtxKPp3Oc1LdU5QSWS7wl0QLhSZqXxQ= +github.com/libp2p/go-netroute v0.2.0 h1:0FpsbsvuSnAhXFnCY0VLFbJOzaK0VnP0r1QT/o4nWRE= +github.com/libp2p/go-netroute v0.2.0/go.mod h1:Vio7LTzZ+6hoT4CMZi5/6CpY3Snzh2vgZhWgxMNwlQI= github.com/libp2p/go-openssl v0.0.2/go.mod h1:v8Zw2ijCSWBQi8Pq5GAixw6DbFfa9u6VIYDXnvOXkc0= github.com/libp2p/go-openssl v0.0.3/go.mod h1:unDrJpgy3oFr+rqXsarWifmJuNnJR4chtO1HmaZjggc= github.com/libp2p/go-openssl v0.0.4/go.mod h1:unDrJpgy3oFr+rqXsarWifmJuNnJR4chtO1HmaZjggc= @@ -929,15 +1036,15 @@ github.com/libp2p/go-reuseport-transport v0.1.0 h1:C3PHeHjmnz8m6f0uydObj02tMEoi7 github.com/libp2p/go-reuseport-transport v0.1.0/go.mod h1:vev0C0uMkzriDY59yFHD9v+ujJvYmDQVLowvAjEOmfw= github.com/libp2p/go-sockaddr v0.0.2/go.mod h1:syPvOmNs24S3dFVGJA1/mrqdeijPxLV2Le3BRLKd68k= github.com/libp2p/go-sockaddr v0.1.0/go.mod h1:syPvOmNs24S3dFVGJA1/mrqdeijPxLV2Le3BRLKd68k= -github.com/libp2p/go-sockaddr v0.1.1 h1:yD80l2ZOdGksnOyHrhxDdTDFrf7Oy+v3FMVArIRgZxQ= github.com/libp2p/go-sockaddr v0.1.1/go.mod h1:syPvOmNs24S3dFVGJA1/mrqdeijPxLV2Le3BRLKd68k= github.com/libp2p/go-socket-activation v0.1.0/go.mod h1:gzda2dNkMG5Ti2OfWNNwW0FDIbj0g/aJJU320FcLfhk= github.com/libp2p/go-stream-muxer v0.0.1/go.mod h1:bAo8x7YkSpadMTbtTaxGVHWUQsR/l5MEaHbKaliuT14= github.com/libp2p/go-stream-muxer v0.1.0/go.mod h1:8JAVsjeRBCWwPoZeH0W1imLOcriqXJyFvB0mR4A04sQ= github.com/libp2p/go-stream-muxer-multistream v0.1.1/go.mod h1:zmGdfkQ1AzOECIAcccoL8L//laqawOsO03zX8Sa+eGw= github.com/libp2p/go-stream-muxer-multistream v0.2.0/go.mod h1:j9eyPol/LLRqT+GPLSxvimPhNph4sfYfMoDPd7HkzIc= -github.com/libp2p/go-stream-muxer-multistream v0.3.0 h1:TqnSHPJEIqDEO7h1wZZ0p3DXdvDSiLHQidKKUGZtiOY= github.com/libp2p/go-stream-muxer-multistream v0.3.0/go.mod h1:yDh8abSIzmZtqtOt64gFJUXEryejzNb0lisTt+fAMJA= +github.com/libp2p/go-stream-muxer-multistream v0.4.0 h1:HsM/9OdtqnIzjVXcxTXjmqKrj3gJ8kacaOJwJS1ipaY= +github.com/libp2p/go-stream-muxer-multistream v0.4.0/go.mod h1:nb+dGViZleRP4XcyHuZSVrJCBl55nRBOMmiSL/dyziw= github.com/libp2p/go-tcp-transport v0.0.4/go.mod h1:+E8HvC8ezEVOxIo3V5vCK9l1y/19K427vCzQ+xHKH/o= github.com/libp2p/go-tcp-transport v0.1.0/go.mod h1:oJ8I5VXryj493DEJ7OsBieu8fcg2nHGctwtInJVpipc= github.com/libp2p/go-tcp-transport v0.1.1/go.mod h1:3HzGvLbx6etZjnFlERyakbaYPdfjg2pWP97dFZworkY= @@ -946,8 +1053,10 @@ github.com/libp2p/go-tcp-transport v0.2.1/go.mod h1:zskiJ70MEfWz2MKxvFB/Pv+tPIB1 github.com/libp2p/go-tcp-transport v0.2.3/go.mod h1:9dvr03yqrPyYGIEN6Dy5UvdJZjyPFvl1S/igQ5QD1SU= github.com/libp2p/go-tcp-transport v0.2.4/go.mod h1:9dvr03yqrPyYGIEN6Dy5UvdJZjyPFvl1S/igQ5QD1SU= github.com/libp2p/go-tcp-transport v0.2.7/go.mod h1:lue9p1b3VmZj1MhhEGB/etmvF/nBQ0X9CW2DutBT3MM= -github.com/libp2p/go-tcp-transport v0.4.0 h1:VDyg4j6en3OuXf90gfDQh5Sy9KowO9udnd0OU8PP6zg= github.com/libp2p/go-tcp-transport v0.4.0/go.mod h1:0y52Rwrn4076xdJYu/51/qJIdxz+EWDAOG2S45sV3VI= +github.com/libp2p/go-tcp-transport v0.5.0/go.mod h1:UPPL0DIjQqiWRwVAb+CEQlaAG0rp/mCqJfIhFcLHc4Y= +github.com/libp2p/go-tcp-transport v0.5.1 h1:edOOs688VLZAozWC7Kj5/6HHXKNwi9M6wgRmmLa8M6Q= +github.com/libp2p/go-tcp-transport v0.5.1/go.mod h1:UPPL0DIjQqiWRwVAb+CEQlaAG0rp/mCqJfIhFcLHc4Y= github.com/libp2p/go-testutil v0.0.1/go.mod h1:iAcJc/DKJQanJ5ws2V+u5ywdL2n12X1WbbEG+Jjy69I= github.com/libp2p/go-testutil v0.1.0/go.mod h1:81b2n5HypcVyrCg/MJx4Wgfp/VHojytjVe/gLzZ2Ehc= github.com/libp2p/go-ws-transport v0.0.5/go.mod h1:Qbl4BxPfXXhhd/o0wcrgoaItHqA9tnZjoFZnxykuaXU= @@ -956,8 +1065,9 @@ github.com/libp2p/go-ws-transport v0.2.0/go.mod h1:9BHJz/4Q5A9ludYWKoGCFC5gUElzl github.com/libp2p/go-ws-transport v0.3.0/go.mod h1:bpgTJmRZAvVHrgHybCVyqoBmyLQ1fiZuEaBYusP5zsk= github.com/libp2p/go-ws-transport v0.3.1/go.mod h1:bpgTJmRZAvVHrgHybCVyqoBmyLQ1fiZuEaBYusP5zsk= github.com/libp2p/go-ws-transport v0.4.0/go.mod h1:EcIEKqf/7GDjth6ksuS/6p7R49V4CBY6/E7R/iyhYUA= -github.com/libp2p/go-ws-transport v0.5.0 h1:cO6x4P0v6PfxbKnxmf5cY2Ny4OPDGYkUqNvZzp/zdlo= github.com/libp2p/go-ws-transport v0.5.0/go.mod h1:I2juo1dNTbl8BKSBYo98XY85kU2xds1iamArLvl8kNg= +github.com/libp2p/go-ws-transport v0.6.0 h1:326XBL6Q+5CQ2KtjXz32+eGu02W/Kz2+Fm4SpXdr0q4= +github.com/libp2p/go-ws-transport v0.6.0/go.mod h1:dXqtI9e2JV9FtF1NOtWVZSKXh5zXvnuwPXfj8GPBbYU= github.com/libp2p/go-yamux v1.2.1/go.mod h1:FGTiPvoV/3DVdgWpX+tM0OW3tsM+W5bSE3gZwqQTcow= github.com/libp2p/go-yamux v1.2.2/go.mod h1:FGTiPvoV/3DVdgWpX+tM0OW3tsM+W5bSE3gZwqQTcow= github.com/libp2p/go-yamux v1.2.3/go.mod h1:FGTiPvoV/3DVdgWpX+tM0OW3tsM+W5bSE3gZwqQTcow= @@ -969,10 +1079,12 @@ github.com/libp2p/go-yamux v1.4.0/go.mod h1:fr7aVgmdNGJK+N1g+b6DW6VxzbRCjCOejR/h github.com/libp2p/go-yamux v1.4.1 h1:P1Fe9vF4th5JOxxgQvfbOHkrGqIZniTLf+ddhZp8YTI= github.com/libp2p/go-yamux v1.4.1/go.mod h1:fr7aVgmdNGJK+N1g+b6DW6VxzbRCjCOejR/hkmpooHE= github.com/libp2p/go-yamux/v2 v2.0.0/go.mod h1:NVWira5+sVUIU6tu1JWvaRn1dRnG+cawOJiflsAM+7U= -github.com/libp2p/go-yamux/v2 v2.1.1/go.mod h1:3So6P6TV6r75R9jiBpiIKgU/66lOarCZjqROGxzPpPQ= github.com/libp2p/go-yamux/v2 v2.2.0/go.mod h1:3So6P6TV6r75R9jiBpiIKgU/66lOarCZjqROGxzPpPQ= -github.com/libp2p/go-yamux/v2 v2.3.0 h1:luRV68GS1vqqr6EFUjtu1kr51d+IbW0gSowu8emYWAI= github.com/libp2p/go-yamux/v2 v2.3.0/go.mod h1:iTU+lOIn/2h0AgKcL49clNTwfEw+WSfDYrXe05EyKIs= +github.com/libp2p/go-yamux/v3 v3.0.1/go.mod h1:s2LsDhHbh+RfCsQoICSYt58U2f8ijtPANFD8BmE74Bo= +github.com/libp2p/go-yamux/v3 v3.0.2/go.mod h1:s2LsDhHbh+RfCsQoICSYt58U2f8ijtPANFD8BmE74Bo= +github.com/libp2p/go-yamux/v3 v3.1.1 h1:X0qSVodCZciOu/f4KTp9V+O0LAqcqP2tdaUGB0+0lng= +github.com/libp2p/go-yamux/v3 v3.1.1/go.mod h1:jeLEQgLXqE2YqX1ilAClIfCMDY+0uXQUKmmb/qp0gT4= github.com/libp2p/zeroconf/v2 v2.1.1 h1:XAuSczA96MYkVwH+LqqqCUZb2yH3krobMJ1YE+0hG2s= github.com/libp2p/zeroconf/v2 v2.1.1/go.mod h1:fuJqLnUwZTshS3U/bMRJ3+ow/v9oid1n0DmyYyNO1Xs= github.com/lightstep/lightstep-tracer-common/golang/gogo v0.0.0-20190605223551-bc2310a04743/go.mod h1:qklhhLq1aX+mtWk9cPHPzaBjWImj5ULL6C7HFJtXQMM= @@ -980,8 +1092,10 @@ github.com/lightstep/lightstep-tracer-go v0.18.1/go.mod h1:jlF1pusYV4pidLvZ+XD0U github.com/lucas-clemente/quic-go v0.19.3/go.mod h1:ADXpNbTQjq1hIzCpB+y/k5iz4n4z4IwqoLb94Kh5Hu8= github.com/lucas-clemente/quic-go v0.21.2/go.mod h1:vF5M1XqhBAHgbjKcJOXY3JZz3GP0T3FQhz/uyOUS38Q= github.com/lucas-clemente/quic-go v0.23.0/go.mod h1:paZuzjXCE5mj6sikVLMvqXk8lJV2AsqtJ6bDhjEfxx0= -github.com/lucas-clemente/quic-go v0.24.0 h1:ToR7SIIEdrgOhgVTHvPgdVRJfgVy+N0wQAagH7L4d5g= github.com/lucas-clemente/quic-go v0.24.0/go.mod h1:paZuzjXCE5mj6sikVLMvqXk8lJV2AsqtJ6bDhjEfxx0= +github.com/lucas-clemente/quic-go v0.25.0/go.mod h1:YtzP8bxRVCBlO77yRanE264+fY/T2U9ZlW1AaHOsMOg= +github.com/lucas-clemente/quic-go v0.27.0 h1:v6WY87q9zD4dKASbG8hy/LpzAVNzEQzw8sEIeloJsc4= +github.com/lucas-clemente/quic-go v0.27.0/go.mod h1:AzgQoPda7N+3IqMMMkywBKggIFo2KT6pfnlrQ2QieeI= github.com/lunixbochs/vtclean v1.0.0/go.mod h1:pHhQNgMf3btfWnGBVipUOjRYhoOsdGqdm/+2c2E2WMI= github.com/lyft/protoc-gen-validate v0.0.13/go.mod h1:XbGvPuh87YZc5TdIa2/I4pLk0QoUACkjt2znoq26NVQ= github.com/magiconair/properties v1.8.0/go.mod h1:PppfXfuXeibc/6YijjN8zIbojt8czPbwD3XqdrwzmxQ= @@ -992,11 +1106,16 @@ github.com/marten-seemann/qtls v0.10.0/go.mod h1:UvMd1oaYDACI99/oZUYLzMCkBXQVT0a github.com/marten-seemann/qtls-go1-15 v0.1.1/go.mod h1:GyFwywLKkRt+6mfU99csTEY1joMZz5vmB1WNZH3P81I= github.com/marten-seemann/qtls-go1-15 v0.1.4/go.mod h1:GyFwywLKkRt+6mfU99csTEY1joMZz5vmB1WNZH3P81I= github.com/marten-seemann/qtls-go1-15 v0.1.5/go.mod h1:GyFwywLKkRt+6mfU99csTEY1joMZz5vmB1WNZH3P81I= -github.com/marten-seemann/qtls-go1-16 v0.1.4 h1:xbHbOGGhrenVtII6Co8akhLEdrawwB2iHl5yhJRpnco= github.com/marten-seemann/qtls-go1-16 v0.1.4/go.mod h1:gNpI2Ol+lRS3WwSOtIUUtRwZEQMXjYK+dQSBFbethAk= +github.com/marten-seemann/qtls-go1-16 v0.1.5 h1:o9JrYPPco/Nukd/HpOHMHZoBDXQqoNtUCmny98/1uqQ= +github.com/marten-seemann/qtls-go1-16 v0.1.5/go.mod h1:gNpI2Ol+lRS3WwSOtIUUtRwZEQMXjYK+dQSBFbethAk= github.com/marten-seemann/qtls-go1-17 v0.1.0-rc.1/go.mod h1:fz4HIxByo+LlWcreM4CZOYNuz3taBQ8rN2X6FqvaWo8= -github.com/marten-seemann/qtls-go1-17 v0.1.0 h1:P9ggrs5xtwiqXv/FHNwntmuLMNq3KaSIG93AtAZ48xk= github.com/marten-seemann/qtls-go1-17 v0.1.0/go.mod h1:fz4HIxByo+LlWcreM4CZOYNuz3taBQ8rN2X6FqvaWo8= +github.com/marten-seemann/qtls-go1-17 v0.1.1 h1:DQjHPq+aOzUeh9/lixAGunn6rIOQyWChPSI4+hgW7jc= +github.com/marten-seemann/qtls-go1-17 v0.1.1/go.mod h1:C2ekUKcDdz9SDWxec1N/MvcXBpaX9l3Nx67XaR84L5s= +github.com/marten-seemann/qtls-go1-18 v0.1.0-beta.1/go.mod h1:PUhIQk19LoFt2174H4+an8TYvWOGjb/hHwphBeaDHwI= +github.com/marten-seemann/qtls-go1-18 v0.1.1 h1:qp7p7XXUFL7fpBvSS1sWD+uSqPvzNQK43DH+/qEkj0Y= +github.com/marten-seemann/qtls-go1-18 v0.1.1/go.mod h1:mJttiymBAByA49mhlNZZGrH5u1uXYZJ+RW28Py7f4m4= github.com/marten-seemann/tcp v0.0.0-20210406111302-dfbc87cc63fd h1:br0buuQ854V8u83wA0rVZ8ttrq5CpaPZdvrK0LP2lOk= github.com/marten-seemann/tcp v0.0.0-20210406111302-dfbc87cc63fd/go.mod h1:QuCEs1Nt24+FYQEqAAncTDPJIuGs+LxK1MCiFL25pMU= github.com/mattn/go-colorable v0.0.9/go.mod h1:9vuHe8Xs5qXnSaW/c/ABM9alt+Vo+STaOChaDxuIBZU= @@ -1008,8 +1127,9 @@ github.com/mattn/go-isatty v0.0.4/go.mod h1:M+lRXTBqGeGNdLjl/ufCoiOlB5xdOkqRJdNx github.com/mattn/go-isatty v0.0.5/go.mod h1:Iq45c/XA43vh69/j3iqttzPXn0bhXyGjM0Hdxcsrc5s= github.com/mattn/go-isatty v0.0.8/go.mod h1:Iq45c/XA43vh69/j3iqttzPXn0bhXyGjM0Hdxcsrc5s= github.com/mattn/go-isatty v0.0.11/go.mod h1:PhnuNfih5lzO57/f3n+odYbM4JtupLOxQOAqxQCu2WE= -github.com/mattn/go-isatty v0.0.13 h1:qdl+GuBjcsKKDco5BsxPJlId98mSWNKqYA+Co0SC1yA= github.com/mattn/go-isatty v0.0.13/go.mod h1:cbi8OIDigv2wuxKPP5vlRcQ1OAZbq2CE4Kysco4FUpU= +github.com/mattn/go-isatty v0.0.14 h1:yVuAays6BHfxijgZPzw+3Zlu5yQgKGP2/hcQbHb7S9Y= +github.com/mattn/go-isatty v0.0.14/go.mod h1:7GGIvUiUoEMVVmxf/4nioHXj79iQHKdU27kJ6hsGG94= github.com/mattn/go-runewidth v0.0.2/go.mod h1:LwmH8dsx7+W8Uxz3IHJYH5QSwggIsqBzpuz5H//U1FU= github.com/mattn/go-runewidth v0.0.4/go.mod h1:LwmH8dsx7+W8Uxz3IHJYH5QSwggIsqBzpuz5H//U1FU= github.com/matttproud/golang_protobuf_extensions v1.0.1 h1:4hp9jkHxhMHkqkrB3Ix0jegS5sx/RkqARlsWZ6pIwiU= @@ -1021,8 +1141,9 @@ github.com/miekg/dns v1.1.12/go.mod h1:W1PPwlIAgtquWBMBEV9nkV9Cazfe8ScdGz/Lj7v3N github.com/miekg/dns v1.1.28/go.mod h1:KNUDUusw/aVsxyTYZM1oqvCicbwhgbNgztCETuNZ7xM= github.com/miekg/dns v1.1.31/go.mod h1:KNUDUusw/aVsxyTYZM1oqvCicbwhgbNgztCETuNZ7xM= github.com/miekg/dns v1.1.41/go.mod h1:p6aan82bvRIyn+zDIv9xYNUpwa73JcSh9BKwknJysuI= -github.com/miekg/dns v1.1.43 h1:JKfpVSCB84vrAmHzyrsxB5NAr5kLoMXZArPSw7Qlgyg= github.com/miekg/dns v1.1.43/go.mod h1:+evo5L0630/F6ca/Z9+GAqzhjGyn8/c+TBaOyfEl0V4= +github.com/miekg/dns v1.1.48 h1:Ucfr7IIVyMBz4lRE8qmGUuZ4Wt3/ZGu9hmcMT3Uu4tQ= +github.com/miekg/dns v1.1.48/go.mod h1:e3IlAVfNqAllflbibAZEWOXOQ+Ynzk/dDozDxY7XnME= github.com/mikioh/tcp v0.0.0-20190314235350-803a9b46060c h1:bzE/A84HN25pxAuk9Eej1Kz9OUelF97nAc82bDquQI8= github.com/mikioh/tcp v0.0.0-20190314235350-803a9b46060c/go.mod h1:0SQS9kMwD2VsyFEB++InYyBJroV/FRmBgcydeSUcJms= github.com/mikioh/tcpinfo v0.0.0-20190314235526-30a79bb1804b h1:z78hV3sbSMAUoyUMM0I83AUIT6Hu17AWfgjzIbtrYFc= @@ -1051,14 +1172,16 @@ github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJ github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= github.com/modern-go/reflect2 v0.0.0-20180701023420-4b7aa43c6742/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0= github.com/modern-go/reflect2 v1.0.1/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0= +github.com/modern-go/reflect2 v1.0.2/go.mod h1:yWuevngMOJpCy52FWWMvUC8ws7m/LJsjYzDa0/r8luk= github.com/mr-tron/base58 v1.1.0/go.mod h1:xcD2VGqlgYjBdcBLw+TuYLr8afG+Hj8g2eTVqeSzSU8= github.com/mr-tron/base58 v1.1.1/go.mod h1:xcD2VGqlgYjBdcBLw+TuYLr8afG+Hj8g2eTVqeSzSU8= github.com/mr-tron/base58 v1.1.2/go.mod h1:BinMc/sQntlIE1frQmRFPUoPA1Zkr8VRgBdjWI2mNwc= github.com/mr-tron/base58 v1.1.3/go.mod h1:BinMc/sQntlIE1frQmRFPUoPA1Zkr8VRgBdjWI2mNwc= github.com/mr-tron/base58 v1.2.0 h1:T/HDJBh4ZCPbU39/+c3rRvE0uKBQlU27+QI8LJ4t64o= github.com/mr-tron/base58 v1.2.0/go.mod h1:BinMc/sQntlIE1frQmRFPUoPA1Zkr8VRgBdjWI2mNwc= -github.com/multiformats/go-base32 v0.0.3 h1:tw5+NhuwaOjJCC5Pp82QuXbrmLzWg7uxlMFp8Nq/kkI= github.com/multiformats/go-base32 v0.0.3/go.mod h1:pLiuGC8y0QR3Ue4Zug5UzK9LjgbkL8NSQj0zQ5Nz/AA= +github.com/multiformats/go-base32 v0.0.4 h1:+qMh4a2f37b4xTNs6mqitDinryCI+tfO2dRVMN9mjSE= +github.com/multiformats/go-base32 v0.0.4/go.mod h1:jNLFzjPZtp3aIARHbJRZIaPuspdH0J6q39uUM5pnABM= github.com/multiformats/go-base36 v0.1.0 h1:JR6TyF7JjGd3m6FbLU2cOxhC0Li8z8dLNGQ89tUg4F4= github.com/multiformats/go-base36 v0.1.0/go.mod h1:kFGE83c6s80PklsHO9sRn2NCoffoRdUUOENyW/Vv6sM= github.com/multiformats/go-multiaddr v0.0.1/go.mod h1:xKVEak1K9cS1VdmPZW3LSIb6lgmoS58qz/pzqmAxV44= @@ -1073,8 +1196,9 @@ github.com/multiformats/go-multiaddr v0.3.0/go.mod h1:dF9kph9wfJ+3VLAaeBqo9Of8x4 github.com/multiformats/go-multiaddr v0.3.1/go.mod h1:uPbspcUPd5AfaP6ql3ujFY+QWzmBD8uLLL4bXW0XfGc= github.com/multiformats/go-multiaddr v0.3.3/go.mod h1:lCKNGP1EQ1eZ35Za2wlqnabm9xQkib3fyB+nZXHLag0= github.com/multiformats/go-multiaddr v0.4.0/go.mod h1:YcpyLH8ZPudLxQlemYBPhSm0/oCXAT8Z4mzFpyoPyRc= -github.com/multiformats/go-multiaddr v0.4.1 h1:Pq37uLx3hsyNlTDir7FZyU8+cFCTqd5y1KiM2IzOutI= github.com/multiformats/go-multiaddr v0.4.1/go.mod h1:3afI9HfVW8csiF8UZqtpYRiDyew8pRX7qLIGHu9FLuM= +github.com/multiformats/go-multiaddr v0.5.0 h1:i/JuOoVg4szYQ4YEzDGtb2h0o8M7CG/Yq6cGlcjWZpM= +github.com/multiformats/go-multiaddr v0.5.0/go.mod h1:3KAxNkUqLTJ20AAwN4XVX4kZar+bR+gh4zgbfr3SNug= github.com/multiformats/go-multiaddr-dns v0.0.1/go.mod h1:9kWcqw/Pj6FwxAwW38n/9403szc57zJPs45fmnznu3Q= github.com/multiformats/go-multiaddr-dns v0.0.2/go.mod h1:9kWcqw/Pj6FwxAwW38n/9403szc57zJPs45fmnznu3Q= github.com/multiformats/go-multiaddr-dns v0.2.0/go.mod h1:TJ5pr5bBO7Y1B18djPuRsVkduhQH2YqYSbxWJzYGdK0= @@ -1096,8 +1220,11 @@ github.com/multiformats/go-multibase v0.0.1/go.mod h1:bja2MqRZ3ggyXtZSEDKpl0uO/g github.com/multiformats/go-multibase v0.0.3 h1:l/B6bJDQjvQ5G52jw4QGSYeOTZoAwIO77RblWplfIqk= github.com/multiformats/go-multibase v0.0.3/go.mod h1:5+1R4eQrT3PkYZ24C3W2Ue2tPwIdYQD509ZjSb5y9Oc= github.com/multiformats/go-multicodec v0.2.0/go.mod h1:/y4YVwkfMyry5kFbMTbLJKErhycTIftytRV+llXdyS4= -github.com/multiformats/go-multicodec v0.3.0 h1:tstDwfIjiHbnIjeM5Lp+pMrSeN+LCMsEwOrkPmWm03A= github.com/multiformats/go-multicodec v0.3.0/go.mod h1:qGGaQmioCDh+TeFOnxrbU0DaIPw8yFgAZgFG0V7p1qQ= +github.com/multiformats/go-multicodec v0.3.1-0.20210902112759-1539a079fd61/go.mod h1:1Hj/eHRaVWSXiSNNfcEPcwZleTmdNP81xlxDLnWU9GQ= +github.com/multiformats/go-multicodec v0.3.1-0.20211210143421-a526f306ed2c/go.mod h1:1Hj/eHRaVWSXiSNNfcEPcwZleTmdNP81xlxDLnWU9GQ= +github.com/multiformats/go-multicodec v0.4.1 h1:BSJbf+zpghcZMZrwTYBGwy0CPcVZGWiC72Cp8bBd4R4= +github.com/multiformats/go-multicodec v0.4.1/go.mod h1:1Hj/eHRaVWSXiSNNfcEPcwZleTmdNP81xlxDLnWU9GQ= github.com/multiformats/go-multihash v0.0.1/go.mod h1:w/5tugSrLEbWqlcgJabL3oHFKTwfvkofsjW2Qa1ct4U= github.com/multiformats/go-multihash v0.0.5/go.mod h1:lt/HCbqlQwlPBz7lv0sQCdtfcMtlJvakRUn/0Ual8po= github.com/multiformats/go-multihash v0.0.8/go.mod h1:YSLudS+Pi8NHE7o6tb3D8vrpKa63epEDmG8nTduyAew= @@ -1115,8 +1242,9 @@ github.com/multiformats/go-multistream v0.1.0/go.mod h1:fJTiDfXJVmItycydCnNx4+wS github.com/multiformats/go-multistream v0.1.1/go.mod h1:KmHZ40hzVxiaiwlj3MEbYgK9JFk2/9UktWZAF54Du38= github.com/multiformats/go-multistream v0.2.0/go.mod h1:5GZPQZbkWOLOn3J2y4Y99vVW7vOfsAflxARk3x14o6k= github.com/multiformats/go-multistream v0.2.1/go.mod h1:5GZPQZbkWOLOn3J2y4Y99vVW7vOfsAflxARk3x14o6k= -github.com/multiformats/go-multistream v0.2.2 h1:TCYu1BHTDr1F/Qm75qwYISQdzGcRdC21nFgQW7l7GBo= github.com/multiformats/go-multistream v0.2.2/go.mod h1:UIcnm7Zuo8HKG+HkWgfQsGL+/MIEhyTqbODbIUwSXKs= +github.com/multiformats/go-multistream v0.3.0 h1:yX1v4IWseLPmr0rmnDo148wWJbNx40JxBZGmQb5fUP4= +github.com/multiformats/go-multistream v0.3.0/go.mod h1:ODRoqamLUsETKS9BNcII4gcRsJBU5VAwRIv7O39cEXg= github.com/multiformats/go-varint v0.0.1/go.mod h1:3Ls8CIEsrijN6+B7PbrXRPxHRPuXSrVKRY101jdMZYE= github.com/multiformats/go-varint v0.0.2/go.mod h1:3Ls8CIEsrijN6+B7PbrXRPxHRPuXSrVKRY101jdMZYE= github.com/multiformats/go-varint v0.0.5/go.mod h1:3Ls8CIEsrijN6+B7PbrXRPxHRPuXSrVKRY101jdMZYE= @@ -1146,17 +1274,21 @@ github.com/onsi/ginkgo v1.12.0/go.mod h1:oUhWkIvk5aDxtKvDDuw8gItl8pKl42LzjC9KZE0 github.com/onsi/ginkgo v1.12.1/go.mod h1:zj2OWP4+oCPe1qIXoGWkgMRwljMUYCdkwsT2108oapk= github.com/onsi/ginkgo v1.14.0/go.mod h1:iSB4RoI2tjJc9BBv4NKIKWKya62Rps+oPG/Lv9klQyY= github.com/onsi/ginkgo v1.16.2/go.mod h1:CObGmKUOKaSC0RjmoAK7tKyn4Azo5P2IWuoMnvwxz1E= -github.com/onsi/ginkgo v1.16.4 h1:29JGrr5oVBm5ulCWet69zQkzWipVXIol6ygQUe/EzNc= github.com/onsi/ginkgo v1.16.4/go.mod h1:dX+/inL/fNMqNlz0e9LfyB9TswhZpCVdJM/Z6Vvnwo0= +github.com/onsi/ginkgo v1.16.5 h1:8xi0RTUf59SOSfEtZMvwTvXYMzG4gV23XVHOZiXNtnE= +github.com/onsi/ginkgo v1.16.5/go.mod h1:+E8gABHa3K6zRBolWtd+ROzc/U5bkGt0FwiG042wbpU= github.com/onsi/gomega v1.4.1/go.mod h1:C1qb7wdrVGGVU+Z6iS04AVkA3Q65CEZX59MT0QO5uiA= github.com/onsi/gomega v1.4.3/go.mod h1:ex+gbHU/CVuBBDIJjb2X0qEXbFg53c61hWP/1CpauHY= github.com/onsi/gomega v1.5.0/go.mod h1:ex+gbHU/CVuBBDIJjb2X0qEXbFg53c61hWP/1CpauHY= github.com/onsi/gomega v1.7.1/go.mod h1:XdKZgCCFLUoM/7CFJVPcG8C1xQ1AJ0vpAezJrB7JYyY= github.com/onsi/gomega v1.9.0/go.mod h1:Ho0h+IUsWyvy1OpqCwxlQ/21gkhVunqlU8fDGcoTdcA= github.com/onsi/gomega v1.10.1/go.mod h1:iN09h71vgCQne3DLsj+A5owkum+a2tYe+TOCB1ybHNo= -github.com/onsi/gomega v1.13.0 h1:7lLHu94wT9Ij0o6EWWclhu0aOh32VxhkwEJvzuWPeak= github.com/onsi/gomega v1.13.0/go.mod h1:lRk9szgn8TxENtWd0Tp4c3wjlRfMTMH27I+3Je41yGY= +github.com/onsi/gomega v1.16.0 h1:6gjqkI8iiRHMvdccRJM8rVKjCWk6ZIm6FTm3ddIe4/c= +github.com/onsi/gomega v1.16.0/go.mod h1:HnhC7FXeEQY45zxNK3PPoIUhzk/80Xly9PcubAlGdZY= github.com/op/go-logging v0.0.0-20160315200505-970db520ece7/go.mod h1:HzydrMdWErDVzsI23lYNej1Htcns9BCg93Dk0bBINWk= +github.com/opencontainers/runtime-spec v1.0.2 h1:UfAcuLBJB9Coz72x1hgl8O5RVzTdNiaglX6v2DM6FI0= +github.com/opencontainers/runtime-spec v1.0.2/go.mod h1:jwyrGlmzljRJv/Fgzds9SsS/C5hL+LL3ko9hs6T5lQ0= github.com/opentracing-contrib/go-observer v0.0.0-20170622124052-a52f23424492/go.mod h1:Ngi6UdF0k5OKD5t5wlmGhe/EDKPoUM3BXZSSfIuJbis= github.com/opentracing/basictracer-go v1.0.0/go.mod h1:QfBfYuafItcjQuMwinw9GhYKwFXS9KnPs5lxoYwgW74= github.com/opentracing/opentracing-go v1.0.2/go.mod h1:UkNAQd3GIcIGf0SeVgPpRdFStlNbqXla1AfSYxPUl2o= @@ -1168,13 +1300,20 @@ github.com/openzipkin/zipkin-go v0.1.1/go.mod h1:NtoC/o8u3JlF1lSlyPNswIbeQH9bJTm github.com/openzipkin/zipkin-go v0.1.6/go.mod h1:QgAqvLzwWbR/WpD4A3cGpPtJrZXNIiJc5AZX7/PBEpw= github.com/openzipkin/zipkin-go v0.2.1/go.mod h1:NaW6tEwdmWMaCDZzg8sh+IBNOxHMPnhQw8ySjnjRyN4= github.com/openzipkin/zipkin-go v0.2.2/go.mod h1:NaW6tEwdmWMaCDZzg8sh+IBNOxHMPnhQw8ySjnjRyN4= +github.com/openzipkin/zipkin-go v0.4.0 h1:CtfRrOVZtbDj8rt1WXjklw0kqqJQwICrCKmlfUuBUUw= +github.com/openzipkin/zipkin-go v0.4.0/go.mod h1:4c3sLeE8xjNqehmF5RpAFLPLJxXscc0R4l6Zg0P1tTQ= github.com/pact-foundation/pact-go v1.0.4/go.mod h1:uExwJY4kCzNPcHRj+hCR/HBbOOIwwtUjcrb0b5/5kLM= github.com/pascaldekloe/goe v0.0.0-20180627143212-57f6aae5913c/go.mod h1:lzWF7FIEvWOWxwDKqyGYQf6ZUaNfKdP144TG7ZOy1lc= +github.com/pbnjay/memory v0.0.0-20210728143218-7b4eea64cf58 h1:onHthvaw9LFnH4t2DcNVpwGmV9E1BkGknEliJkfwQj0= +github.com/pbnjay/memory v0.0.0-20210728143218-7b4eea64cf58/go.mod h1:DXv8WO4yhMYhSNPKjeNKa5WY9YCIEBRbNzFFPJbWO6Y= github.com/pborman/uuid v1.2.0/go.mod h1:X/NO0urCmaxf9VXbdlT7C2Yzkj2IKimNn4k+gtPdI/k= github.com/pelletier/go-toml v1.2.0/go.mod h1:5z9KED0ma1S8pY6P1sdut58dfprrGBbd/94hg7ilaic= github.com/performancecopilot/speed v3.0.0+incompatible/go.mod h1:/CLtqpZ5gBg1M9iaPbIdPPGyKcA8hKdoy6hAWba7Yac= +github.com/petar/GoLLRB v0.0.0-20210522233825-ae3b015fd3e9 h1:1/WtZae0yGtPq+TI6+Tv1WTxkukpXeMlviSxvL7SRgk= +github.com/petar/GoLLRB v0.0.0-20210522233825-ae3b015fd3e9/go.mod h1:x3N5drFsm2uilKKuuYo6LdyD8vZAW55sH/9w+pbo1sw= github.com/pierrec/lz4 v1.0.2-0.20190131084431-473cd7ce01a1/go.mod h1:3/3N9NVKO0jef7pBehbT1qWhCMrIgbYNnFAZCqQ5LRc= github.com/pierrec/lz4 v2.0.5+incompatible/go.mod h1:pdkljMzZIN41W+lC3N2tnIh5sFi+IEE17M5jbnwPHcY= +github.com/pierrec/lz4 v2.6.1+incompatible/go.mod h1:pdkljMzZIN41W+lC3N2tnIh5sFi+IEE17M5jbnwPHcY= github.com/pkg/errors v0.8.0/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4= @@ -1197,8 +1336,9 @@ github.com/prometheus/client_golang v1.3.0/go.mod h1:hJaj2vgQTGQmVCsAACORcieXFeD github.com/prometheus/client_golang v1.7.1/go.mod h1:PY5Wy2awLA44sXw4AOSfFBetzPP4j5+D6mVACh+pe2M= github.com/prometheus/client_golang v1.9.0/go.mod h1:FqZLKOZnGdFAhOK4nqGHa7D66IdsO+O441Eve7ptJDU= github.com/prometheus/client_golang v1.10.0/go.mod h1:WJM3cc3yu7XKBKa/I8WeZm+V3eltZnBwfENSU7mdogU= -github.com/prometheus/client_golang v1.11.0 h1:HNkLOAEQMIDv/K+04rukrLx6ch7msSRwf3/SASFAGtQ= github.com/prometheus/client_golang v1.11.0/go.mod h1:Z6t4BnS23TR94PD6BsDNk8yVqroYurpAkEiz0P2BEV0= +github.com/prometheus/client_golang v1.12.1 h1:ZiaPsmm9uiBeaSMRznKsCDNtPCS0T3JVDGF+06gjBzk= +github.com/prometheus/client_golang v1.12.1/go.mod h1:3Z9XVyYiZYEO+YQWt3RD2R3jrbd179Rt297l4aS6nDY= github.com/prometheus/client_model v0.0.0-20180712105110-5c3871d89910/go.mod h1:MbSGuTsp3dbXC40dX6PRTWyKYBIrTGTE9sqQNg2J8bo= github.com/prometheus/client_model v0.0.0-20190115171406-56726106282f/go.mod h1:MbSGuTsp3dbXC40dX6PRTWyKYBIrTGTE9sqQNg2J8bo= github.com/prometheus/client_model v0.0.0-20190129233127-fd36f4220a90/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= @@ -1216,8 +1356,10 @@ github.com/prometheus/common v0.15.0/go.mod h1:U+gB1OBLb1lF3O42bTCL+FK18tX9Oar16 github.com/prometheus/common v0.18.0/go.mod h1:U+gB1OBLb1lF3O42bTCL+FK18tX9Oar16Clt/msog/s= github.com/prometheus/common v0.26.0/go.mod h1:M7rCNAaPfAosfx8veZJCuw84e35h3Cfd9VFqTh1DIvc= github.com/prometheus/common v0.28.0/go.mod h1:vu+V0TpY+O6vW9J44gczi3Ap/oXXR10b+M/gUGO4Hls= -github.com/prometheus/common v0.30.0 h1:JEkYlQnpzrzQFxi6gnukFPdQ+ac82oRhzMcIduJu/Ug= github.com/prometheus/common v0.30.0/go.mod h1:vu+V0TpY+O6vW9J44gczi3Ap/oXXR10b+M/gUGO4Hls= +github.com/prometheus/common v0.32.1/go.mod h1:vu+V0TpY+O6vW9J44gczi3Ap/oXXR10b+M/gUGO4Hls= +github.com/prometheus/common v0.33.0 h1:rHgav/0a6+uYgGdNt3jwz8FNSesO/Hsang3O0T9A5SE= +github.com/prometheus/common v0.33.0/go.mod h1:gB3sOl7P0TvJabZpLY5uQMpUqRCPPCyRLCZYc7JZTNE= github.com/prometheus/procfs v0.0.0-20180725123919-05ee40e3a273/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk= github.com/prometheus/procfs v0.0.0-20181005140218-185b4288413d/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk= github.com/prometheus/procfs v0.0.0-20181204211112-1dc9a6cbc91a/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk= @@ -1230,13 +1372,21 @@ github.com/prometheus/procfs v0.6.0/go.mod h1:cz+aTbrPOrUb4q7XlbU9ygM+/jj0fzG6c1 github.com/prometheus/procfs v0.7.3 h1:4jVXhlkAyzOScmCkXBTOLRLTz8EeU+eyjrwB/EPq0VU= github.com/prometheus/procfs v0.7.3/go.mod h1:cz+aTbrPOrUb4q7XlbU9ygM+/jj0fzG6c1xBZuNvfVA= github.com/prometheus/statsd_exporter v0.21.0/go.mod h1:rbT83sZq2V+p73lHhPZfMc3MLCHmSHelCh9hSGYNLTQ= +github.com/rabbitmq/amqp091-go v1.1.0/go.mod h1:ogQDLSOACsLPsIq0NpbtiifNZi2YOz0VTJ0kHRghqbM= +github.com/raulk/clock v1.1.0 h1:dpb29+UKMbLqiU/jqIJptgLR1nn23HLgMY0sTCDza5Y= +github.com/raulk/clock v1.1.0/go.mod h1:3MpVxdZ/ODBQDxbN+kzshf5OSZwPjtMDx6BBXBmOeY0= +github.com/raulk/go-watchdog v1.2.0 h1:konN75pw2BMmZ+AfuAm5rtFsWcJpKF3m02rKituuXNo= +github.com/raulk/go-watchdog v1.2.0/go.mod h1:lzSbAl5sh4rtI8tYHU01BWIDzgzqaQLj6RcA1i4mlqI= github.com/rcrowley/go-metrics v0.0.0-20181016184325-3113b8401b8a/go.mod h1:bCqnVzQkZxMG4s8nGwiZ5l3QUCyqpo9Y+/ZMZ9VjZe4= +github.com/rcrowley/go-metrics v0.0.0-20201227073835-cf1acfcdf475/go.mod h1:bCqnVzQkZxMG4s8nGwiZ5l3QUCyqpo9Y+/ZMZ9VjZe4= github.com/rogpeppe/fastuuid v0.0.0-20150106093220-6724a57986af/go.mod h1:XWv6SoW27p1b0cqNHllgS5HIMJraePCO15w5zCzIWYg= github.com/rogpeppe/fastuuid v1.2.0/go.mod h1:jVj6XXZzXRy/MSR5jhDC/2q6DgLz+nrA6LYCDYWNEvQ= github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4= github.com/rogpeppe/go-internal v1.6.1 h1:/FiVV8dS/e+YqF2JvO3yXRFbBLTIuSDkuC7aBOAvL+k= github.com/rogpeppe/go-internal v1.6.1/go.mod h1:xXDCJY+GAPziupqXw64V24skbSoqbTEfhy4qGm1nDQc= github.com/rs/cors v1.7.0/go.mod h1:gFx+x8UowdsKA9AchylcLynDq+nNFfI8FkUZdN/jGCU= +github.com/rs/xid v1.2.1/go.mod h1:+uKXf+4Djp6Md1KODXJxgGQPKngRmWyn10oCKFzNHOQ= +github.com/rs/zerolog v1.21.0/go.mod h1:ZPhntP/xmq1nnND05hhpAh2QMhSsA4UN3MGZ6O2J3hM= github.com/russross/blackfriday v1.5.2/go.mod h1:JO/DiYxRf+HjHt06OyowR9PTA263kcR/rfWxYHBV53g= github.com/russross/blackfriday/v2 v2.0.1/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM= github.com/rwcarlsen/goexif v0.0.0-20190401172101-9e8deecbddbd/go.mod h1:hPqNNc0+uJM6H+SuU8sEs5K5IQeKccPqeSjfgcKGgPk= @@ -1270,6 +1420,8 @@ github.com/shurcooL/webdavfs v0.0.0-20170829043945-18c3829fa133/go.mod h1:hKmq5k github.com/sirupsen/logrus v1.2.0/go.mod h1:LxeOpSwHxABJmUn/MG1IvRgCAasNZTLOkJPxbbu5VWo= github.com/sirupsen/logrus v1.4.2/go.mod h1:tLMulIdttU9McNUspp0xgXVQah82FyeX6MwdIuYE2rE= github.com/sirupsen/logrus v1.6.0/go.mod h1:7uNnSEd1DgxDLC74fIahvMZmmYsHGZGEOFrfsX/uA88= +github.com/sirupsen/logrus v1.7.0/go.mod h1:yWOB1SBYBC5VeMP7gHvWumXLIWorT60ONWic61uBYv0= +github.com/sirupsen/logrus v1.8.1/go.mod h1:yWOB1SBYBC5VeMP7gHvWumXLIWorT60ONWic61uBYv0= github.com/smartystreets/assertions v0.0.0-20180927180507-b2de0cb4f26d/go.mod h1:OnSkiWE9lh6wB0YB77sQom3nweQdgAjqCqsofrRNTgc= github.com/smartystreets/assertions v1.0.0 h1:UVQPSSmc3qtTi+zPPkCXvZX9VvW/xT/NsRvKfwY81a8= github.com/smartystreets/assertions v1.0.0/go.mod h1:kHHU4qYBaI3q23Pp3VPrmWhuIUrLW/7eUrw0BU5VaoM= @@ -1301,27 +1453,39 @@ github.com/streadway/amqp v0.0.0-20190404075320-75d898a42a94/go.mod h1:AZpEONHx3 github.com/streadway/amqp v0.0.0-20190827072141-edfb9018d271/go.mod h1:AZpEONHx3DKn8O/DFsRAY58/XVQiIPMTMB1SddzLXVw= github.com/streadway/handy v0.0.0-20190108123426-d5acb3125c2a/go.mod h1:qNTQ5P5JnDBl6z3cMAg/SywNDC5ABu5ApDIw6lUbRmI= github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= +github.com/stretchr/objx v0.1.1 h1:2vfRuCMp5sSVIDSqO8oNnWJq7mPa6KVP3iPIwFBuy8A= github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs= github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4= github.com/stretchr/testify v1.5.1/go.mod h1:5W2xD1RspED5o8YsWQXVCued0rvSQ+mT+I5cxcmMvtA= github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= -github.com/stretchr/testify v1.7.0 h1:nwc3DEeHmmLAfoZucVR881uASk0Mfjw8xYJ99tb5CcY= github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= +github.com/stretchr/testify v1.7.1 h1:5TQK59W5E3v0r2duFAb7P95B6hEeOyEnHRa8MjYSMTY= +github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= github.com/syndtr/goleveldb v1.0.0 h1:fBdIW9lB4Iz0n9khmH8w27SJ3QEJ7+IgjPEwGSZiFdE= github.com/syndtr/goleveldb v1.0.0/go.mod h1:ZVVdQEZoIme9iO1Ch2Jdy24qqXrMMOU6lpPAyBWyWuQ= github.com/tarm/serial v0.0.0-20180830185346-98f6abe2eb07/go.mod h1:kDXzergiv9cbyO7IOYJZWg1U88JhDg3PB6klq9Hg2pA= github.com/texttheater/golang-levenshtein v0.0.0-20180516184445-d188e65d659e/go.mod h1:XDKHRm5ThF8YJjx001LtgelzsoaEcvnA7lVWz9EeX3g= +github.com/tidwall/gjson v1.14.0 h1:6aeJ0bzojgWLa82gDQHcx3S0Lr/O51I9bJ5nv6JFx5w= +github.com/tidwall/gjson v1.14.0/go.mod h1:/wbyibRr2FHMks5tjHJ5F8dMZh3AcwJEMf5vlfC0lxk= +github.com/tidwall/match v1.1.1 h1:+Ho715JplO36QYgwN9PGYNhgZvoUSc9X2c80KVTi+GA= +github.com/tidwall/match v1.1.1/go.mod h1:eRSPERbgtNPcGhD8UCthc6PmLEQXEWd3PRB5JTxsfmM= +github.com/tidwall/pretty v1.2.0 h1:RWIZEg2iJ8/g6fDDYzMpobmaoGh5OLl4AXtGUGPcqCs= +github.com/tidwall/pretty v1.2.0/go.mod h1:ITEVvHYasfjBbM0u2Pg8T2nJnzm8xPwvNhhsoaGGjNU= github.com/tmc/grpc-websocket-proxy v0.0.0-20170815181823-89b8d40f7ca8/go.mod h1:ncp9v5uamzpCO7NfCPTXjqaC+bZgJeR0sMTm6dMHP7U= github.com/tv42/httpunix v0.0.0-20191220191345-2ba4b9c3382c h1:u6SKchux2yDvFQnDHS3lPnIRmfVJ5Sxy3ao2SIdysLQ= github.com/tv42/httpunix v0.0.0-20191220191345-2ba4b9c3382c/go.mod h1:hzIxponao9Kjc7aWznkXaL4U4TWaDSs8zcsY4Ka08nM= github.com/ugorji/go/codec v0.0.0-20181204163529-d75b2dcb6bc8/go.mod h1:VFNgLljTbGfSG7qAOspJ7OScBnGdDN/yBr0sguwnwf0= github.com/urfave/cli v1.20.0/go.mod h1:70zkFmudgCuE/ngEzBv17Jvp/497gISqfk5gWijbERA= github.com/urfave/cli v1.22.1/go.mod h1:Gos4lmkARVdJ6EkW0WaNv/tZAAMe9V7XWyB60NtXRu0= +github.com/urfave/cli v1.22.2/go.mod h1:Gos4lmkARVdJ6EkW0WaNv/tZAAMe9V7XWyB60NtXRu0= github.com/urfave/cli/v2 v2.0.0/go.mod h1:SE9GqnLQmjVa0iPEY0f1w3ygNIYcIJ0OKPMoW2caLfQ= +github.com/urfave/cli/v2 v2.3.0/go.mod h1:LJmUH05zAU44vOAcrfzZQKsZbVcdbOG8rtL3/XcUArI= github.com/viant/assertly v0.4.8/go.mod h1:aGifi++jvCrUaklKEKT0BU95igDNaqkvz+49uaYMPRU= github.com/viant/toolbox v0.24.0/go.mod h1:OxMCG57V0PXuIP2HNQrtJf2CjqdmbrOx5EkMILuUhzM= +github.com/wI2L/jsondiff v0.2.0 h1:dE00WemBa1uCjrzQUUTE/17I6m5qAaN0EMFOg2Ynr/k= +github.com/wI2L/jsondiff v0.2.0/go.mod h1:axTcwtBkY4TsKuV+RgoMhHyHKKFRI6nnjRLi8LLYQnA= github.com/wangjia184/sortedset v0.0.0-20160527075905-f5d03557ba30/go.mod h1:YkocrP2K2tcw938x9gCOmT5G5eCD6jsTz0SZuyAqwIE= github.com/warpfork/go-testmark v0.3.0/go.mod h1:jhEf8FVxd+F17juRubpmut64NEG6I2rgkUhlcqqXwE0= github.com/warpfork/go-testmark v0.9.0 h1:nc+uaCiv5lFQLYjhuC2LTYeJ7JaC+gdDmsz9r0ISy0Y= @@ -1332,6 +1496,8 @@ github.com/warpfork/go-wish v0.0.0-20200122115046-b9ea61034e4a h1:G++j5e0OC488te github.com/warpfork/go-wish v0.0.0-20200122115046-b9ea61034e4a/go.mod h1:x6AKhvSSexNrVSrViXSHUEbICjmGXhtgABaHIySUSGw= github.com/whyrusleeping/base32 v0.0.0-20170828182744-c30ac30633cc h1:BCPnHtcboadS0DvysUuJXZ4lWVv5Bh5i7+tbIyi+ck4= github.com/whyrusleeping/base32 v0.0.0-20170828182744-c30ac30633cc/go.mod h1:r45hJU7yEoA81k6MWNhpMj/kms0n14dkzkxYHoB96UM= +github.com/whyrusleeping/cbor v0.0.0-20171005072247-63513f603b11 h1:5HZfQkwe0mIfyDmc1Em5GqlNRzcdtlv4HTNmdpt7XH0= +github.com/whyrusleeping/cbor v0.0.0-20171005072247-63513f603b11/go.mod h1:Wlo/SzPmxVp6vXpGt/zaXhHH0fn4IxgqZc82aKg6bpQ= github.com/whyrusleeping/cbor-gen v0.0.0-20200123233031-1cdf64d27158/go.mod h1:Xj/M2wWU+QdTdRbu/L/1dIZY8/Wb2K9pAhtroQuxJJI= github.com/whyrusleeping/cbor-gen v0.0.0-20200710004633-5379fc63235d/go.mod h1:fgkXqYy7bV2cFeIEOkVTZS/WjXARfBqSH6Q2qHL33hQ= github.com/whyrusleeping/cbor-gen v0.0.0-20210219115102-f37d292932f2 h1:bsUlNhdmbtlfdLVXAVfuvKQ01RnWAM09TVrJkI7NZs4= @@ -1353,6 +1519,9 @@ github.com/whyrusleeping/multiaddr-filter v0.0.0-20160516205228-e903e4adabd7/go. github.com/whyrusleeping/timecache v0.0.0-20160911033111-cfcb2f1abfee h1:lYbXeSvJi5zk5GLKVuid9TVjS9a0OmLIDKTfoZBL6Ow= github.com/whyrusleeping/timecache v0.0.0-20160911033111-cfcb2f1abfee/go.mod h1:m2aV4LZI4Aez7dP5PMyVKEHhUyEJ/RjmPEDOpDvudHg= github.com/x-cray/logrus-prefixed-formatter v0.5.2/go.mod h1:2duySbKsL6M18s5GU7VPsoEPHyzalCE06qoARUCeBBE= +github.com/xdg-go/pbkdf2 v1.0.0/go.mod h1:jrpuAogTd400dnrH08LKmI/xc1MbPOebTwRqcT5RDeI= +github.com/xdg-go/scram v1.0.2/go.mod h1:1WAq6h33pAW+iRreB34OORO2Nf7qel3VV3fjBj+hCSs= +github.com/xdg-go/stringprep v1.0.2/go.mod h1:8F9zXuvzgwmyT5DUm4GUfZGDdT3W+LCvS6+da4O5kxM= github.com/xiang90/probing v0.0.0-20190116061207-43a291ad63a2/go.mod h1:UETIi67q53MR2AWcXfiuqkDkRtnGDLqkBTpCHuJHxtU= github.com/xordataexchange/crypt v0.0.3-0.20170626215501-b2862e3d0a77/go.mod h1:aYKd//L2LvnjZzWKhF00oedf4jCCReLcmhLdhm1A27Q= github.com/yuin/goldmark v1.1.25/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= @@ -1360,6 +1529,7 @@ github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9de github.com/yuin/goldmark v1.1.32/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= github.com/yuin/goldmark v1.3.5/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k= +github.com/yuin/goldmark v1.4.1/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k= go.etcd.io/bbolt v1.3.3/go.mod h1:IbVyRI1SCnLcuJnV2u8VeU0CEYM7e686BmAb1XKL+uU= go.etcd.io/etcd v0.0.0-20191023171146-3cf2f69b5738/go.mod h1:dnLIgRNXwCJa5e+c6mIZCrds/GIG4ncV9HhK5PX7jPg= go.opencensus.io v0.18.0/go.mod h1:vKdFvxhtzZ9onBp9VKHK8z/sRpBMnKAsufL7wlDrCOA= @@ -1373,15 +1543,43 @@ go.opencensus.io v0.22.3/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw= go.opencensus.io v0.22.4/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw= go.opencensus.io v0.23.0 h1:gqCw0LfLxScz8irSi8exQc7fyQ0fKQU/qnC/X8+V/1M= go.opencensus.io v0.23.0/go.mod h1:XItmlyltB5F7CS4xOC1DcqMoFqwtC6OG2xF7mCv7P7E= -go.opentelemetry.io/otel v0.20.0 h1:eaP0Fqu7SXHwvjiqDq83zImeehOHX8doTvU9AwXON8g= +go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.31.0/go.mod h1:PFmBsWbldL1kiWZk9+0LBZz2brhByaGsvp6pRICMlPE= go.opentelemetry.io/otel v0.20.0/go.mod h1:Y3ugLH2oa81t5QO+Lty+zXf8zC9L26ax4Nzoxm/dooo= -go.opentelemetry.io/otel/metric v0.20.0 h1:4kzhXFP+btKm4jwxpjIqjs41A7MakRFUS86bqLHTIw8= +go.opentelemetry.io/otel v1.2.0/go.mod h1:aT17Fk0Z1Nor9e0uisf98LrntPGMnk4frBO9+dkf69I= +go.opentelemetry.io/otel v1.6.0/go.mod h1:bfJD2DZVw0LBxghOTlgnlI0CV3hLDu9XF/QKOUXMTQQ= +go.opentelemetry.io/otel v1.6.1/go.mod h1:blzUabWHkX6LJewxvadmzafgh/wnvBSDBdOuwkAtrWQ= +go.opentelemetry.io/otel v1.6.3 h1:FLOfo8f9JzFVFVyU+MSRJc2HdEAXQgm7pIv2uFKRSZE= +go.opentelemetry.io/otel v1.6.3/go.mod h1:7BgNga5fNlF/iZjG06hM3yofffp0ofKCDwSXx1GC4dI= +go.opentelemetry.io/otel/exporters/jaeger v1.6.3 h1:7tvBU1Ydbzq080efuepYYqC1Pv3/vOFBgCSrxLb24d0= +go.opentelemetry.io/otel/exporters/jaeger v1.6.3/go.mod h1:YgX3eZWbJzgrNyNHCK0otGreAMBTIAcObtZS2VRi6sU= +go.opentelemetry.io/otel/exporters/otlp/internal/retry v1.6.3 h1:nAmg1WgsUXoXf46dJG9eS/AzOcvkCTK4xJSUYpWyHYg= +go.opentelemetry.io/otel/exporters/otlp/internal/retry v1.6.3/go.mod h1:NEu79Xo32iVb+0gVNV8PMd7GoWqnyDXRlj04yFjqz40= +go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.6.3 h1:4/UjHWMVVc5VwX/KAtqJOHErKigMCH8NexChMuanb/o= +go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.6.3/go.mod h1:UJmXdiVVBaZ63umRUTwJuCMAV//GCMvDiQwn703/GoY= +go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.6.3 h1:leYDq5psbM3K4QNcZ2juCj30LjUnvxjuYQj1mkGjXFM= +go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.6.3/go.mod h1:ycItY/esVj8c0dKgYTOztTERXtPzcfDU/0o8EdwCjoA= +go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp v1.6.3 h1:ufVuVt/g16GZ/yDOyp+AcCGebGX8u4z7kDRuwEX0DkA= +go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp v1.6.3/go.mod h1:S18p8VK4KRHHyAg5rH3iUnJUcRvIUg9xwIWtq1MWibM= +go.opentelemetry.io/otel/exporters/stdout/stdouttrace v1.6.3 h1:uSApZ0WGBOrEMNp0rtX1jtpYBh5CvktueAEHTWfLOtk= +go.opentelemetry.io/otel/exporters/stdout/stdouttrace v1.6.3/go.mod h1:LhMjYbVawqjXUIRbAT2CFuWtuQVxTPL8WEtxB/Iyg5Y= +go.opentelemetry.io/otel/exporters/zipkin v1.6.3 h1:5BzTuSYCahVIsRlxZjJO23WUsJjq/q70TnmNZz5Klk8= +go.opentelemetry.io/otel/exporters/zipkin v1.6.3/go.mod h1:JRfrU4shvi54xFL5KA9ftJv7El3FMMpkz3V2S8aZ/q0= go.opentelemetry.io/otel/metric v0.20.0/go.mod h1:598I5tYlH1vzBjn+BTuhzTCSb/9debfNp6R3s7Pr1eU= -go.opentelemetry.io/otel/oteltest v0.20.0 h1:HiITxCawalo5vQzdHfKeZurV8x7ljcqAgiWzF6Vaeaw= +go.opentelemetry.io/otel/metric v0.28.0/go.mod h1:TrzsfQAmQaB1PDcdhBauLMk7nyyg9hm+GoQq/ekE9Iw= go.opentelemetry.io/otel/oteltest v0.20.0/go.mod h1:L7bgKf9ZB7qCwT9Up7i9/pn0PWIa9FqQ2IQ8LoxiGnw= -go.opentelemetry.io/otel/trace v0.20.0 h1:1DL6EXUdcg95gukhuRRvLDO/4X5THh/5dIV52lqtnbw= +go.opentelemetry.io/otel/sdk v0.20.0/go.mod h1:g/IcepuwNsoiX5Byy2nNV0ySUF1em498m7hBWC279Yc= +go.opentelemetry.io/otel/sdk v1.2.0/go.mod h1:jNN8QtpvbsKhgaC6V5lHiejMoKD+V8uadoSafgHPx1U= +go.opentelemetry.io/otel/sdk v1.6.3 h1:prSHYdwCQOX5DrsEzxowH3nLhoAzEBdZhvrR79scfLs= +go.opentelemetry.io/otel/sdk v1.6.3/go.mod h1:A4iWF7HTXa+GWL/AaqESz28VuSBIcZ+0CV+IzJ5NMiQ= go.opentelemetry.io/otel/trace v0.20.0/go.mod h1:6GjCW8zgDjwGHGa6GkyeB8+/5vjT16gUEi0Nf1iBdgw= +go.opentelemetry.io/otel/trace v1.2.0/go.mod h1:N5FLswTubnxKxOJHM7XZC074qpeEdLy3CgAVsdMucK0= +go.opentelemetry.io/otel/trace v1.6.0/go.mod h1:qs7BrU5cZ8dXQHBGxHMOxwME/27YH2qEp4/+tZLLwJE= +go.opentelemetry.io/otel/trace v1.6.1/go.mod h1:RkFRM1m0puWIq10oxImnGEduNBzxiN7TXluRBtE+5j0= +go.opentelemetry.io/otel/trace v1.6.3 h1:IqN4L+5b0mPNjdXIiZ90Ni4Bl5BRkDQywePLWemd9bc= +go.opentelemetry.io/otel/trace v1.6.3/go.mod h1:GNJQusJlUgZl9/TQBPKU/Y/ty+0iVB5fjhKeJGZPGFs= go.opentelemetry.io/proto/otlp v0.7.0/go.mod h1:PqfVotwruBrMGOCsRd/89rSnXhoiJIqeYNgFYFoEGnI= +go.opentelemetry.io/proto/otlp v0.15.0 h1:h0bKrvdrT/9sBwEJ6iWUqT/N/xPcS66bL4u3isneJ6w= +go.opentelemetry.io/proto/otlp v0.15.0/go.mod h1:H7XAot3MsfNsj7EXtrA2q5xSNQ10UqI405h3+duxN4U= go.uber.org/atomic v1.3.2/go.mod h1:gD2HeocX3+yG+ygLZcrzQJaqmWj9AIm7n08wl/qW/PE= go.uber.org/atomic v1.4.0/go.mod h1:gD2HeocX3+yG+ygLZcrzQJaqmWj9AIm7n08wl/qW/PE= go.uber.org/atomic v1.5.0/go.mod h1:sABNBOSYdrvTF6hTgEIbc7YasKWGhgEQZyfxyTvoXHQ= @@ -1389,21 +1587,24 @@ go.uber.org/atomic v1.6.0/go.mod h1:sABNBOSYdrvTF6hTgEIbc7YasKWGhgEQZyfxyTvoXHQ= go.uber.org/atomic v1.7.0/go.mod h1:fEN4uk6kAWBTFdckzkM89CLk9XfWZrxpCo0nPH17wJc= go.uber.org/atomic v1.9.0 h1:ECmE8Bn/WFTYwEW/bpKD3M8VtR/zQVbavAoalC1PYyE= go.uber.org/atomic v1.9.0/go.mod h1:fEN4uk6kAWBTFdckzkM89CLk9XfWZrxpCo0nPH17wJc= -go.uber.org/dig v1.12.0 h1:l1GQeZpEbss0/M4l/ZotuBndCrkMdjnygzgcuOjAdaY= go.uber.org/dig v1.12.0/go.mod h1:X34SnWGr8Fyla9zQNO2GSO2D+TIuqB14OS8JhYocIyw= -go.uber.org/fx v1.15.0 h1:kcfBpAm98n0ksanyyZLFE/Q3T7yPi13Ge2liu3TxR+A= -go.uber.org/fx v1.15.0/go.mod h1:jI3RazQUhGv5KkpZIRv+kuP4CcgX3fnc0qX8bLnzbx8= +go.uber.org/dig v1.14.0 h1:VmGvIH45/aapXPQkaOrK5u4B5B7jxZB98HM/utx0eME= +go.uber.org/dig v1.14.0/go.mod h1:jHAn/z1Ld1luVVyGKOAIFYz/uBFqKjjEEdIqVAqfQ2o= +go.uber.org/fx v1.16.0 h1:N8i80+X1DCX+qMRiKzM+jPPZiIiyK/bVCysga3+B+1w= +go.uber.org/fx v1.16.0/go.mod h1:OMoT5BnXcOaiexlpjtpE4vcAmzyDKyRs9TRYXCzamx8= go.uber.org/goleak v1.0.0/go.mod h1:8a7PlsEVH3e/a/GLqe5IIrQx6GzcnRmZEufDUTk4A7A= go.uber.org/goleak v1.1.10/go.mod h1:8a7PlsEVH3e/a/GLqe5IIrQx6GzcnRmZEufDUTk4A7A= go.uber.org/goleak v1.1.11-0.20210813005559-691160354723/go.mod h1:cwTWslyiVhfpKIDGSZEM2HlOvcqm+tG4zioyIeLoqMQ= -go.uber.org/goleak v1.1.11 h1:wy28qYRKZgnJTxGxvye5/wgWr1EKjmUDGYox5mGlRlI= go.uber.org/goleak v1.1.11/go.mod h1:cwTWslyiVhfpKIDGSZEM2HlOvcqm+tG4zioyIeLoqMQ= +go.uber.org/goleak v1.1.12 h1:gZAh5/EyT/HQwlpkCy6wTpqfH9H8Lz8zbm3dZh+OyzA= +go.uber.org/goleak v1.1.12/go.mod h1:cwTWslyiVhfpKIDGSZEM2HlOvcqm+tG4zioyIeLoqMQ= go.uber.org/multierr v1.1.0/go.mod h1:wR5kodmAFQ0UK8QlbwjlSNy0Z68gJhDJUG5sjR94q/0= go.uber.org/multierr v1.3.0/go.mod h1:VgVr7evmIr6uPjLBxg28wmKNXyqE9akIJ5XnfpiKl+4= go.uber.org/multierr v1.5.0/go.mod h1:FeouvMocqHpRaaGuG9EjoKcStLC43Zu/fmqdUMPcKYU= go.uber.org/multierr v1.6.0/go.mod h1:cdWPpRnG4AhwMwsgIHip0KRBQjJy5kYEpYjJxpXp9iU= -go.uber.org/multierr v1.7.0 h1:zaiO/rmgFjbmCXdSYJWQcdvOCsthmdaHfr3Gm2Kx4Ec= go.uber.org/multierr v1.7.0/go.mod h1:7EAYxJLBy9rStEaz58O2t4Uvip6FSURkq8/ppBp95ak= +go.uber.org/multierr v1.8.0 h1:dg6GjLku4EH+249NNmoIciG9N/jURbDG+pFlTkhzIC8= +go.uber.org/multierr v1.8.0/go.mod h1:7EAYxJLBy9rStEaz58O2t4Uvip6FSURkq8/ppBp95ak= go.uber.org/tools v0.0.0-20190618225709-2cfd321de3ee/go.mod h1:vJERXedbb3MVM5f9Ejo0C68/HhF8uaILCdgjnY+goOA= go.uber.org/zap v1.10.0/go.mod h1:vwi/ZaCAaUcBkycHslxD9B2zi4UTXhF60s6SWpuDF0Q= go.uber.org/zap v1.13.0/go.mod h1:zwrFLgMcdUuIBviXEYEH1YKNaOBnKXsx2IPda5bBwHM= @@ -1412,8 +1613,9 @@ go.uber.org/zap v1.15.0/go.mod h1:Mb2vm2krFEG5DV0W9qcHBYFtp/Wku1cvYaqPsS/WYfc= go.uber.org/zap v1.16.0/go.mod h1:MA8QOfq0BHJwdXa996Y4dYkAqRKB8/1K1QMMZVaNZjQ= go.uber.org/zap v1.18.1/go.mod h1:xg/QME4nWcxGxrpdeYfq7UvYrLh66cuVKdrbD1XF/NI= go.uber.org/zap v1.19.0/go.mod h1:xg/QME4nWcxGxrpdeYfq7UvYrLh66cuVKdrbD1XF/NI= -go.uber.org/zap v1.19.1 h1:ue41HOKd1vGURxrmeKIgELGb3jPW9DMUDGtsinblHwI= go.uber.org/zap v1.19.1/go.mod h1:j3DNczoxDZroyBnOT1L/Q79cfUMGZxlv/9dzN7SM1rI= +go.uber.org/zap v1.21.0 h1:WefMeulhovoZ2sYXz7st6K0sLj7bBhpiFaud4r4zST8= +go.uber.org/zap v1.21.0/go.mod h1:wjWOCqI0f2ZZrJF/UufIOkiC8ii6tm1iqIsLo76RfJw= go4.org v0.0.0-20180809161055-417644f6feb5/go.mod h1:MkTOUMDaeVYJUOUsaDXIhWPZYa1yOyC1qaOBpL57BhE= go4.org v0.0.0-20200411211856-f5505b9728dd h1:BNJlw5kRTzdmyfh5U8F93HA2OwkP7ZGwA51eJ/0wKOU= go4.org v0.0.0-20200411211856-f5505b9728dd/go.mod h1:CIiUVy99QCPfoE13bO4EZaz5GZMZXMSBGhxRdsvzbkg= @@ -1444,16 +1646,21 @@ golang.org/x/crypto v0.0.0-20200510223506-06a226fb4e37/go.mod h1:LzIPMQfyMNhhGPh golang.org/x/crypto v0.0.0-20200602180216-279210d13fed/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= golang.org/x/crypto v0.0.0-20200820211705-5c72a883971a/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= +golang.org/x/crypto v0.0.0-20201112155050-0c6587e931a9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= golang.org/x/crypto v0.0.0-20210220033148-5ea612d1eb83/go.mod h1:jdWPYTVW3xRLrWPugEBEK3UY2ZEsg3UU495nc5E+M+I= golang.org/x/crypto v0.0.0-20210322153248-0c34fe9e7dc2/go.mod h1:T9bdIzuCu7OtxOm1hfPfRQxPLYneinmdGuTeoZ9dtd4= golang.org/x/crypto v0.0.0-20210506145944-38f3c27a63bf/go.mod h1:P+XmwS30IXTQdn5tA2iutPOUgjI07+tq3H3K9MVA1s8= golang.org/x/crypto v0.0.0-20210513164829-c07d793c2f9a/go.mod h1:P+XmwS30IXTQdn5tA2iutPOUgjI07+tq3H3K9MVA1s8= +golang.org/x/crypto v0.0.0-20210711020723-a769d52b0f97/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= golang.org/x/crypto v0.0.0-20210813211128-0a44fdfbc16e/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= -golang.org/x/crypto v0.0.0-20210921155107-089bfa567519 h1:7I4JAnoQBe7ZtJcBaYHi5UtiO8tQHbUSXxL+pnGRANg= +golang.org/x/crypto v0.0.0-20210920023735-84f357641f63/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= +golang.org/x/crypto v0.0.0-20220411220226-7b82a4e95df4 h1:kUhD7nTDoI3fVd9G4ORWrbV5NY0liEs/Jg2pv5f+bBA= +golang.org/x/crypto v0.0.0-20220411220226-7b82a4e95df4/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4= golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= golang.org/x/exp v0.0.0-20190306152737-a1d7652674e8/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= golang.org/x/exp v0.0.0-20190510132918-efd6b22b2522/go.mod h1:ZjyILWgesfNpC6sMxTJOJm9Kp84zZh5NQWvqDGG3Qr8= +golang.org/x/exp v0.0.0-20190731235908-ec7cb31e5a56/go.mod h1:JhuoJpWY28nO4Vef9tZUw9qufEGTyX1+7lmHxV5q5G4= golang.org/x/exp v0.0.0-20190829153037-c13cbed26979/go.mod h1:86+5VVa7VpoJ4kLfm080zCjGlMRFzhUhsZKEZO7MGek= golang.org/x/exp v0.0.0-20191030013958-a1ab85dbe136/go.mod h1:JXzH8nQsPlswgeRAPE3MuO9GYsAcnJvJ4vnMwN/5qkY= golang.org/x/exp v0.0.0-20191129062945-2f5052295587/go.mod h1:2RIsYlXP63K8oxa1u096TMicItID8zy7Y6sNkU49FU4= @@ -1461,6 +1668,8 @@ golang.org/x/exp v0.0.0-20191227195350-da58074b4299/go.mod h1:2RIsYlXP63K8oxa1u0 golang.org/x/exp v0.0.0-20200119233911-0405dc783f0a/go.mod h1:2RIsYlXP63K8oxa1u096TMicItID8zy7Y6sNkU49FU4= golang.org/x/exp v0.0.0-20200207192155-f17229e696bd/go.mod h1:J/WKrq2StrnmMY6+EHIKF9dgMWnmCNThgcyBT1FY9mM= golang.org/x/exp v0.0.0-20200224162631-6cc2880d07d6/go.mod h1:3jZMyOhIsHpP37uCMkUooju7aAi5cS1Q23tOzKc+0MU= +golang.org/x/exp v0.0.0-20210615023648-acb5c1269671 h1:ddvpKwqE7dm58PoWjRCmaCiA3DANEW0zWGfNYQD212Y= +golang.org/x/exp v0.0.0-20210615023648-acb5c1269671/go.mod h1:DVyR6MI7P4kEQgvZJSj1fQGrWIi2RzIrfYWycwheUAc= golang.org/x/image v0.0.0-20190227222117-0694c2d4d067/go.mod h1:kZ7UVZpmo3dzQBMxlp+ypCbDeSB+sBbTgSJuh5dn5js= golang.org/x/image v0.0.0-20190802002840-cff245a6509b/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0= golang.org/x/lint v0.0.0-20180702182130-06c8688daad7/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE= @@ -1473,18 +1682,20 @@ golang.org/x/lint v0.0.0-20190909230951-414d861bb4ac/go.mod h1:6SW0HCj/g11FgYtHl golang.org/x/lint v0.0.0-20190930215403-16217165b5de/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= golang.org/x/lint v0.0.0-20191125180803-fdd1cda4f05f/go.mod h1:5qLYkcX4OjUUV8bRuDixDT3tpyyb+LUpUlRWLxfhWrs= golang.org/x/lint v0.0.0-20200130185559-910be7a94367/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY= -golang.org/x/lint v0.0.0-20200302205851-738671d3881b h1:Wh+f8QHJXR411sJR8/vRBTZ7YapZaRvUcLFFJhusH0k= golang.org/x/lint v0.0.0-20200302205851-738671d3881b/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY= golang.org/x/mobile v0.0.0-20190312151609-d3739f865fa6/go.mod h1:z+o9i4GpDbdi3rU15maQ/Ox0txvL9dWGYEHz965HBQE= golang.org/x/mobile v0.0.0-20190719004257-d2bd2a29d028/go.mod h1:E/iHnbuqvinMTCcRqshq8CkpyQDoeVncDDYHnLhea+o= +golang.org/x/mobile v0.0.0-20201217150744-e6ae53a27f4f/go.mod h1:skQtrUTUwhdJvXM/2KKJzY8pDgNr9I/FOMqDVRPBUS4= golang.org/x/mod v0.0.0-20190513183733-4bf6d317e70e/go.mod h1:mXi4GBBbnImb6dmsKGUJ2LatrhH/nqhxcFungHvyanc= golang.org/x/mod v0.1.0/go.mod h1:0QHyrYULN0/3qlju5TqG8bIK38QM8yzMo5ekMj3DlcY= golang.org/x/mod v0.1.1-0.20191105210325-c90efee705ee/go.mod h1:QqPTAvyqsEbceGzBzNggFXnrqF1CaUcvgkdR5Ot7KZg= golang.org/x/mod v0.1.1-0.20191107180719-034126e5016b/go.mod h1:QqPTAvyqsEbceGzBzNggFXnrqF1CaUcvgkdR5Ot7KZg= +golang.org/x/mod v0.1.1-0.20191209134235-331c550502dd/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= golang.org/x/mod v0.2.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= -golang.org/x/mod v0.4.2 h1:Gz96sIWK3OalVv/I/qNygP42zyoKp3xptRVCWRFEBvo= golang.org/x/mod v0.4.2/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= +golang.org/x/mod v0.6.0-dev.0.20220106191415-9b9b3d81d5e3 h1:kQgndtyPBW/JIYERgdxfwMYh3AVStj88WQTlNDi2a+o= +golang.org/x/mod v0.6.0-dev.0.20220106191415-9b9b3d81d5e3/go.mod h1:3p9vT2HGsQu2K1YbXdKPJLVgG5VJdoTa1poYQBtP1AY= golang.org/x/net v0.0.0-20180719180050-a680a1efc54d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= @@ -1540,8 +1751,15 @@ golang.org/x/net v0.0.0-20210423184538-5f58ad60dda6/go.mod h1:OJAsFXCWl8Ukc7SiCT golang.org/x/net v0.0.0-20210428140749-89ef3d95e781/go.mod h1:OJAsFXCWl8Ukc7SiCT/9KSuxbyM7479/AVlXFRxuMCk= golang.org/x/net v0.0.0-20210505024714-0287a6fb4125/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= golang.org/x/net v0.0.0-20210525063256-abc453219eb5/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= -golang.org/x/net v0.0.0-20210813160813-60bc85c4be6d h1:LO7XpTYMwTqxjLcGWPijK3vRXg1aWdlNOVOHRq45d7c= +golang.org/x/net v0.0.0-20210726213435-c6fcb2dbf985/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= golang.org/x/net v0.0.0-20210813160813-60bc85c4be6d/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= +golang.org/x/net v0.0.0-20210917221730-978cfadd31cf/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= +golang.org/x/net v0.0.0-20211015210444-4f30a5c0130f/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= +golang.org/x/net v0.0.0-20211112202133-69e39bad7dc2/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= +golang.org/x/net v0.0.0-20220127200216-cd36cc0744dd/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk= +golang.org/x/net v0.0.0-20220225172249-27dd8689420f/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk= +golang.org/x/net v0.0.0-20220418201149-a630d4f3e7a2 h1:6mzvA99KwZxbOrxww4EvWVQUnN1+xEu9tafK5ZxkYeA= +golang.org/x/net v0.0.0-20220418201149-a630d4f3e7a2/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk= golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= golang.org/x/oauth2 v0.0.0-20181017192945-9dcd33a902f4/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= golang.org/x/oauth2 v0.0.0-20181203162652-d668ce993890/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= @@ -1550,6 +1768,8 @@ golang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45/go.mod h1:gOpvHmFTYa4Iltr golang.org/x/oauth2 v0.0.0-20191202225959-858c2ad4c8b6/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= golang.org/x/oauth2 v0.0.0-20200107190931-bf48bf16ab8d/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= golang.org/x/oauth2 v0.0.0-20210514164344-f6687ab2804c/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= +golang.org/x/oauth2 v0.0.0-20211104180415-d3ed0bb246c8/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= +golang.org/x/oauth2 v0.0.0-20220223155221-ee480838109b/go.mod h1:DAh4E804XQdzx2j+YRIaUnCqCV2RuMz24cGBJ5QYIrc= golang.org/x/perf v0.0.0-20180704124530-6e6d33e29852/go.mod h1:JLpeXjPJfIyPr5TlbXLkXWLhP8nz10XfvxElABhCtcw= golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= @@ -1563,6 +1783,7 @@ golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJ golang.org/x/sync v0.0.0-20201207232520-09787c993a3a/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20210220032951-036812b2e83c h1:5KslGYwFpkhGh+Q16bwMP3cOontH8FOep7tGV86Y7SQ= golang.org/x/sync v0.0.0-20210220032951-036812b2e83c/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sys v0.0.0-20180810173357-98c5dad5d1a0/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20180823144017-11551d06cbcc/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20180905080454-ebe1bf3edb33/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= @@ -1609,6 +1830,7 @@ golang.org/x/sys v0.0.0-20200106162015-b016eb3dc98e/go.mod h1:h1NjWce9XRLGQEsW7w golang.org/x/sys v0.0.0-20200113162924-86b910548bc1/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200116001909-b77594299b42/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200122134326-e047566fdf82/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200124204421-9fbb57f87de9/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200202164722-d101bd2416d5/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200212091648-12a6c2dcc1e4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200223170610-d5e6a3e2c0ae/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= @@ -1628,6 +1850,7 @@ golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7w golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20201214210602-f9fddec55a1e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210112080510-489259a85091/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210119212857-b64e53b001e4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210124154548-22da62e12c0c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210303074136-134d130e1a04/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210309074719-68d13333faf2/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= @@ -1635,6 +1858,7 @@ golang.org/x/sys v0.0.0-20210315160823-c6e025ad8005/go.mod h1:h1NjWce9XRLGQEsW7w golang.org/x/sys v0.0.0-20210317225723-c4fcb01b228e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210330210617-4fbd30eecc44/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210423185535-09eb48e85fd7/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210426080607-c94f62235c83/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210510120138-977fb7262007/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20210511113859-b0526f3d8744/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= @@ -1644,15 +1868,20 @@ golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBc golang.org/x/sys v0.0.0-20210630005230-0f9fa26af87c/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20210816183151-1e6c022a8912/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20210903071746-97244b99971b/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20211025112917-711f33c9992c h1:i4MLwL3EbCgobekQtkVW94UBSPLMadfEGtKq+CAFsEU= -golang.org/x/sys v0.0.0-20211025112917-711f33c9992c/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20211019181941-9d821ace8654/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20211216021012-1d35b9e2eb4e/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220114195835-da31bd327af9/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220412211240-33da011f77ad h1:ntjMns5wyP/fN65tdBD4g8J5w8n015+iIIs9rtjXkY0= +golang.org/x/sys v0.0.0-20220412211240-33da011f77ad/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/term v0.0.0-20201117132131-f5c789dd3221/go.mod h1:Nr5EML6q2oocZ2LXRh80K7BxOlk5/8JxuGnuhpl+muw= golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= +golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8= golang.org/x/text v0.0.0-20170915032832-14c0d48ead0c/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.1-0.20180807135948-17ff2d5776d2/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk= golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= +golang.org/x/text v0.3.5/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/text v0.3.7 h1:olpwvP2KacW1ZWvsR7uQhoyTYvKAupfQrRGBFM352Gk= golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ= @@ -1694,6 +1923,7 @@ golang.org/x/tools v0.0.0-20191216052735-49a3e744a425/go.mod h1:TB2adYChydJhpapK golang.org/x/tools v0.0.0-20191216173652-a0e659d51361/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= golang.org/x/tools v0.0.0-20191227053925-7b8e75db28f4/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= golang.org/x/tools v0.0.0-20200103221440-774c71fcf114/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= +golang.org/x/tools v0.0.0-20200117012304-6edc0a871e69/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= golang.org/x/tools v0.0.0-20200117161641-43d50277825c/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= golang.org/x/tools v0.0.0-20200122220014-bf1340f18c4a/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= golang.org/x/tools v0.0.0-20200130002326-2f3ba24bd6e7/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= @@ -1715,14 +1945,18 @@ golang.org/x/tools v0.0.0-20200804011535-6c149bb5ef0d/go.mod h1:njjCfa9FT2d7l9Bc golang.org/x/tools v0.0.0-20200825202427-b303f430e36d/go.mod h1:njjCfa9FT2d7l9Bc6FUM5FLjQPp3cFF28FI3qnDFljA= golang.org/x/tools v0.0.0-20201224043029-2b0845dc783e/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= golang.org/x/tools v0.0.0-20210106214847-113979e3529a/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= +golang.org/x/tools v0.1.0/go.mod h1:xkSsbof2nBLbhDlRMhhhyNLN/zl3eTqcnHD5viDpcZ0= golang.org/x/tools v0.1.1/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk= -golang.org/x/tools v0.1.5 h1:ouewzE6p+/VEB31YYnTbEJdi8pFqKp4P4n85vwo3DHA= golang.org/x/tools v0.1.5/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk= +golang.org/x/tools v0.1.6-0.20210726203631-07bc1bf47fb2/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk= +golang.org/x/tools v0.1.10 h1:QjFRCZxdOhBJ/UNgnBZLbNV13DlbnK0quyivTnXJM20= +golang.org/x/tools v0.1.10/go.mod h1:Uh6Zz+xoGYZom868N8YTex3t7RhtHDBrE8Gzo9bV56E= golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= -golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1 h1:go1bK/D/BFZV2I8cIQd1NKEZ+0owSTG1fDTci4IqFcE= golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= +golang.org/x/xerrors v0.0.0-20220411194840-2f41105eb62f h1:GGU+dLjvlC3qDwqYgL6UgRmHXhOOgns0bZu2Ty5mm6U= +golang.org/x/xerrors v0.0.0-20220411194840-2f41105eb62f/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= google.golang.org/api v0.0.0-20180910000450-7ca32eb868bf/go.mod h1:4mhQ8q/RsB7i+udVvVy5NUi08OU8ZlA0gRVgrF7VFY0= google.golang.org/api v0.0.0-20181030000543-1d582fd0359e/go.mod h1:4mhQ8q/RsB7i+udVvVy5NUi08OU8ZlA0gRVgrF7VFY0= google.golang.org/api v0.1.0/go.mod h1:UGEZY7KEX120AnNLIHFMKIo4obdJhkp2tPbaPlQx13Y= @@ -1786,6 +2020,8 @@ google.golang.org/genproto v0.0.0-20200618031413-b414f8b61790/go.mod h1:jDfRM7Fc google.golang.org/genproto v0.0.0-20200729003335-053ba62fc06f/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= google.golang.org/genproto v0.0.0-20200804131852-c06518451d9c/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= google.golang.org/genproto v0.0.0-20200825200019-8632dd797987/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= +google.golang.org/genproto v0.0.0-20211118181313-81c1377c94b1 h1:b9mVrqYfq3P4bCdaLg1qtBnPzUYgglsIdjZkL/fQVOE= +google.golang.org/genproto v0.0.0-20211118181313-81c1377c94b1/go.mod h1:5CzLGKJ67TSI2B9POpiiyGha0AjJvZIUgRMt1dSmuhc= google.golang.org/grpc v1.14.0/go.mod h1:yo6s7OP7yaDglbqo1J04qKzAhqBH6lvTonzMVmEdcZw= google.golang.org/grpc v1.16.0/go.mod h1:0JHn/cJsOMiMfNA9+DeHDlAU7KAAB5GDlYFpa9MZMio= google.golang.org/grpc v1.17.0/go.mod h1:6QZJwpn2B+Zp71q/5VxRsJ6NXXVCE5NRUHRo+f3cWCs= @@ -1810,8 +2046,11 @@ google.golang.org/grpc v1.31.1/go.mod h1:N36X2cJ7JwdamYAgDz+s+rVMFjt3numwzf/HckM google.golang.org/grpc v1.33.1/go.mod h1:fr5YgcSWrqhRRxogOsw7RzIpsmvOZ6IcH4kBYTpR3n0= google.golang.org/grpc v1.33.2/go.mod h1:JMHMWHQWaTccqQQlmk3MJZS+GWXOdAesneDmEnv2fbc= google.golang.org/grpc v1.36.0/go.mod h1:qjiiYl8FncCW8feJPdyg3v6XW24KsRHe+dy9BAGRRjU= -google.golang.org/grpc v1.40.0 h1:AGJ0Ih4mHjSeibYkFGh1dD9KJ/eOtZ93I6hoHhukQ5Q= google.golang.org/grpc v1.40.0/go.mod h1:ogyxbiOoUXAkP+4+xa6PZSE9DZgIHtSpzjDTB9KAK34= +google.golang.org/grpc v1.41.0/go.mod h1:U3l9uK9J0sini8mHphKoXyaqDA/8VyGnDee1zzIUK6k= +google.golang.org/grpc v1.42.0/go.mod h1:k+4IHHFw41K8+bbowsex27ge2rCb65oeWqe4jJ590SU= +google.golang.org/grpc v1.45.0 h1:NEpgUqV3Z+ZjkqMsxMg11IaDrXY4RY6CQukSGK0uI1M= +google.golang.org/grpc v1.45.0/go.mod h1:lN7owxKUQEqMfSyQikvvk5tf/6zMPsrK+ONuO11+0rQ= google.golang.org/protobuf v0.0.0-20200109180630-ec00e32a8dfd/go.mod h1:DFci5gLYBciE7Vtevhsrf46CRTquxDuWsQurQQe4oz8= google.golang.org/protobuf v0.0.0-20200221191635-4d8936d0db64/go.mod h1:kwYJMbMJ01Woi6D6+Kah6886xMZcty6N08ah7+eCXa0= google.golang.org/protobuf v0.0.0-20200228230310-ab0ca4ff8a60/go.mod h1:cfTl7dwQJ+fmap5saPgwCLgHXTUD7jkjRqWcaiX5VyM= @@ -1824,8 +2063,9 @@ google.golang.org/protobuf v1.24.0/go.mod h1:r/3tXBNzIEhYS9I1OUVjXDlt8tc493IdKGj google.golang.org/protobuf v1.25.0/go.mod h1:9JNX74DMeImyA3h4bdi1ymwjUzf21/xIlbajtzgsN7c= google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw= google.golang.org/protobuf v1.26.0/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc= -google.golang.org/protobuf v1.27.1 h1:SnqbnDw1V7RiZcXPx5MEeqPv2s79L9i7BJUlG/+RurQ= google.golang.org/protobuf v1.27.1/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc= +google.golang.org/protobuf v1.28.0 h1:w43yiav+6bVFTBQFZX0r7ipe9JQ1QsbMgHwbBziscLw= +google.golang.org/protobuf v1.28.0/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I= gopkg.in/alecthomas/kingpin.v2 v2.2.6/go.mod h1:FMv+mEhP44yOT+4EoQTLFTRgOQ1FBLkstjWtayDeSgw= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= @@ -1867,8 +2107,10 @@ honnef.co/go/tools v0.0.0-20190523083050-ea95bdfd59fc/go.mod h1:rf3lG4BRIbNafJWh honnef.co/go/tools v0.0.1-2019.2.3/go.mod h1:a3bituU0lyd329TUQxRnasdCoJDkEUEAqEt0JzvZhAg= honnef.co/go/tools v0.0.1-2020.1.3/go.mod h1:X/FiERA/W4tHapMX5mGpAtMSVEeEUOyHaw9vFzvIQ3k= honnef.co/go/tools v0.0.1-2020.1.4/go.mod h1:X/FiERA/W4tHapMX5mGpAtMSVEeEUOyHaw9vFzvIQ3k= -lukechampine.com/blake3 v1.1.6 h1:H3cROdztr7RCfoaTpGZFQsrqvweFLrqS73j7L7cmR5c= +honnef.co/go/tools v0.1.3/go.mod h1:NgwopIslSNH47DimFoV78dnkksY2EFtX0ajyb3K/las= lukechampine.com/blake3 v1.1.6/go.mod h1:tkKEOtDkNtklkXtLNEOGNq5tcV90tJiA1vAA12R78LA= +lukechampine.com/blake3 v1.1.7 h1:GgRMhmdsuK8+ii6UZFDL8Nb+VyMwadAgcJyfYHxG6n0= +lukechampine.com/blake3 v1.1.7/go.mod h1:tkKEOtDkNtklkXtLNEOGNq5tcV90tJiA1vAA12R78LA= pgregory.net/rapid v0.4.7 h1:MTNRktPuv5FNqOO151TM9mDTa+XHcX6ypYeISDVD14g= pgregory.net/rapid v0.4.7/go.mod h1:UYpPVyjFHzYBGHIxLFoupi8vwk6rXNzRY9OMvVxFIOU= rsc.io/binaryregexp v0.2.0/go.mod h1:qTv7/COck+e2FymRvadv62gMdZztPaShugOCi3I+8D8= diff --git a/docs/examples/go-ipfs-as-a-library/main.go b/docs/examples/go-ipfs-as-a-library/main.go index 5b032e56a29..3833deb3e1d 100644 --- a/docs/examples/go-ipfs-as-a-library/main.go +++ b/docs/examples/go-ipfs-as-a-library/main.go @@ -11,12 +11,12 @@ import ( "strings" "sync" - config "github.com/ipfs/go-ipfs-config" files "github.com/ipfs/go-ipfs-files" icore "github.com/ipfs/interface-go-ipfs-core" icorepath "github.com/ipfs/interface-go-ipfs-core/path" ma "github.com/multiformats/go-multiaddr" + "github.com/ipfs/go-ipfs/config" "github.com/ipfs/go-ipfs/core" "github.com/ipfs/go-ipfs/core/coreapi" "github.com/ipfs/go-ipfs/core/node/libp2p" From 00c4a0c1203b6649f0d688d97d5021f486ba952b Mon Sep 17 00:00:00 2001 From: Adin Schmahmann Date: Wed, 4 May 2022 16:10:39 -0400 Subject: [PATCH 389/414] Merge pull request #8941 from ipfs/docs/0.13.0-changelog docs: v0.13.0 changelog --- CHANGELOG.md | 1123 +++++++++++++++++++++++++++++++++++++++++++++- bin/mkreleaselog | 1 + 2 files changed, 1105 insertions(+), 19 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 80155f91fac..463b9448aa2 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,24 +1,1109 @@ # go-ipfs changelog -## v0.13 (DRAFT) - -### BREAKING CHANGES - -- `ipfs block put` command produces CIDv1 with `raw` codec by default now - - `ipfs block put --cid-codec` makes `block put` return CID with alternative codec - - this impacts only the returned CID, it does not trigger any validation or data transformation - - codec names are validated against tables from https://github.com/multiformats/go-multicodec - - `ipfs block put --format` is deprecated. It used incorrect codec names and should be avoided for new deployments. Use it only if you need the old, invalid behavior, namely: - - `ipfs block put --format=v0` will produce CIDv0 (implicit dag-pb) - - `ipfs block put --format=cbor` will produce CIDv1 with dag-cbor (!) - - `ipfs block put --format=protobuf` will produce CIDv1 with dag-pb (!) -- `ipfs cid codecs` command - - it now lists codecs from https://github.com/multiformats/go-multicodec - - `ipfs cid codecs --supported` can be passed to only show codecs supported in various go-ipfs commands -- `Swarm` configuration - - Daemon will refuse to start if long-deprecated RelayV1 config key `Swarm.EnableAutoRelay` or `Swarm.DisableRelay` is set to `true` - - When `Swarm.Transports.Network.Relay` is disabled, `Swarm.RelayService` and `Swarm.RelayClient` are also disabled (unless user explicitly enabled them). - - If user enabled them manually, then we error on start and inform they require `Swarm.Transports.Network.Relay` +## v0.13.0 2022-05-04 + +We're happy to announce go-ipfs 0.13.0, packed full of changes and improvements! + +As usual, this release includes important fixes, some of which may be critical for security. Unless the fix addresses a bug being exploited in the wild, the fix will _not_ be called out in the release notes. Please make sure to update ASAP. See our [release process](https://github.com/ipfs/go-ipfs/tree/master/docs/releases.md#security-fix-policy) for details. + +### Overview + +Below is an outline of all that is in this release, so you get a sense of all that's included. + +- [🛠 BREAKING CHANGES](#---breaking-changes) + * [`ipfs block put` command](#-ipfs-block-put--command) + * [`ipfs cid codecs` command](#-ipfs-cid-codecs--command) + * [`Swarm` configuration](#-swarm--configuration) + * [Circuit Relay V1 is deprecated](#circuit-relay-v1-is-deprecated) + * [`ls` requests for `/multistream/1.0.0` are removed](#-ls--requests-for---multistream-100--are-removed) + * [Gateway Items](#gateway-items) +- [🔦 Highlights](#---highlights) + * [🧑‍💼 libp2p Network Resource Manager (`Swarm.ResourceMgr`)](#------libp2p-network-resource-manager---swarmresourcemgr--) + * [🔃 Relay V2 client with auto discovery (`Swarm.RelayClient`)](#---relay-v2-client-with-auto-discovery---swarmrelayclient--) + * [🌉 HTTP Gateway improvements](#---http-gateway-improvements) + + [🍱 Support for Block and CAR response formats](#---support-for-block-and-car-response-formats) + + [🐎 Fast listing generation for huge directories](#---fast-listing-generation-for-huge--directories) + + [🎫 Improved `Etag` and `If-None-Match` for bandwidth savings](#---improved--etag--and--if-none-match--for-bandwidth-savings) + + [⛓️ Added X-Ipfs-Roots for smarter HTTP caches](#---added-x-ipfs-roots-for-smarter-http-caches) + + [🌡️ Added metrics per response type](#----added-metrics-per-response-type) + * [🕵️ OpenTelemetry tracing](#----opentelemetry-tracing) + + [How to use Jaeger UI for visual tracing?](#how-to-use-jaeger-ui-for-visual-tracing-) + * [🩺 Built-in `ipfs diag profile` to ease debugging](#---built-in--ipfs-diag-profile--to-ease-debugging) + * [🔑 Support for PEM/PKCS8 for key import/export](#---support-for-pem-pkcs8-for-key-import-export) + * [🧹 Using standard IPLD codec names across the CLI/HTTP API](#---using-standard-ipld-codec-names-across-the-cli-http-api) + * [🐳 Custom initialization for Docker](#---custom-initialization-for-docker) + * [RPC API docs for experimental and deprecated commands](#rpc-api-docs-for-experimental-and-deprecated-commands) + * [Yamux over Mplex](#yamux-over-mplex) + +### 🛠 BREAKING CHANGES + +#### `ipfs block put` command + +`ipfs block put` command returns a CIDv1 with `raw` codec by default now. +- `ipfs block put --cid-codec` makes `block put` return CID with alternative codec + - This impacts only the returned CID; it does not trigger any validation or data transformation. + - Retrieving a block with a different codec or CID version than it was put with is valid. + - Codec names are validated against tables from [go-multicodec](https://github.com/multiformats/go-multicodec) library. +- `ipfs block put --format` is deprecated. It used incorrect codec names and should be avoided for new deployments. Use it only if you need the old, invalid behavior, namely: + - `ipfs block put --format=v0` will produce CIDv0 (implicit dag-pb) + - `ipfs block put --format=cbor` will produce CIDv1 with dag-cbor (!) + - `ipfs block put --format=protobuf` will produce CIDv1 with dag-pb (!) + +#### `ipfs cid codecs` command +- Now lists codecs from [go-multicodec](https://github.com/multiformats/go-multicodec) library. +- `ipfs cid codecs --supported` can be passed to only show codecs supported in various go-ipfs commands. + +#### `Swarm` configuration +- Daemon will refuse to start if long-deprecated RelayV1 config key `Swarm.EnableAutoRelay` or `Swarm.DisableRelay` is set to `true`. +- If `Swarm.Transports.Network.Relay` is disabled, then `Swarm.RelayService` and `Swarm.RelayClient` are also disabled (unless they have been explicitly enabled). + +#### Circuit Relay V1 is deprecated +- By default, `Swarm.RelayClient` does not use Circuit Relay V1. Circuit V1 support is only enabled when `Swarm.RelayClient.StaticRelays` are specified. + +#### `ls` requests for `/multistream/1.0.0` are removed +- go-libp2p 0.19 removed support for undocumented `ls` command ([PR](https://github.com/multiformats/go-multistream/pull/76)). If you are still using it for internal testing, it is time to refactor ([example](https://github.com/ipfs/go-ipfs/commit/39047bcf61163096d1c965283d671c7c487c9173)) + +#### Gateway Behavior +Directory listings returned by the HTTP Gateway won't have size column if the directory is bigger than [`Gateway.FastDirIndexThreshold`](https://github.com/ipfs/go-ipfs/blob/master/docs/config.md#gatewayfastdirindexthreshold) config (default is 100). + +To understand the wider context why we made these changes, read *Highlights* below. + +### 🔦 Highlights + +#### 🧑‍💼 libp2p Network Resource Manager (`Swarm.ResourceMgr`) + +*You can now easily bound how much resource usage libp2p consumes! This aids in protecting nodes from consuming more resources then are available to them.* + +The [libp2p Network Resource Manager](https://github.com/libp2p/go-libp2p-resource-manager#readme) is enabled by default, but can be disabled via: + +`ipfs config --json Swarm.ResourceMgr.Enabled false` + +When enabled, it applies some safe defaults that can be inspected and adjusted with: +- `ipfs swarm stats --help` +- `ipfs swarm limit --help` + +User changes persist to config at [`Swarm.ResourceMgr`](https://github.com/ipfs/go-ipfs/blob/master/docs/config.md#swarmresourcemgr). + +#### 🔃 Relay V2 client with auto discovery (`Swarm.RelayClient`) + +*All the pieces are enabled for [hole-punching](https://blog.ipfs.io/2022-01-20-libp2p-hole-punching/) by default, improving connecting with nodes behind NATs and Firewalls!* + +This release enables [`Swarm.RelayClient`](https://github.com/ipfs/go-ipfs/blob/master/docs/config.md#swarmrelayclient) by default, along with circuit v2 relay discovery provided by go-libp2p [v0.19.0](https://github.com/libp2p/go-libp2p/releases/tag/v0.19.0). This means: +1. go-ipfs will coordinate with the counterparty using a [relayed connection](https://github.com/libp2p/specs/blob/master/relay/circuit-v2.md), to [upgrade to a direct connection](https://github.com/libp2p/specs/blob/master/relay/DCUtR.md) through a NAT/firewall whenever possible. +2. go-ipfs daemon will automatically use [public relays](https://github.com/ipfs/go-ipfs/blob/master/docs/config.md#swarmrelayservice) if it detects that it cannot be reached from the public internet (e.g., it's behind a firewall). This results in a `/p2p-circuit` address from a public relay. + +**Notes:** +- [`Swarm.RelayClient`](https://github.com/ipfs/go-ipfs/blob/master/docs/config.md#swarmrelayclient) does not use Circuit Relay V1 nodes any more. Circuit V1 support is only enabled when static relays are specified in [`Swarm.RelayClient.StaticRelays`](https://github.com/ipfs/go-ipfs/blob/master/docs/config.md#swarmrelayclientstaticrelays). +- One can opt-out via [`Swarm.EnableHolePunching`](https://github.com/ipfs/go-ipfs/blob/master/docs/config.md#swarmenableholepunching). + + +#### 🌉 HTTP Gateway improvements + +HTTP Gateway enables seamless interop with the existing Web, clients, user agents, tools, frameworks and libraries. + +This release ships the first batch of improvements that enable creation of faster and smarter CDNs, and unblocks creation of light clients for Mobile and IoT. + +Details below. + +##### 🍱 Support for Block and CAR response formats + +*Alternative response formats from Gateway can be requested to avoid needing to trust a gateway.* + +For now, `{format}` is limited to two options: +- `raw` – fetching single block +- `car` – fetching entire DAG behind a CID as a [CARv1 stream](https://ipld.io/specs/transport/car/carv1/) + +When not set, the default UnixFS response is returned. + +*Why these two formats?* Requesting Block or CAR for `/ipfs/{cid}` allows a client to **use gateways in a trustless fashion**. These types of gateway responses can be verified locally and rejected if digest inside of requested CID does not match received bytes. This enables creation of "light IPFS clients" which use HTTP Gateways as inexpensive transport for [content-addressed](https://docs.ipfs.io/concepts/content-addressing/) data, unlocking use in Mobile and IoT contexts. + + +Future releases will [add support for dag-json and dag-cbor responses](https://github.com/ipfs/go-ipfs/issues/8823). + +There are two ways for requesting CID specific response format: +1. HTTP header: `Accept: application/vnd.ipld.{format}` +- Examples: [application/vnd.ipld.car](https://www.iana.org/assignments/media-types/application/vnd.ipld.car), [application/vnd.ipld.raw](https://www.iana.org/assignments/media-types/application/vnd.ipld.raw) +2. URL paramerer: `?format=` +- Useful for creating "Download CAR" links. + +*Usage examples:* + +1. Downloading a single raw Block and manually importing it to the local datastore: + +```console +$ curl -H 'Accept: application/vnd.ipld.raw' "http://127.0.0.1:8080/ipfs/QmZULkCELmmk5XNfCgTnCyFgAVxBRBXyDHGGMVoLFLiXEN" --output block.bin +$ cat block.bin | ipfs block put +$ ipfs cat QmZULkCELmmk5XNfCgTnCyFgAVxBRBXyDHGGMVoLFLiXEN +hello +``` + +2. Downloading entire DAG as a CAR file and importing it: + +```console +$ ipfs resolve -r /ipns/webui.ipfs.io +/ipfs/bafybeiednzu62vskme5wpoj4bjjikeg3xovfpp4t7vxk5ty2jxdi4mv4bu +$ curl -H 'Accept: application/vnd.ipld.car' "http://127.0.0.1:8080/ipfs/bafybeiednzu62vskme5wpoj4bjjikeg3xovfpp4t7vxk5ty2jxdi4mv4bu" --output webui.car +$ ipfs dag import webui.car +$ ipfs dag stat bafybeiednzu62vskme5wpoj4bjjikeg3xovfpp4t7vxk5ty2jxdi4mv4bu --offline +Size: 27684934, NumBlocks: 394 +``` + +See also: + +- [Content Addressable aRchives (CAR / .car) Specifications](https://ipld.io/specs/transport/car/) +- [IANA media type](https://www.iana.org/assignments/media-types/media-types.xhtml) definitions: [application/vnd.ipld.car](https://www.iana.org/assignments/media-types/application/vnd.ipld.car), [application/vnd.ipld.raw](https://www.iana.org/assignments/media-types/application/vnd.ipld.raw) +- [ipfs-car](https://www.npmjs.com/package/ipfs-car) - CLI tool for verifying and unpacking CAR files +- [go-car](https://github.com/ipld/go-car), [js-car](https://github.com/ipld/js-car/) – CAR libraries for GO and JS + +##### 🐎 Fast listing generation for huge directories + +*Added [`Gateway.FastDirIndexThreshold`](https://github.com/ipfs/go-ipfs/blob/master/docs/config.md#gatewayfastdirindexthreshold) configuration, which allows for fast listings of big directories, without the linear slowdown caused by reading size metadata from child nodes.* + +As an example, the CID `bafybeiggvykl7skb2ndlmacg2k5modvudocffxjesexlod2pfvg5yhwrqm` represents UnixFS directory with over 10k (10100) of files. + +Opening it with go-ipfs 0.12 would require fetching size information of each file, which would take a long long time, most likely causing timeout in the browser or CDN, and introducing unnecessary burden on the gateway node. + +go-ipfs 0.13 opens it instantly, because the number of items is bigger than the default [`Gateway.FastDirIndexThreshold`](https://github.com/ipfs/go-ipfs/blob/master/docs/config.md#gatewayfastdirindexthreshold) and only the root UnixFS node needs to be resolved before the HTML Dir Index is returned to the user. + +Notes: +- The default threshold is 100 items. +- Setting to 0 will enable fast listings for all directories. +- CLI users will note that this is equivalent to running `ipfs ls -s --size=false --resolve-type=false /ipfs/bafybeiggvykl7skb2ndlmacg2k5modvudocffxjesexlod2pfvg5yhwrqm`. Now the same speed is available on the gateways. + +##### 🎫 Improved `Etag` and `If-None-Match` for bandwidth savings + +*Every response type has an unique [`Etag`](https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/ETag) which can be used by the client or CDN to save bandwidth, as a gateway does not need to resend a full response if the content was not changed.* + +Gateway evaluates Etags sent by a client in [`If-None-Match`](https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/If-None-Match) and returns status code 304 (Not Modified) on strong or weak match ([RFC 7232, 2.3](https://datatracker.ietf.org/doc/html/rfc7232#section-2.3)). + +##### ⛓️ Added X-Ipfs-Roots for smarter HTTP caches + +`X-Ipfs-Roots` is now returned with every Gateway response. It is a way to indicate all CIDs required for resolving path segments from `X-Ipfs-Path`. Together, these two headers are meant to improve interop with existing HTTP software (load-balancers, caches, CDNs). + +This additional information allows HTTP caches and CDNs to make better decisions around cache invalidation: not just invalidate everything under specific IPNS website when the root changes, but do more fine-grained cache invalidation by detecting when only a specific subdirectory (branch of a [DAG](https://docs.ipfs.io/concepts/glossary/#dag)) changes. + +##### 🌡️ Added metrics per response type + +New metrics can be found at `/debug/metrics/prometheus` on the RPC API port (`127.0.0.1:5001` is the default): + +- `gw_first_content_block_get_latency_seconds` – the time until the first content block is received on GET from the gateway (no matter the content or response types) +- `gw_unixfs_file_get_duration_seconds` – the time to serve an entire UnixFS file from the gateway +- `gw_unixfs_gen_dir_listing_get_duration_seconds` – the time to serve a generated UnixFS HTML directory listing from the gateway +- `gw_car_stream_get_duration_seconds` – the time to GET an entire CAR stream from the gateway +- `gw_raw_block_get_duration_seconds` – The time to GET an entire raw Block from the gateway + + +#### 🕵️ OpenTelemetry tracing + +*Opt-in tracing support with many spans for tracing the duration of specific tasks performed by go-ipfs.* + +See [Tracing](https://github.com/ipfs/go-ipfs/blob/master/docs/environment-variables.md#tracing) for details. + +We will continue to add tracing instrumentation throughout IPFS subcomponents over time. + +##### How to use Jaeger UI for visual tracing? + +One can use the `jaegertracing/all-in-one` Docker image to run a full Jaeger stack and configure go-ipfs to publish traces to it (here, in an ephemeral container): + +```console +$ docker run --rm -it --name jaeger \ + -e COLLECTOR_ZIPKIN_HOST_PORT=:9411 \ + -p 5775:5775/udp \ + -p 6831:6831/udp \ + -p 6832:6832/udp \ + -p 5778:5778 \ + -p 16686:16686 \ + -p 14268:14268 \ + -p 14250:14250 \ + -p 9411:9411 \ + jaegertracing/all-in-one +``` + +Then, in other terminal, start go-ipfs with Jaeger tracing enabled: +``` +$ OTEL_TRACES_EXPORTER=jaeger ipfs daemon +``` + +Finally, the [Jaeger UI](https://github.com/jaegertracing/jaeger-ui#readme) is available at http://localhost:16686 + +Below are examples of visual tracing for Gateway requests. (Note: this a preview how useful this insight is. Details may look different now, as we are constantly improving tracing annotations across the go-ipfs codebase.) + +| CAR | Block | File | Directory | +| ---- | ---- | ---- | ---- | +| ![2022-04-01_01-46](https://user-images.githubusercontent.com/157609/161167986-951d5c8c-9a5e-464d-bc20-81eb5ccbdc22.png) | ![block_2022-04-01_01-47](https://user-images.githubusercontent.com/157609/161167983-e8cac0ce-0575-4271-8cb8-4d44a0d5d786.png) | ![2022-04-01_01-49](https://user-images.githubusercontent.com/157609/161167978-e19aa44c-f5a4-45f4-b7c7-14c313ab1dee.png) | ![dir_2022-04-01_01-48](https://user-images.githubusercontent.com/157609/161167981-456ca52b-3e87-4042-916b-8db149071228.png) | + +#### 🩺 Built-in `ipfs diag profile` to ease debugging +The `diag profile` command has been expanded to include all information that was previously included in the `collect-profiles.sh` script, and the script has been removed. Profiles are now collected in parallel, so that profile collection is much faster. Specific profiles can also be selected for targeted debugging. + +See `ipfs diag profile --help` for more details. + +For general debugging information, see [the debug guide](https://github.com/ipfs/go-ipfs/blob/master/docs/debug-guide.md). + +#### 🔑 Support for PEM/PKCS8 for key import/export + +It is now possible to import or export private keys wrapped in interoperable [PEM PKCS8](https://en.wikipedia.org/wiki/PKCS_8) by passing `--format=pem-pkcs8-cleartext` to `ipfs key import` and `export` commands. + +This improved interop allows for key generation outside of the IPFS node: + +```console +$ openssl genpkey -algorithm ED25519 > ed25519.pem +$ ipfs key import test-openssl -f pem-pkcs8-cleartext ed25519.pem +``` + +Or using external tools like the standard `openssl` to get a PEM file with the public key: +```console + $ ipfs key export testkey --format=pem-pkcs8-cleartext -o privkey.pem + $ openssl pkey -in privkey.pem -pubout > pubkey.pem +``` + +#### 🧹 Using standard IPLD codec names across the CLI/HTTP API + +This release makes necessary (breaking) changes in effort to use canonical codec names from [multicodec/table.csv](https://github.com/multiformats/multicodec/blob/master/table.csv). We also switched to CIDv1 in `block put`. The breaking changes are discussed above. + + +#### 🐳 Custom initialization for Docker + +Docker images published at https://hub.docker.com/r/ipfs/go-ipfs/ now support custom initialization by mounting scripts in the `/container-init.d` directory in the container. Scripts can set custom configuration using `ipfs config`, or otherwise customize the container before the daemon is started. + +Scripts are executed sequentially and in lexicographic order, before the IPFS daemon is started and after `ipfs init` is run and the swarm keys are copied (if the IPFS repo needs initialization). + +For more information, see: +- Documentation: [ Run IPFS inside Docker](https://docs.ipfs.io/how-to/run-ipfs-inside-docker/) +- Examples in [ipfs-shipyard/go-ipfs-docker-examples](https://github.com/ipfs-shipyard/go-ipfs-docker-examples). + +#### RPC API docs for experimental and deprecated commands + +https://docs.ipfs.io/reference/http/api/ now includes separate sections for _experimental_ and _deprecated_ commands. + +We also display a warning in the command line: + +```console +$ ipfs name pubsub state --help +WARNING: EXPERIMENTAL, command may change in future releases +``` + +#### Yamux over Mplex + +The more fully featured yamux stream multiplexer is now prioritized over mplex for outgoing connections. + +### Changelog + +
    +Full Changelog + +- github.com/ipfs/go-ipfs: + - docs: v0.13.0 changelog + - docs(tracing): update env var docs for new tracing env vars + - feat: enable Resource Manager by default + - chore: Update test/dependencies to match go-ipfs dependencies. (#8928) ([ipfs/go-ipfs#8928](https://github.com/ipfs/go-ipfs/pull/8928)) + - chore: fix linting errors (#8930) ([ipfs/go-ipfs#8930](https://github.com/ipfs/go-ipfs/pull/8930)) + - docs: Swarm.ResourceMgr.Limits + - feat: EnableHolePunching by default ([ipfs/go-ipfs#8748](https://github.com/ipfs/go-ipfs/pull/8748)) + - ci: add more golang strictness checks ([ipfs/go-ipfs#8931](https://github.com/ipfs/go-ipfs/pull/8931)) + - feat(gateway): Gateway.FastDirIndexThreshold (#8853) ([ipfs/go-ipfs#8853](https://github.com/ipfs/go-ipfs/pull/8853)) + - docs: replace all git.io links with their actual URLs + - feat: relay v2 discovery (go-libp2p v0.19.0) (#8868) ([ipfs/go-ipfs#8868](https://github.com/ipfs/go-ipfs/pull/8868)) + - fix(cmds): add: reject files with different import dir + - chore: mark 'log tail' experimental (#8912) ([ipfs/go-ipfs#8912](https://github.com/ipfs/go-ipfs/pull/8912)) + - feat: persist limits to Swarm.ResourceMgr.Limits (#8901) ([ipfs/go-ipfs#8901](https://github.com/ipfs/go-ipfs/pull/8901)) + - fix: build after Go 1.17 and Prometheus upgrades (#8916) ([ipfs/go-ipfs#8916](https://github.com/ipfs/go-ipfs/pull/8916)) + - feat(tracing): use OpenTelemetry env vars where possible (#8875) ([ipfs/go-ipfs#8875](https://github.com/ipfs/go-ipfs/pull/8875)) + - feat(cmds): allow to set the configuration file path ([ipfs/go-ipfs#8634](https://github.com/ipfs/go-ipfs/pull/8634)) + - chore: deprecate /api/v0/dns (#8893) ([ipfs/go-ipfs#8893](https://github.com/ipfs/go-ipfs/pull/8893)) + - fix(cmds): CIDv1 and correct multicodecs in 'block put' and 'cid codecs' (#8568) ([ipfs/go-ipfs#8568](https://github.com/ipfs/go-ipfs/pull/8568)) + - feat(gw): improved If-None-Match support (#8891) ([ipfs/go-ipfs#8891](https://github.com/ipfs/go-ipfs/pull/8891)) + - Update Go version to 1.17 (#8815) ([ipfs/go-ipfs#8815](https://github.com/ipfs/go-ipfs/pull/8815)) + - chore(gw): extract logical functions to improve readability (#8885) ([ipfs/go-ipfs#8885](https://github.com/ipfs/go-ipfs/pull/8885)) + - feat(docker): /container-init.d for advanced initialization (#6577) ([ipfs/go-ipfs#6577](https://github.com/ipfs/go-ipfs/pull/6577)) + - feat: port collect-profiles.sh to 'ipfs diag profile' (#8786) ([ipfs/go-ipfs#8786](https://github.com/ipfs/go-ipfs/pull/8786)) + - fix: assets: correctly use the argument err in the WalkDirFunc Hashing Files + - Change `assets.Asset` from a `func` to the embed.FS + - Remove gobindata + - fix: fix context plumbing in gateway handlers (#8871) ([ipfs/go-ipfs#8871](https://github.com/ipfs/go-ipfs/pull/8871)) + - fix(gw): missing return if dir fails to finalize (#8806) ([ipfs/go-ipfs#8806](https://github.com/ipfs/go-ipfs/pull/8806)) + - fix(gw): update metrics only when payload data sent (#8827) ([ipfs/go-ipfs#8827](https://github.com/ipfs/go-ipfs/pull/8827)) + - Merge branch 'release' + - feat: detect changes in go-libp2p-resource-manager (#8857) ([ipfs/go-ipfs#8857](https://github.com/ipfs/go-ipfs/pull/8857)) + - feat: opt-in Swarm.ResourceMgr (go-libp2p v0.18) (#8680) ([ipfs/go-ipfs#8680](https://github.com/ipfs/go-ipfs/pull/8680)) + - feat(cmds): add support for CAR v2 imports (#8854) ([ipfs/go-ipfs#8854](https://github.com/ipfs/go-ipfs/pull/8854)) + - docs(logging): environment variables (#8833) ([ipfs/go-ipfs#8833](https://github.com/ipfs/go-ipfs/pull/8833)) + - fix: unknown fetcher type error (#8830) ([ipfs/go-ipfs#8830](https://github.com/ipfs/go-ipfs/pull/8830)) + - chore: deprecate tar commands (#8849) ([ipfs/go-ipfs#8849](https://github.com/ipfs/go-ipfs/pull/8849)) + - chore: bump go-ipld-format v0.4.0 and fix related sharness tests ([ipfs/go-ipfs#8838](https://github.com/ipfs/go-ipfs/pull/8838)) + - feat: add basic gateway tracing (#8595) ([ipfs/go-ipfs#8595](https://github.com/ipfs/go-ipfs/pull/8595)) + - fix(cli): ipfs add with multiple files of same name (#8493) ([ipfs/go-ipfs#8493](https://github.com/ipfs/go-ipfs/pull/8493)) + - fix(gw): validate requested CAR version (#8835) ([ipfs/go-ipfs#8835](https://github.com/ipfs/go-ipfs/pull/8835)) + - feat: re-enable docker sharness tests (#8808) ([ipfs/go-ipfs#8808](https://github.com/ipfs/go-ipfs/pull/8808)) + - docs: gateway.md (#8825) ([ipfs/go-ipfs#8825](https://github.com/ipfs/go-ipfs/pull/8825)) + - fix(core/commands): do not cache config (#8824) ([ipfs/go-ipfs#8824](https://github.com/ipfs/go-ipfs/pull/8824)) + - remove unused import (#8787) ([ipfs/go-ipfs#8787](https://github.com/ipfs/go-ipfs/pull/8787)) + - feat(cmds): document deprecated RPC API commands (#8802) ([ipfs/go-ipfs#8802](https://github.com/ipfs/go-ipfs/pull/8802)) + - fix(fsrepo): deep merge when setting config ([ipfs/go-ipfs#8793](https://github.com/ipfs/go-ipfs/pull/8793)) + - feat: add gateway histogram metrics (#8443) ([ipfs/go-ipfs#8443](https://github.com/ipfs/go-ipfs/pull/8443)) + - ErrNotFound changes: bubble tagged libraries. ([ipfs/go-ipfs#8803](https://github.com/ipfs/go-ipfs/pull/8803)) + - Fix typos + - Bubble ErrNotFound improvements. + ([ipfs/go-ipfs#8757](https://github.com/ipfs/go-ipfs/pull/8757)) + - feat(gateway): Block and CAR response formats (#8758) ([ipfs/go-ipfs#8758](https://github.com/ipfs/go-ipfs/pull/8758)) + - fix: allow ipfs-companion browser extension to access RPC API (#8690) ([ipfs/go-ipfs#8690](https://github.com/ipfs/go-ipfs/pull/8690)) + - fix(core/node): unwrap fx error in node construction ([ipfs/go-ipfs#8638](https://github.com/ipfs/go-ipfs/pull/8638)) + - Update PATCH_RELEASE_TEMPLATE.md + - feat: add full goroutine stack dump (#8790) ([ipfs/go-ipfs#8790](https://github.com/ipfs/go-ipfs/pull/8790)) + - feat(cmds): extend block size check for dag|block put (#8751) ([ipfs/go-ipfs#8751](https://github.com/ipfs/go-ipfs/pull/8751)) + - feat: add endpoint for enabling block profiling (#8469) ([ipfs/go-ipfs#8469](https://github.com/ipfs/go-ipfs/pull/8469)) + - fix(cmds): option for progress bar in cat/get (#8686) ([ipfs/go-ipfs#8686](https://github.com/ipfs/go-ipfs/pull/8686)) + - docs: note the default reprovider strategy as all (#8603) ([ipfs/go-ipfs#8603](https://github.com/ipfs/go-ipfs/pull/8603)) + - fix: listen on loopback for API and gateway ports in docker-compose.yaml (#8773) ([ipfs/go-ipfs#8773](https://github.com/ipfs/go-ipfs/pull/8773)) + - fix(discovery): fix daemon not starting due to mdns startup failure (#8704) ([ipfs/go-ipfs#8704](https://github.com/ipfs/go-ipfs/pull/8704)) + - Move go-ipfs-config back into go-ipfs, + ([ipfs/go-ipfs#8756](https://github.com/ipfs/go-ipfs/pull/8756)) + - feat: ipfs-webui v2.15 (#8712) ([ipfs/go-ipfs#8712](https://github.com/ipfs/go-ipfs/pull/8712)) + - feat: X-Ipfs-Roots for smarter HTTP caches (#8720) ([ipfs/go-ipfs#8720](https://github.com/ipfs/go-ipfs/pull/8720)) + - chore: add instructions for Chocolatey release + - fix prioritization of stream muxers ([ipfs/go-ipfs#8750](https://github.com/ipfs/go-ipfs/pull/8750)) + - fix(cmds/keystore): do not allow to import keys we don't generate (#8733) ([ipfs/go-ipfs#8733](https://github.com/ipfs/go-ipfs/pull/8733)) + - docs: add Internal.UnixFSShardingSizeThreshold (#8723) ([ipfs/go-ipfs#8723](https://github.com/ipfs/go-ipfs/pull/8723)) + - feat(cmd): add silent option for repo gc (#7147) ([ipfs/go-ipfs#7147](https://github.com/ipfs/go-ipfs/pull/7147)) + - docs(changelog): update v0.12.0 release notes + - Merge branch 'release' + - fix: installation without sudo (#8715) ([ipfs/go-ipfs#8715](https://github.com/ipfs/go-ipfs/pull/8715)) + - Fix typos (#8726) ([ipfs/go-ipfs#8726](https://github.com/ipfs/go-ipfs/pull/8726)) + - fix(build): Recognize Go Beta versions in makefile (#8677) ([ipfs/go-ipfs#8677](https://github.com/ipfs/go-ipfs/pull/8677)) + - chore(cmds): encapsulate ipfs rm logic in another function (#8574) ([ipfs/go-ipfs#8574](https://github.com/ipfs/go-ipfs/pull/8574)) + - feat: warn user when 'pin remote add' while offline (#8621) ([ipfs/go-ipfs#8621](https://github.com/ipfs/go-ipfs/pull/8621)) + - chore(gateway): debug logging for the http requests (#8518) ([ipfs/go-ipfs#8518](https://github.com/ipfs/go-ipfs/pull/8518)) + - docker: build for arm cpu (#8633) ([ipfs/go-ipfs#8633](https://github.com/ipfs/go-ipfs/pull/8633)) + - feat: refactor Fetcher interface used for downloading migrations (#8728) ([ipfs/go-ipfs#8728](https://github.com/ipfs/go-ipfs/pull/8728)) + - feat: log multifetcher errors + - docs: optionalInteger|String|Duration (#8729) ([ipfs/go-ipfs#8729](https://github.com/ipfs/go-ipfs/pull/8729)) + - feat: DNS.MaxCacheTTL for DNS-over-HTTPS resolvers (#8615) ([ipfs/go-ipfs#8615](https://github.com/ipfs/go-ipfs/pull/8615)) + - feat(cmds): ipfs id: support --offline option (#8626) ([ipfs/go-ipfs#8626](https://github.com/ipfs/go-ipfs/pull/8626)) + - feat(cmds): add cleartext PEM/PKCS8 for key import/export (#8616) ([ipfs/go-ipfs#8616](https://github.com/ipfs/go-ipfs/pull/8616)) + - docs: update badger section in config.md (#8662) ([ipfs/go-ipfs#8662](https://github.com/ipfs/go-ipfs/pull/8662)) + - docs: fix typo + - Adding PowerShell to Minimal Go Installation + - Fixed typos in docs/config.md + - docs: add Snap note about customizing IPFS_PATH (#8584) ([ipfs/go-ipfs#8584](https://github.com/ipfs/go-ipfs/pull/8584)) + - Fix typo ([ipfs/go-ipfs#8625](https://github.com/ipfs/go-ipfs/pull/8625)) + - chore: update version to v0.13.0-dev +- github.com/ipfs/go-bitswap (v0.5.1 -> v0.6.0): + - v0.6.0 + - Use ipld.ErrNotFound + - feat: add peer block filter option (#549) ([ipfs/go-bitswap#549](https://github.com/ipfs/go-bitswap/pull/549)) + - configurable target message size ([ipfs/go-bitswap#546](https://github.com/ipfs/go-bitswap/pull/546)) +- github.com/ipfs/go-blockservice (v0.2.1 -> v0.3.0): + - v0.3.0 + - s/log/logger + - Use ipld.ErrNotFound instead of ErrNotFound +- github.com/ipfs/go-filestore (v1.1.0 -> v1.2.0): + - v1.2.0 + - refactor: follow the happy left practice in Filestore.DeleteBlock + - Use ipld.ErrNotFound +- github.com/ipfs/go-graphsync (v0.11.0 -> v0.13.1): + - docs(CHANGELOG): update for v0.13.1 + - feat(ipld): wrap bindnode with panic protection (#368) ([ipfs/go-graphsync#368](https://github.com/ipfs/go-graphsync/pull/368)) + - docs(CHANGELOG): update for v0.13.0 (#366) ([ipfs/go-graphsync#366](https://github.com/ipfs/go-graphsync/pull/366)) + - fix(impl): delete file + - Minimal alternate metadata type support (#365) ([ipfs/go-graphsync#365](https://github.com/ipfs/go-graphsync/pull/365)) + - Fix unixfs fetch (#364) ([ipfs/go-graphsync#364](https://github.com/ipfs/go-graphsync/pull/364)) + - [Feature] UUIDs, protocol versioning, v2 protocol w/ dag-cbor messaging (#332) ([ipfs/go-graphsync#332](https://github.com/ipfs/go-graphsync/pull/332)) + - feat(CHANGELOG): update for v0.12.0 + - Use do not send blocks for pause/resume & prevent processing of blocks on cancelled requests (#333) ([ipfs/go-graphsync#333](https://github.com/ipfs/go-graphsync/pull/333)) + - Support unixfs reification in default linksystem (#329) ([ipfs/go-graphsync#329](https://github.com/ipfs/go-graphsync/pull/329)) + - Don't run hooks on blocks we didn't have (#331) ([ipfs/go-graphsync#331](https://github.com/ipfs/go-graphsync/pull/331)) + - feat(responsemanager): trace full messages via links to responses (#325) ([ipfs/go-graphsync#325](https://github.com/ipfs/go-graphsync/pull/325)) + - chore(requestmanager): rename processResponses internals for consistency (#328) ([ipfs/go-graphsync#328](https://github.com/ipfs/go-graphsync/pull/328)) + - Response message tracing (#327) ([ipfs/go-graphsync#327](https://github.com/ipfs/go-graphsync/pull/327)) + - fix(testutil): fix tracing span collection (#324) ([ipfs/go-graphsync#324](https://github.com/ipfs/go-graphsync/pull/324)) + - docs(CHANGELOG): update for v0.11.5 release + - feat(requestmanager): add tracing for response messages & block processing (#322) ([ipfs/go-graphsync#322](https://github.com/ipfs/go-graphsync/pull/322)) + - ipldutil: simplify state synchronization, add docs (#300) ([ipfs/go-graphsync#300](https://github.com/ipfs/go-graphsync/pull/300)) + - docs(CHANGELOG): update for v0.11.4 release + - Scrub response errors (#320) ([ipfs/go-graphsync#320](https://github.com/ipfs/go-graphsync/pull/320)) + - fix(responsemanager): remove unused maxInProcessRequests parameter (#319) ([ipfs/go-graphsync#319](https://github.com/ipfs/go-graphsync/pull/319)) + - feat(responsemanager): allow ctx augmentation via queued request hook + - make go test with coverpkg=./... + - docs(CHANGELOG): update for v0.11.3 + - Merge tag 'v0.10.9' + - feat: add basic tracing for responses (#291) ([ipfs/go-graphsync#291](https://github.com/ipfs/go-graphsync/pull/291)) + - fix(impl): remove accidental legacy field (#310) ([ipfs/go-graphsync#310](https://github.com/ipfs/go-graphsync/pull/310)) + - docs(CHANGELOG): update for v0.11.2 + - Merge branch 'release/v0.10.8' + - feat(taskqueue): fix race on peer state gather (#303) ([ipfs/go-graphsync#303](https://github.com/ipfs/go-graphsync/pull/303)) + - feat(responsemanager): clarify response completion (#304) ([ipfs/go-graphsync#304](https://github.com/ipfs/go-graphsync/pull/304)) + - docs(CHANGELOG): update for v0.11.1 + - Merge branch 'release/v0.10.7' + - Expose task queue diagnostics (#302) ([ipfs/go-graphsync#302](https://github.com/ipfs/go-graphsync/pull/302)) + - chore: short-circuit unnecessary message processing + - Add a bit of logging (#301) ([ipfs/go-graphsync#301](https://github.com/ipfs/go-graphsync/pull/301)) + - Peer Stats function (#298) ([ipfs/go-graphsync#298](https://github.com/ipfs/go-graphsync/pull/298)) + - fix: use sync.Cond to handle no-task blocking wait (#299) ([ipfs/go-graphsync#299](https://github.com/ipfs/go-graphsync/pull/299)) + - ipldutil: use chooser APIs from dagpb and basicnode (#292) ([ipfs/go-graphsync#292](https://github.com/ipfs/go-graphsync/pull/292)) + - testutil/chaintypes: simplify maintenance of codegen (#294) ([ipfs/go-graphsync#294](https://github.com/ipfs/go-graphsync/pull/294)) + - fix(test): increase 1s timeouts to 2s for slow CI (#289) ([ipfs/go-graphsync#289](https://github.com/ipfs/go-graphsync/pull/289)) + - docs(tests): document tracing test helper utilities + - feat: add basic OT tracing for incoming requests + - fix(responsemanager): make fix more global + - fix(responsemanager): fix flaky tests + - feat: add WorkerTaskQueue#WaitForNoActiveTasks() for tests (#284) ([ipfs/go-graphsync#284](https://github.com/ipfs/go-graphsync/pull/284)) +- github.com/ipfs/go-ipfs-blockstore (v1.1.2 -> v1.2.0): + - v0.2.0 ([ipfs/go-ipfs-blockstore#98](https://github.com/ipfs/go-ipfs-blockstore/pull/98)) + - s/log/logger + - Use ipld.ErrNotFound for NotFound errors +- github.com/ipfs/go-ipfs-cmds (v0.6.0 -> v0.8.1): + - fix(cli/parse): extract dir before name ([ipfs/go-ipfs-cmds#230](https://github.com/ipfs/go-ipfs-cmds/pull/230)) + - Version 0.8.0 ([ipfs/go-ipfs-cmds#228](https://github.com/ipfs/go-ipfs-cmds/pull/228)) + - fix(cli): use NewSliceDirectory for duplicate file paths ([ipfs/go-ipfs-cmds#220](https://github.com/ipfs/go-ipfs-cmds/pull/220)) + - chore: release v0.7.0 ([ipfs/go-ipfs-cmds#227](https://github.com/ipfs/go-ipfs-cmds/pull/227)) + - feat(Command): add status for the helptext ([ipfs/go-ipfs-cmds#225](https://github.com/ipfs/go-ipfs-cmds/pull/225)) + - allow header and set header in client ([ipfs/go-ipfs-cmds#226](https://github.com/ipfs/go-ipfs-cmds/pull/226)) + - sync: update CI config files (#221) ([ipfs/go-ipfs-cmds#221](https://github.com/ipfs/go-ipfs-cmds/pull/221)) + - fix: chanResponseEmitter cancel being ineffective + - add: tests for postrun execution + - fix: postrun's run condition in Execute + - fix: exec deadlock when emitter is not Typer intf + - sync: update CI config files ([ipfs/go-ipfs-cmds#207](https://github.com/ipfs/go-ipfs-cmds/pull/207)) + - fix: preserve windows file paths ([ipfs/go-ipfs-cmds#214](https://github.com/ipfs/go-ipfs-cmds/pull/214)) + - Resolve `staticcheck` issue in prep for unified CI ([ipfs/go-ipfs-cmds#212](https://github.com/ipfs/go-ipfs-cmds/pull/212)) +- github.com/ipfs/go-ipfs-exchange-offline (v0.1.1 -> v0.2.0): + - v0.2.0 + - Improve NotFound error description +- github.com/ipfs/go-ipfs-files (v0.0.9 -> v0.1.1): + - Release v0.1.1 + - fix: add dragonfly build option for filewriter flags + - fix: add freebsd build option for filewriter flags + - Release v0.1.0 + - docs: fix community CONTRIBUTING.md link (#45) ([ipfs/go-ipfs-files#45](https://github.com/ipfs/go-ipfs-files/pull/45)) + - chore(filewriter): cleanup writes (#43) ([ipfs/go-ipfs-files#43](https://github.com/ipfs/go-ipfs-files/pull/43)) + - sync: update CI config files (#44) ([ipfs/go-ipfs-files#44](https://github.com/ipfs/go-ipfs-files/pull/44)) +- github.com/ipfs/go-ipld-format (v0.2.0 -> v0.4.0): + - chore: release version v0.4.0 + - feat: use new more clearer format in ErrNotFound + - chore: bump version to 0.3.1 + - fix: make Undef ErrNotFound string consistent with Def version + - Version 0.3.0 + - ErrNotFound: change error string ([ipfs/go-ipld-format#69](https://github.com/ipfs/go-ipld-format/pull/69)) + - Revert "Revert "Add IsErrNotFound() method"" ([ipfs/go-ipld-format#68](https://github.com/ipfs/go-ipld-format/pull/68)) + - sync: update CI config files (#67) ([ipfs/go-ipld-format#67](https://github.com/ipfs/go-ipld-format/pull/67)) + - ignore statticheck error for EndOfDag ([ipfs/go-ipld-format#62](https://github.com/ipfs/go-ipld-format/pull/62)) + - remove Makefile ([ipfs/go-ipld-format#59](https://github.com/ipfs/go-ipld-format/pull/59)) + - fix staticcheck ([ipfs/go-ipld-format#60](https://github.com/ipfs/go-ipld-format/pull/60)) + - Allowing custom NavigableNode implementations ([ipfs/go-ipld-format#58](https://github.com/ipfs/go-ipld-format/pull/58)) +- github.com/ipfs/go-ipld-legacy (v0.1.0 -> v0.1.1): + - feat(node): add json.Marshaller method ([ipfs/go-ipld-legacy#7](https://github.com/ipfs/go-ipld-legacy/pull/7)) +- github.com/ipfs/go-log/v2 (v2.3.0 -> v2.5.1): + - feat: add logger option to skip a number of stack frames ([ipfs/go-log#132](https://github.com/ipfs/go-log/pull/132)) + - release v2.5.0 (#131) ([ipfs/go-log#131](https://github.com/ipfs/go-log/pull/131)) + - config inspection (#129) ([ipfs/go-log#129](https://github.com/ipfs/go-log/pull/129)) + - release v2.4.0 (#127) ([ipfs/go-log#127](https://github.com/ipfs/go-log/pull/127)) + - sync: update CI config files (#125) ([ipfs/go-log#125](https://github.com/ipfs/go-log/pull/125)) + - fix: cannot call SetPrimaryCore after using a Tee logger ([ipfs/go-log#121](https://github.com/ipfs/go-log/pull/121)) + - Document environment variables ([ipfs/go-log#120](https://github.com/ipfs/go-log/pull/120)) + - sync: update CI config files (#119) ([ipfs/go-log#119](https://github.com/ipfs/go-log/pull/119)) + - Add WithStacktrace untility ([ipfs/go-log#118](https://github.com/ipfs/go-log/pull/118)) + - In addition to StdOut/Err check the outfile for TTYness ([ipfs/go-log#117](https://github.com/ipfs/go-log/pull/117)) +- github.com/ipfs/go-merkledag (v0.5.1 -> v0.6.0): + - v0.6.0 + - Improve ErrNotFound +- github.com/ipfs/go-namesys (v0.4.0 -> v0.5.0): + - Version 0.5.0 + - fix: CIDv1 error with go-libp2p 0.19 (#32) ([ipfs/go-namesys#32](https://github.com/ipfs/go-namesys/pull/32)) + - feat: add tracing (#30) ([ipfs/go-namesys#30](https://github.com/ipfs/go-namesys/pull/30)) + - fix(publisher): fix garbled code output (#28) ([ipfs/go-namesys#28](https://github.com/ipfs/go-namesys/pull/28)) +- github.com/ipfs/go-path (v0.2.1 -> v0.3.0): + - Release v0.3.0 ([ipfs/go-path#55](https://github.com/ipfs/go-path/pull/55)) + - Resolver: convert to interface. ([ipfs/go-path#53](https://github.com/ipfs/go-path/pull/53)) + - Release v0.2.2 (#52) ([ipfs/go-path#52](https://github.com/ipfs/go-path/pull/52)) + - chore: improve error message for invalid ipfs paths ([ipfs/go-path#51](https://github.com/ipfs/go-path/pull/51)) +- github.com/ipfs/go-peertaskqueue (v0.7.0 -> v0.7.1): + - Add topic inspector ([ipfs/go-peertaskqueue#20](https://github.com/ipfs/go-peertaskqueue/pull/20)) +- github.com/ipfs/go-pinning-service-http-client (v0.1.0 -> v0.1.1): + - chore: release v0.1.1 + - fix: error handling while enumerating pins + - sync: update CI config files (#15) ([ipfs/go-pinning-service-http-client#15](https://github.com/ipfs/go-pinning-service-http-client/pull/15)) + - Resolve lint issues prior to CI integration +- github.com/ipfs/go-unixfsnode (v1.1.3 -> v1.4.0): + - 1.4.0 release ([ipfs/go-unixfsnode#29](https://github.com/ipfs/go-unixfsnode/pull/29)) + - Partial file test ([ipfs/go-unixfsnode#26](https://github.com/ipfs/go-unixfsnode/pull/26)) + - Add unixfs to UnixFS path selector tail ([ipfs/go-unixfsnode#28](https://github.com/ipfs/go-unixfsnode/pull/28)) + - release v1.3.0 ([ipfs/go-unixfsnode#25](https://github.com/ipfs/go-unixfsnode/pull/25)) + - add AsLargeBytes support to unixfs files (#24) ([ipfs/go-unixfsnode#24](https://github.com/ipfs/go-unixfsnode/pull/24)) + - fix: add extra test to span the shard/no-shard boundary + - fix: more Tsize fixes, fix HAMT and make it match go-unixfs output + - fix: encode Tsize correctly everywhere (using wraped LinkSystem) + - docs(version): tag 1.2.0 + - Update deps for ADL selectors ([ipfs/go-unixfsnode#20](https://github.com/ipfs/go-unixfsnode/pull/20)) + - add license (#17) ([ipfs/go-unixfsnode#17](https://github.com/ipfs/go-unixfsnode/pull/17)) + - handle empty files (#15) ([ipfs/go-unixfsnode#15](https://github.com/ipfs/go-unixfsnode/pull/15)) + - Add ADL/single-node-view of a full unixFS file. (#14) ([ipfs/go-unixfsnode#14](https://github.com/ipfs/go-unixfsnode/pull/14)) + - sync: update CI config files (#13) ([ipfs/go-unixfsnode#13](https://github.com/ipfs/go-unixfsnode/pull/13)) + - Add builder for unixfs dags (#12) ([ipfs/go-unixfsnode#12](https://github.com/ipfs/go-unixfsnode/pull/12)) +- github.com/ipfs/interface-go-ipfs-core (v0.5.2 -> v0.7.0): + - refactor(block): CIDv1 and BlockPutSettings CidPrefix (#80) ([ipfs/interface-go-ipfs-core#80](https://github.com/ipfs/interface-go-ipfs-core/pull/80)) + - chore: release v0.6.2 + - fix: use IPLD.ErrNotFound instead of string comparison in tests + - fix: document error (#74) ([ipfs/interface-go-ipfs-core#74](https://github.com/ipfs/interface-go-ipfs-core/pull/74)) + - version: release 0.6.1 + - v0.6.0 + - Update tests to use ipld.IsNotFound to check for notfound errors + - sync: update CI config files (#79) ([ipfs/interface-go-ipfs-core#79](https://github.com/ipfs/interface-go-ipfs-core/pull/79)) +- github.com/ipld/go-car/v2 (null -> v2.1.1): + - Update v2 to context datastores (#275) ([ipld/go-car#275](https://github.com/ipld/go-car/pull/275)) + - update context datastore ([ipld/go-car#273](https://github.com/ipld/go-car/pull/273)) + - Traversal-based car creation (#269) ([ipld/go-car#269](https://github.com/ipld/go-car/pull/269)) + - Seek to start before index generation in `ReadOnly` blockstore + - support extraction of unixfs content stored in car files (#263) ([ipld/go-car#263](https://github.com/ipld/go-car/pull/263)) + - Add a barebones readme to the car CLI (#262) ([ipld/go-car#262](https://github.com/ipld/go-car/pull/262)) + - sync: update CI config files (#261) ([ipld/go-car#261](https://github.com/ipld/go-car/pull/261)) + - fix!: use -version=n instead of -v1 for index command + - feat: fix get-dag and add version=1 option + - creation of car from file / directory (#246) ([ipld/go-car#246](https://github.com/ipld/go-car/pull/246)) + - forEach iterates over index in stable order (#258) ([ipld/go-car#258](https://github.com/ipld/go-car/pull/258)) + - Expose selector traversal options for SelectiveCar ([ipld/go-car#251](https://github.com/ipld/go-car/pull/251)) + - Implement API to allow replacing root CIDs in a CARv1 or CARv2 + - blockstore: OpenReadWrite should not modify if it refuses to resume + - clarify the relation between StoreIdentityCIDs and SetFullyIndexed + - Implement options to handle `IDENTITY` CIDs gracefully + - Combine API options for simplicity and logical coherence + - Add test script for car verify (#236) ([ipld/go-car#236](https://github.com/ipld/go-car/pull/236)) + - cmd/car: add first testscript tests + - integrate `car/` cli into `cmd/car` (#233) ([ipld/go-car#233](https://github.com/ipld/go-car/pull/233)) + - Add `car get-dag` command (#232) ([ipld/go-car#232](https://github.com/ipld/go-car/pull/232)) + - Separate CLI to separate module (#231) ([ipld/go-car#231](https://github.com/ipld/go-car/pull/231)) + - add `get block` to car cli (#230) ([ipld/go-car#230](https://github.com/ipld/go-car/pull/230)) + - use file size when loading from v1 car (#229) ([ipld/go-car#229](https://github.com/ipld/go-car/pull/229)) + - add interface describing iteration (#228) ([ipld/go-car#228](https://github.com/ipld/go-car/pull/228)) + - Add `list` and `filter` commands (#227) ([ipld/go-car#227](https://github.com/ipld/go-car/pull/227)) + - Add `car split` command (#226) ([ipld/go-car#226](https://github.com/ipld/go-car/pull/226)) + - Make `MultihashIndexSorted` the default index codec for CARv2 + - Add carve utility for updating the index of a car{v1,v2} file (#219) ([ipld/go-car#219](https://github.com/ipld/go-car/pull/219)) + - Ignore records with `IDENTITY` CID in `IndexSorted` + - Fix index GetAll infinite loop if function always returns `true` + - Expose the ability to iterate over records in `MultihasIndexSorted` + - avoid another alloc per read byte + - avoid allocating on every byte read + - Implement new index type that also includes mutltihash code + - Return `nil` as Index reader when reading indexless CARv2 +- github.com/ipld/go-codec-dagpb (v1.3.2 -> v1.4.0): + - bump to v1.4.0 given that we updated ipld-prime + - add a decode-then-encode roundtrip fuzzer + - 1.3.1 + - fix: use protowire for Links bytes decoding + - delete useless code + - sync: update CI config files (#33) ([ipld/go-codec-dagpb#33](https://github.com/ipld/go-codec-dagpb/pull/33)) +- github.com/ipld/go-ipld-prime (v0.14.2 -> v0.16.0): + - mark v0.16.0 + - node/bindnode: enforce pointer requirement for nullable maps + - Implement WalkTransforming traversal (#376) ([ipld/go-ipld-prime#376](https://github.com/ipld/go-ipld-prime/pull/376)) + - docs(datamodel): add comment to LargeBytesNode + - Add partial-match traversal of large bytes (#375) ([ipld/go-ipld-prime#375](https://github.com/ipld/go-ipld-prime/pull/375)) + - Implement option to start traversals at a path ([ipld/go-ipld-prime#358](https://github.com/ipld/go-ipld-prime/pull/358)) + - add top-level "go value with schema" example + - Support optional `LargeBytesNode` interface (#372) ([ipld/go-ipld-prime#372](https://github.com/ipld/go-ipld-prime/pull/372)) + - node/bindnode: support pointers to datamodel.Node to bind with Any + - fix(bindnode): tuple struct iterator should handle absent fields properly + - node/bindnode: make AssignNode work at the repr level + - node/bindnode: add support for unsigned integers + - node/bindnode: cover even more edge case panics + - node/bindnode: polish some more AsT panics + - schema/dmt: stop using a fake test to generate code ([ipld/go-ipld-prime#356](https://github.com/ipld/go-ipld-prime/pull/356)) + - schema: remove one review note; add another. + - fix: minor EncodedLength fixes, add tests to fully exercise + - feat: add dagcbor.EncodedLength(Node) to calculate length without encoding + - chore: rename Garbage() to Generate() + - fix: minor garbage nits + - fix: Garbage() takes rand parameter, tweak algorithms, improve docs + - feat: add Garbage() Node generator + - node/bindnode: introduce an assembler that always errors + - node/bindnode: polish panics on invalid AssignT calls + - datamodel: don't panic when stringifying an empty KindSet + - node/bindnode: start using ipld.LoadSchema APIs + - selectors: fix for edge case around recursion clauses with an immediate edge. ([ipld/go-ipld-prime#334](https://github.com/ipld/go-ipld-prime/pull/334)) + - node/bindnode: improve support for pointer types + - node/bindnode: subtract all absents in Length at the repr level + - fix(codecs): error when encoding maps whose lengths don't match entry count + - schema: avoid alloc and copy in Struct and Enum methods + - node/bindnode: allow mapping int-repr enums with Go integers + - schema,node/bindnode: add support for Any + - signaling ADLs in selectors (#301) ([ipld/go-ipld-prime#301](https://github.com/ipld/go-ipld-prime/pull/301)) + - node/bindnode: add support for enums + - schema/...: add support for enum int representations + - node/bindnode: allow binding cidlink.Link to links + - Update to context datastores (#312) ([ipld/go-ipld-prime#312](https://github.com/ipld/go-ipld-prime/pull/312)) + - schema: add support for struct tuple reprs + - Allow parsing padding in dag-json bytes fields (#309) ([ipld/go-ipld-prime#309](https://github.com/ipld/go-ipld-prime/pull/309)) +- github.com/ipld/go-ipld-prime/storage/bsadapter (null -> v0.0.0-20211210234204-ce2a1c70cd73): + failed to fetch repo +- github.com/libp2p/go-doh-resolver (v0.3.1 -> v0.4.0): + - Release v0.4.0 (#16) ([libp2p/go-doh-resolver#16](https://github.com/libp2p/go-doh-resolver/pull/16)) + - sync: update CI config files (#14) ([libp2p/go-doh-resolver#14](https://github.com/libp2p/go-doh-resolver/pull/14)) + - Add a max TTL for cached entries ([libp2p/go-doh-resolver#12](https://github.com/libp2p/go-doh-resolver/pull/12)) + - Perform test locally instead of using a live dns resolution ([libp2p/go-doh-resolver#13](https://github.com/libp2p/go-doh-resolver/pull/13)) + - sync: update CI config files (#7) ([libp2p/go-doh-resolver#7](https://github.com/libp2p/go-doh-resolver/pull/7)) + - fix staticcheck ([libp2p/go-doh-resolver#6](https://github.com/libp2p/go-doh-resolver/pull/6)) +- github.com/libp2p/go-libp2p (v0.16.0 -> v0.19.1): + - fix race condition in holepunch service, release v0.19.1 ([libp2p/go-libp2p#1474](https://github.com/libp2p/go-libp2p/pull/1474)) + - release v0.19.0 (#1408) ([libp2p/go-libp2p#1408](https://github.com/libp2p/go-libp2p/pull/1408)) + - Close resource manager when host closes (#1343) ([libp2p/go-libp2p#1343](https://github.com/libp2p/go-libp2p/pull/1343)) + - fix flaky reconnect test (#1406) ([libp2p/go-libp2p#1406](https://github.com/libp2p/go-libp2p/pull/1406)) + - make sure to not oversubscribe to relays (#1404) ([libp2p/go-libp2p#1404](https://github.com/libp2p/go-libp2p/pull/1404)) + - rewrite the reconnect test (#1399) ([libp2p/go-libp2p#1399](https://github.com/libp2p/go-libp2p/pull/1399)) + - don't try to reconnect to already connected relays (#1401) ([libp2p/go-libp2p#1401](https://github.com/libp2p/go-libp2p/pull/1401)) + - reduce flakiness of AutoRelay TestBackoff test (#1400) ([libp2p/go-libp2p#1400](https://github.com/libp2p/go-libp2p/pull/1400)) + - improve AutoRelay v1 handling ([libp2p/go-libp2p#1396](https://github.com/libp2p/go-libp2p/pull/1396)) + - remove note about gx from README (#1385) ([libp2p/go-libp2p#1385](https://github.com/libp2p/go-libp2p/pull/1385)) + - use the vcs information from ReadBuildInfo in Go 1.18 ([libp2p/go-libp2p#1381](https://github.com/libp2p/go-libp2p/pull/1381)) + - fix race condition in AutoRelay candidate handling (#1383) ([libp2p/go-libp2p#1383](https://github.com/libp2p/go-libp2p/pull/1383)) + - implement relay v2 discovery ([libp2p/go-libp2p#1368](https://github.com/libp2p/go-libp2p/pull/1368)) + - fix go vet error in proxy example (#1377) ([libp2p/go-libp2p#1377](https://github.com/libp2p/go-libp2p/pull/1377)) + - Resolve addresses when creating a new stream (#1342) ([libp2p/go-libp2p#1342](https://github.com/libp2p/go-libp2p/pull/1342)) + - remove mplex from the list of default muxers (#1344) ([libp2p/go-libp2p#1344](https://github.com/libp2p/go-libp2p/pull/1344)) + - refactor the holepunching code ([libp2p/go-libp2p#1355](https://github.com/libp2p/go-libp2p/pull/1355)) + - speed up the connmgr tests (#1354) ([libp2p/go-libp2p#1354](https://github.com/libp2p/go-libp2p/pull/1354)) + - update go-libp2p-resource manager, release v0.18.0 (#1361) ([libp2p/go-libp2p#1361](https://github.com/libp2p/go-libp2p/pull/1361)) + - fix flaky BackoffConnector test (#1353) ([libp2p/go-libp2p#1353](https://github.com/libp2p/go-libp2p/pull/1353)) + - release v0.18.0-rc6 (#1350) ([libp2p/go-libp2p#1350](https://github.com/libp2p/go-libp2p/pull/1350)) + - release v0.18.0-rc5 ([libp2p/go-libp2p#1341](https://github.com/libp2p/go-libp2p/pull/1341)) + - update README (#1330) ([libp2p/go-libp2p#1330](https://github.com/libp2p/go-libp2p/pull/1330)) + - fix parsing of IP addresses for zeroconf initialization (#1338) ([libp2p/go-libp2p#1338](https://github.com/libp2p/go-libp2p/pull/1338)) + - fix flaky TestBackoffConnector test (#1328) ([libp2p/go-libp2p#1328](https://github.com/libp2p/go-libp2p/pull/1328)) + - release v0.18.0-rc4 ([libp2p/go-libp2p#1327](https://github.com/libp2p/go-libp2p/pull/1327)) + - fix (and speed up) flaky TestBackoffConnector test (#1316) ([libp2p/go-libp2p#1316](https://github.com/libp2p/go-libp2p/pull/1316)) + - fix flaky TestAutoRelay test (#1322) ([libp2p/go-libp2p#1322](https://github.com/libp2p/go-libp2p/pull/1322)) + - deflake resource manager tests, take 2 ([libp2p/go-libp2p#1318](https://github.com/libp2p/go-libp2p/pull/1318)) + - fix race condition causing TestAutoNATServiceDialError test failure (#1312) ([libp2p/go-libp2p#1312](https://github.com/libp2p/go-libp2p/pull/1312)) + - disable flaky relay example test on CI (#1219) ([libp2p/go-libp2p#1219](https://github.com/libp2p/go-libp2p/pull/1219)) + - fix flaky resource manager tests ([libp2p/go-libp2p#1315](https://github.com/libp2p/go-libp2p/pull/1315)) + - update deps, fixing nil peer scope pointer issues in connection upgrading ([libp2p/go-libp2p#1309](https://github.com/libp2p/go-libp2p/pull/1309)) + - release v0.18.0-rc2 ([libp2p/go-libp2p#1306](https://github.com/libp2p/go-libp2p/pull/1306)) + - add semaphore to control push/delta concurrency ([libp2p/go-libp2p#1305](https://github.com/libp2p/go-libp2p/pull/1305)) + - release v0.18.0-rc1 ([libp2p/go-libp2p#1300](https://github.com/libp2p/go-libp2p/pull/1300)) + - default connection manager ([libp2p/go-libp2p#1299](https://github.com/libp2p/go-libp2p/pull/1299)) + - Basic resource manager integration tests ([libp2p/go-libp2p#1296](https://github.com/libp2p/go-libp2p/pull/1296)) + - use the resource manager ([libp2p/go-libp2p#1275](https://github.com/libp2p/go-libp2p/pull/1275)) + - move the go-libp2p-connmgr here ([libp2p/go-libp2p#1297](https://github.com/libp2p/go-libp2p/pull/1297)) + - move go-libp2p-discovery here ([libp2p/go-libp2p#1291](https://github.com/libp2p/go-libp2p/pull/1291)) + - speed up identify tests ([libp2p/go-libp2p#1294](https://github.com/libp2p/go-libp2p/pull/1294)) + - don't close the connection when opening the identify stream fails ([libp2p/go-libp2p#1293](https://github.com/libp2p/go-libp2p/pull/1293)) + - use the netutil package that was moved to go-libp2p-testing (#1263) ([libp2p/go-libp2p#1263](https://github.com/libp2p/go-libp2p/pull/1263)) + - speed up the autorelay test, fix flaky TestAutoRelay test ([libp2p/go-libp2p#1272](https://github.com/libp2p/go-libp2p/pull/1272)) + - fix flaky TestStreamsStress test (#1288) ([libp2p/go-libp2p#1288](https://github.com/libp2p/go-libp2p/pull/1288)) + - add an option for the swarm dial timeout ([libp2p/go-libp2p#1271](https://github.com/libp2p/go-libp2p/pull/1271)) + - use the transport.Upgrader interface ([libp2p/go-libp2p#1277](https://github.com/libp2p/go-libp2p/pull/1277)) + - fix typo in options.go (#1274) ([libp2p/go-libp2p#1274](https://github.com/libp2p/go-libp2p/pull/1274)) + - remove direct dependency on libp2p/go-addr-util ([libp2p/go-libp2p#1279](https://github.com/libp2p/go-libp2p/pull/1279)) + - fix flaky TestNotifications test ([libp2p/go-libp2p#1278](https://github.com/libp2p/go-libp2p/pull/1278)) + - move go-libp2p-autonat to p2p/host/autonat ([libp2p/go-libp2p#1273](https://github.com/libp2p/go-libp2p/pull/1273)) + - require the expiration field of the circuit v2 Reservation protobuf ([libp2p/go-libp2p#1269](https://github.com/libp2p/go-libp2p/pull/1269)) + - run reconnect test using QUIC ([libp2p/go-libp2p#1268](https://github.com/libp2p/go-libp2p/pull/1268)) + - remove goprocess from the mock package ([libp2p/go-libp2p#1266](https://github.com/libp2p/go-libp2p/pull/1266)) + - release v0.17.0 (#1265) ([libp2p/go-libp2p#1265](https://github.com/libp2p/go-libp2p/pull/1265)) + - use the new network.ConnStats ([libp2p/go-libp2p#1262](https://github.com/libp2p/go-libp2p/pull/1262)) + - move the peerstoremanager to the host ([libp2p/go-libp2p#1258](https://github.com/libp2p/go-libp2p/pull/1258)) + - reduce the default stream protocol negotiation timeout (#1254) ([libp2p/go-libp2p#1254](https://github.com/libp2p/go-libp2p/pull/1254)) + - Doc: QUIC is default when no transports set (#1250) ([libp2p/go-libp2p#1250](https://github.com/libp2p/go-libp2p/pull/1250)) + - exclude web3-bot from mkreleaselog ([libp2p/go-libp2p#1248](https://github.com/libp2p/go-libp2p/pull/1248)) + - identify: also match observed against listening addresses ([libp2p/go-libp2p#1255](https://github.com/libp2p/go-libp2p/pull/1255)) + - make it possible to run the auto relays tests multiple times ([libp2p/go-libp2p#1253](https://github.com/libp2p/go-libp2p/pull/1253)) +- github.com/libp2p/go-libp2p-asn-util (v0.1.0 -> v0.2.0): + - Release 0.2.0 (#21) ([libp2p/go-libp2p-asn-util#21](https://github.com/libp2p/go-libp2p-asn-util/pull/21)) + - perf: replace the ipv6 map by an array of struct (#20) ([libp2p/go-libp2p-asn-util#20](https://github.com/libp2p/go-libp2p-asn-util/pull/20)) + - sync: update CI config files (#18) ([libp2p/go-libp2p-asn-util#18](https://github.com/libp2p/go-libp2p-asn-util/pull/18)) +- github.com/libp2p/go-libp2p-blankhost (v0.2.0 -> v0.3.0): + - add a WithEventBus constructor option ([libp2p/go-libp2p-blankhost#61](https://github.com/libp2p/go-libp2p-blankhost/pull/61)) + - emit the EvtPeerConnectednessChanged event ([libp2p/go-libp2p-blankhost#58](https://github.com/libp2p/go-libp2p-blankhost/pull/58)) + - chore: update go-log to v2 ([libp2p/go-libp2p-blankhost#59](https://github.com/libp2p/go-libp2p-blankhost/pull/59)) + - Remove invalid links ([libp2p/go-libp2p-blankhost#57](https://github.com/libp2p/go-libp2p-blankhost/pull/57)) + - fix go vet ([libp2p/go-libp2p-blankhost#53](https://github.com/libp2p/go-libp2p-blankhost/pull/53)) +- github.com/libp2p/go-libp2p-circuit (v0.4.0 -> v0.6.0): + - release v0.6.0 (#151) ([libp2p/go-libp2p-circuit#151](https://github.com/libp2p/go-libp2p-circuit/pull/151)) + - chore: update go-log to v2 (#147) ([libp2p/go-libp2p-circuit#147](https://github.com/libp2p/go-libp2p-circuit/pull/147)) + - release v0.5.0 (#150) ([libp2p/go-libp2p-circuit#150](https://github.com/libp2p/go-libp2p-circuit/pull/150)) + - use the resource manager ([libp2p/go-libp2p-circuit#148](https://github.com/libp2p/go-libp2p-circuit/pull/148)) + - use the transport.Upgrader interface ([libp2p/go-libp2p-circuit#149](https://github.com/libp2p/go-libp2p-circuit/pull/149)) + - sync: update CI config files (#144) ([libp2p/go-libp2p-circuit#144](https://github.com/libp2p/go-libp2p-circuit/pull/144)) + - ([libp2p/go-libp2p-circuit#143](https://github.com/libp2p/go-libp2p-circuit/pull/143)) + - add a Close method, remove the context from the constructor ([libp2p/go-libp2p-circuit#141](https://github.com/libp2p/go-libp2p-circuit/pull/141)) + - chore: update go-libp2p-core, go-libp2p-swarm ([libp2p/go-libp2p-circuit#140](https://github.com/libp2p/go-libp2p-circuit/pull/140)) + - remove the circuit v2 code ([libp2p/go-libp2p-circuit#139](https://github.com/libp2p/go-libp2p-circuit/pull/139)) + - implement circuit v2 ([libp2p/go-libp2p-circuit#136](https://github.com/libp2p/go-libp2p-circuit/pull/136)) + - remove deprecated types ([libp2p/go-libp2p-circuit#135](https://github.com/libp2p/go-libp2p-circuit/pull/135)) + - fix race condition in TestActiveRelay ([libp2p/go-libp2p-circuit#133](https://github.com/libp2p/go-libp2p-circuit/pull/133)) + - minor staticcheck fixes ([libp2p/go-libp2p-circuit#126](https://github.com/libp2p/go-libp2p-circuit/pull/126)) + - Timeout Stream Read ([libp2p/go-libp2p-circuit#124](https://github.com/libp2p/go-libp2p-circuit/pull/124)) +- github.com/libp2p/go-libp2p-core (v0.11.0 -> v0.15.1): + - release v0.15.1 (#246) ([libp2p/go-libp2p-core#246](https://github.com/libp2p/go-libp2p-core/pull/246)) + - feat: harden encoding/decoding functions against panics (#243) ([libp2p/go-libp2p-core#243](https://github.com/libp2p/go-libp2p-core/pull/243)) + - release v0.15.0 (#242) ([libp2p/go-libp2p-core#242](https://github.com/libp2p/go-libp2p-core/pull/242)) + - sync: update CI config files (#241) ([libp2p/go-libp2p-core#241](https://github.com/libp2p/go-libp2p-core/pull/241)) + - fix: switch to go-multicodec mappings (#240) ([libp2p/go-libp2p-core#240](https://github.com/libp2p/go-libp2p-core/pull/240)) + - chore: add `String()` method to `IDSlice` type (#238) ([libp2p/go-libp2p-core#238](https://github.com/libp2p/go-libp2p-core/pull/238)) + - release v0.14.0 (#235) ([libp2p/go-libp2p-core#235](https://github.com/libp2p/go-libp2p-core/pull/235)) + - Network Resource Manager interface (#229) ([libp2p/go-libp2p-core#229](https://github.com/libp2p/go-libp2p-core/pull/229)) + - introduce a transport.Upgrader interface (#232) ([libp2p/go-libp2p-core#232](https://github.com/libp2p/go-libp2p-core/pull/232)) + - remove the transport.AcceptTimeout (#231) ([libp2p/go-libp2p-core#231](https://github.com/libp2p/go-libp2p-core/pull/231)) + - remove the DialTimeout (#230) ([libp2p/go-libp2p-core#230](https://github.com/libp2p/go-libp2p-core/pull/230)) + - remove duplicate io.Closer on Network interface (#228) ([libp2p/go-libp2p-core#228](https://github.com/libp2p/go-libp2p-core/pull/228)) + - release v0.13.0 (#227) ([libp2p/go-libp2p-core#227](https://github.com/libp2p/go-libp2p-core/pull/227)) + - rename network.Stat to Stats, introduce ConnStats (#226) ([libp2p/go-libp2p-core#226](https://github.com/libp2p/go-libp2p-core/pull/226)) + - release v0.12.0 (#223) ([libp2p/go-libp2p-core#223](https://github.com/libp2p/go-libp2p-core/pull/223)) + - generate ecdsa public key from an input public key (#219) ([libp2p/go-libp2p-core#219](https://github.com/libp2p/go-libp2p-core/pull/219)) + - add RemovePeer method to PeerMetadata, Metrics, ProtoBook and Keybook (#218) ([libp2p/go-libp2p-core#218](https://github.com/libp2p/go-libp2p-core/pull/218)) +- github.com/libp2p/go-libp2p-mplex (v0.4.1 -> v0.7.0): + - release v0.7.0 (#36) ([libp2p/go-libp2p-mplex#36](https://github.com/libp2p/go-libp2p-mplex/pull/36)) + - release v0.6.0 (#32) ([libp2p/go-libp2p-mplex#32](https://github.com/libp2p/go-libp2p-mplex/pull/32)) + - update mplex (#31) ([libp2p/go-libp2p-mplex#31](https://github.com/libp2p/go-libp2p-mplex/pull/31)) + - release v0.5.0 (#30) ([libp2p/go-libp2p-mplex#30](https://github.com/libp2p/go-libp2p-mplex/pull/30)) + - implement the new network.MuxedConn interface (#29) ([libp2p/go-libp2p-mplex#29](https://github.com/libp2p/go-libp2p-mplex/pull/29)) + - sync: update CI config files (#28) ([libp2p/go-libp2p-mplex#28](https://github.com/libp2p/go-libp2p-mplex/pull/28)) + - remove Makefile ([libp2p/go-libp2p-mplex#25](https://github.com/libp2p/go-libp2p-mplex/pull/25)) +- github.com/libp2p/go-libp2p-noise (v0.3.0 -> v0.4.0): + - release v0.4.0 (#112) ([libp2p/go-libp2p-noise#112](https://github.com/libp2p/go-libp2p-noise/pull/112)) + - catch panics during the handshake (#111) ([libp2p/go-libp2p-noise#111](https://github.com/libp2p/go-libp2p-noise/pull/111)) + - sync: update CI config files (#106) ([libp2p/go-libp2p-noise#106](https://github.com/libp2p/go-libp2p-noise/pull/106)) + - update README to reflect that Noise is enabled by default ([libp2p/go-libp2p-noise#101](https://github.com/libp2p/go-libp2p-noise/pull/101)) +- github.com/libp2p/go-libp2p-peerstore (v0.4.0 -> v0.6.0): + - release v0.6.0 ([libp2p/go-libp2p-peerstore#189](https://github.com/libp2p/go-libp2p-peerstore/pull/189)) + - remove the pstoremanager (will be moved to the Host) ([libp2p/go-libp2p-peerstore#188](https://github.com/libp2p/go-libp2p-peerstore/pull/188)) + - release v0.5.0 (#187) ([libp2p/go-libp2p-peerstore#187](https://github.com/libp2p/go-libp2p-peerstore/pull/187)) + - remove metadata interning ([libp2p/go-libp2p-peerstore#185](https://github.com/libp2p/go-libp2p-peerstore/pull/185)) + - when passed an event bus, automatically clean up disconnected peers ([libp2p/go-libp2p-peerstore#184](https://github.com/libp2p/go-libp2p-peerstore/pull/184)) + - implement the RemovePeer method ([libp2p/go-libp2p-peerstore#174](https://github.com/libp2p/go-libp2p-peerstore/pull/174)) + - chore: update go-log to v2 (#179) ([libp2p/go-libp2p-peerstore#179](https://github.com/libp2p/go-libp2p-peerstore/pull/179)) +- github.com/libp2p/go-libp2p-pubsub (v0.6.0 -> v0.6.1): + - add tests for clearing the peerPromises map + - properly clear the peerPromises map + - more info + - add to MinTopicSize godoc re topic size +- github.com/libp2p/go-libp2p-quic-transport (v0.15.0 -> v0.17.0): + - release v0.17.0 (#269) ([libp2p/go-libp2p-quic-transport#269](https://github.com/libp2p/go-libp2p-quic-transport/pull/269)) + - update quic-go to v0.27.0 (#264) ([libp2p/go-libp2p-quic-transport#264](https://github.com/libp2p/go-libp2p-quic-transport/pull/264)) + - release v0.16.1 (#261) ([libp2p/go-libp2p-quic-transport#261](https://github.com/libp2p/go-libp2p-quic-transport/pull/261)) + - Prevent data race in allowWindowIncrease (#259) ([libp2p/go-libp2p-quic-transport#259](https://github.com/libp2p/go-libp2p-quic-transport/pull/259)) + - release v0.16.0 (#258) ([libp2p/go-libp2p-quic-transport#258](https://github.com/libp2p/go-libp2p-quic-transport/pull/258)) + - use the Resource Manager ([libp2p/go-libp2p-quic-transport#249](https://github.com/libp2p/go-libp2p-quic-transport/pull/249)) + - don't start a Go routine for every connection dialed ([libp2p/go-libp2p-quic-transport#252](https://github.com/libp2p/go-libp2p-quic-transport/pull/252)) + - migrate to standard Go tests, stop using Ginkgo ([libp2p/go-libp2p-quic-transport#250](https://github.com/libp2p/go-libp2p-quic-transport/pull/250)) + - chore: remove Codecov config (#251) ([libp2p/go-libp2p-quic-transport#251](https://github.com/libp2p/go-libp2p-quic-transport/pull/251)) + - reduce the maximum number of incoming streams to 256 (#243) ([libp2p/go-libp2p-quic-transport#243](https://github.com/libp2p/go-libp2p-quic-transport/pull/243)) + - chore: update go-log to v2 (#242) ([libp2p/go-libp2p-quic-transport#242](https://github.com/libp2p/go-libp2p-quic-transport/pull/242)) +- github.com/libp2p/go-libp2p-swarm (v0.8.0 -> v0.10.2): + - bump version to v0.10.2 ([libp2p/go-libp2p-swarm#316](https://github.com/libp2p/go-libp2p-swarm/pull/316)) + - Refactor dial worker loop into an object and fix bug ([libp2p/go-libp2p-swarm#315](https://github.com/libp2p/go-libp2p-swarm/pull/315)) + - release v0.10.1 ([libp2p/go-libp2p-swarm#313](https://github.com/libp2p/go-libp2p-swarm/pull/313)) + - release the stream scope if the conn fails to open a new stream ([libp2p/go-libp2p-swarm#312](https://github.com/libp2p/go-libp2p-swarm/pull/312)) + - release v0.10.0 (#311) ([libp2p/go-libp2p-swarm#311](https://github.com/libp2p/go-libp2p-swarm/pull/311)) + - add support for the resource manager ([libp2p/go-libp2p-swarm#308](https://github.com/libp2p/go-libp2p-swarm/pull/308)) + - use the transport.Upgrader interface ([libp2p/go-libp2p-swarm#309](https://github.com/libp2p/go-libp2p-swarm/pull/309)) + - remove dependency on go-addr-util ([libp2p/go-libp2p-swarm#300](https://github.com/libp2p/go-libp2p-swarm/pull/300)) + - stop using transport.DialTimeout in tests (#307) ([libp2p/go-libp2p-swarm#307](https://github.com/libp2p/go-libp2p-swarm/pull/307)) + - increment active dial counter in dial worker loop ([libp2p/go-libp2p-swarm#305](https://github.com/libp2p/go-libp2p-swarm/pull/305)) + - speed up the dial tests ([libp2p/go-libp2p-swarm#301](https://github.com/libp2p/go-libp2p-swarm/pull/301)) + - stop using the deprecated libp2p/go-maddr-filter ([libp2p/go-libp2p-swarm#303](https://github.com/libp2p/go-libp2p-swarm/pull/303)) + - add constructor options for timeout, stop using transport.DialTimeout ([libp2p/go-libp2p-swarm#302](https://github.com/libp2p/go-libp2p-swarm/pull/302)) + - release v0.9.0 (#299) ([libp2p/go-libp2p-swarm#299](https://github.com/libp2p/go-libp2p-swarm/pull/299)) + - count the number of streams on a connection for the stats ([libp2p/go-libp2p-swarm#298](https://github.com/libp2p/go-libp2p-swarm/pull/298)) + - chore: update go-log to v2 (#294) ([libp2p/go-libp2p-swarm#294](https://github.com/libp2p/go-libp2p-swarm/pull/294)) +- github.com/libp2p/go-libp2p-testing (v0.5.0 -> v0.9.2): + - release v0.9.2 (#56) ([libp2p/go-libp2p-testing#56](https://github.com/libp2p/go-libp2p-testing/pull/56)) + - fix memory allocation check in SubtestStreamReset (#55) ([libp2p/go-libp2p-testing#55](https://github.com/libp2p/go-libp2p-testing/pull/55)) + - release v0.9.1 (#54) ([libp2p/go-libp2p-testing#54](https://github.com/libp2p/go-libp2p-testing/pull/54)) + - remove stray debug statements for memory allocations + - release v0.9.0 (#53) ([libp2p/go-libp2p-testing#53](https://github.com/libp2p/go-libp2p-testing/pull/53)) + - add tests for memory management ([libp2p/go-libp2p-testing#52](https://github.com/libp2p/go-libp2p-testing/pull/52)) + - release v0.8.0 (#50) ([libp2p/go-libp2p-testing#50](https://github.com/libp2p/go-libp2p-testing/pull/50)) + - use io.ReadFull in muxer test, use require.Equal to compare buffers (#49) ([libp2p/go-libp2p-testing#49](https://github.com/libp2p/go-libp2p-testing/pull/49)) + - release v0.7.0 (#47) ([libp2p/go-libp2p-testing#47](https://github.com/libp2p/go-libp2p-testing/pull/47)) + - add mocks for the resource manager ([libp2p/go-libp2p-testing#46](https://github.com/libp2p/go-libp2p-testing/pull/46)) + - merge libp2p/go-libp2p-netutil into this repo ([libp2p/go-libp2p-testing#45](https://github.com/libp2p/go-libp2p-testing/pull/45)) + - reduce the number of connections in the stream muxer stress test (#44) ([libp2p/go-libp2p-testing#44](https://github.com/libp2p/go-libp2p-testing/pull/44)) + - release v0.6.0 (#42) ([libp2p/go-libp2p-testing#42](https://github.com/libp2p/go-libp2p-testing/pull/42)) + - expose a map, not a slice, of muxer tests (#41) ([libp2p/go-libp2p-testing#41](https://github.com/libp2p/go-libp2p-testing/pull/41)) + - sync: update CI config files (#40) ([libp2p/go-libp2p-testing#40](https://github.com/libp2p/go-libp2p-testing/pull/40)) +- github.com/libp2p/go-libp2p-tls (v0.3.1 -> v0.4.1): + - release v0.4.1 (#112) ([libp2p/go-libp2p-tls#112](https://github.com/libp2p/go-libp2p-tls/pull/112)) + - feat: catch panics in TLS negotiation ([libp2p/go-libp2p-tls#111](https://github.com/libp2p/go-libp2p-tls/pull/111)) + - release v0.4.0 (#110) ([libp2p/go-libp2p-tls#110](https://github.com/libp2p/go-libp2p-tls/pull/110)) + - use tls.Conn.HandshakeContext instead of tls.Conn.Handshake (#106) ([libp2p/go-libp2p-tls#106](https://github.com/libp2p/go-libp2p-tls/pull/106)) + - remove paragraph about Go modules from README (#104) ([libp2p/go-libp2p-tls#104](https://github.com/libp2p/go-libp2p-tls/pull/104)) + - migrate to standard Go tests, stop using Ginkgo ([libp2p/go-libp2p-tls#105](https://github.com/libp2p/go-libp2p-tls/pull/105)) + - chore: remove Codecov config (#103) ([libp2p/go-libp2p-tls#103](https://github.com/libp2p/go-libp2p-tls/pull/103)) +- github.com/libp2p/go-libp2p-transport-upgrader (v0.5.0 -> v0.7.1): + - release v0.7.1 ([libp2p/go-libp2p-transport-upgrader#105](https://github.com/libp2p/go-libp2p-transport-upgrader/pull/105)) + - Fix nil peer scope issues ([libp2p/go-libp2p-transport-upgrader#104](https://github.com/libp2p/go-libp2p-transport-upgrader/pull/104)) + - release v0.7.0 (#103) ([libp2p/go-libp2p-transport-upgrader#103](https://github.com/libp2p/go-libp2p-transport-upgrader/pull/103)) + - use the Resource Manager ([libp2p/go-libp2p-transport-upgrader#99](https://github.com/libp2p/go-libp2p-transport-upgrader/pull/99)) + - rename the package to upgrader ([libp2p/go-libp2p-transport-upgrader#101](https://github.com/libp2p/go-libp2p-transport-upgrader/pull/101)) + - use the new transport.Upgrader interface ([libp2p/go-libp2p-transport-upgrader#100](https://github.com/libp2p/go-libp2p-transport-upgrader/pull/100)) + - reset the temporary error catcher delay after successful accept ([libp2p/go-libp2p-transport-upgrader#97](https://github.com/libp2p/go-libp2p-transport-upgrader/pull/97)) + - make the accept timeout configurable, stop using transport.AcceptTimeout ([libp2p/go-libp2p-transport-upgrader#98](https://github.com/libp2p/go-libp2p-transport-upgrader/pull/98)) + - release v0.6.0 (#95) ([libp2p/go-libp2p-transport-upgrader#95](https://github.com/libp2p/go-libp2p-transport-upgrader/pull/95)) + - remove note about go.mod and Go 1.11 in README (#94) ([libp2p/go-libp2p-transport-upgrader#94](https://github.com/libp2p/go-libp2p-transport-upgrader/pull/94)) + - fix flaky TestAcceptQueueBacklogged test ([libp2p/go-libp2p-transport-upgrader#96](https://github.com/libp2p/go-libp2p-transport-upgrader/pull/96)) + - chore: remove Codecov config (#93) ([libp2p/go-libp2p-transport-upgrader#93](https://github.com/libp2p/go-libp2p-transport-upgrader/pull/93)) + - use the new network.ConnStats ([libp2p/go-libp2p-transport-upgrader#92](https://github.com/libp2p/go-libp2p-transport-upgrader/pull/92)) + - sync: update CI config files (#89) ([libp2p/go-libp2p-transport-upgrader#89](https://github.com/libp2p/go-libp2p-transport-upgrader/pull/89)) + - chore: update go-log ([libp2p/go-libp2p-transport-upgrader#88](https://github.com/libp2p/go-libp2p-transport-upgrader/pull/88)) +- github.com/libp2p/go-libp2p-yamux (v0.6.0 -> v0.9.1): + - release v0.9.1 (#55) ([libp2p/go-libp2p-yamux#55](https://github.com/libp2p/go-libp2p-yamux/pull/55)) + - release v0.9.0 (#53) ([libp2p/go-libp2p-yamux#53](https://github.com/libp2p/go-libp2p-yamux/pull/53)) + - release v0.8.2 (#50) ([libp2p/go-libp2p-yamux#50](https://github.com/libp2p/go-libp2p-yamux/pull/50)) + - disable the incoming streams limit (#49) ([libp2p/go-libp2p-yamux#49](https://github.com/libp2p/go-libp2p-yamux/pull/49)) + - Release v0.8.1 ([libp2p/go-libp2p-yamux#48](https://github.com/libp2p/go-libp2p-yamux/pull/48)) + - release v0.8.0 (#47) ([libp2p/go-libp2p-yamux#47](https://github.com/libp2p/go-libp2p-yamux/pull/47)) + - pass the PeerScope to yamux (satifiying its MemoryManger interface) (#46) ([libp2p/go-libp2p-yamux#46](https://github.com/libp2p/go-libp2p-yamux/pull/46)) + - release v0.7.0 (#43) ([libp2p/go-libp2p-yamux#43](https://github.com/libp2p/go-libp2p-yamux/pull/43)) + - sync: update CI config files (#42) ([libp2p/go-libp2p-yamux#42](https://github.com/libp2p/go-libp2p-yamux/pull/42)) + - reduce the number of max incoming stream to 256 ([libp2p/go-libp2p-yamux#41](https://github.com/libp2p/go-libp2p-yamux/pull/41)) +- github.com/libp2p/go-mplex (v0.3.0 -> v0.7.0): + - release v0.7.0 (#112) ([libp2p/go-mplex#112](https://github.com/libp2p/go-mplex/pull/112)) + - catch panics in handleIncoming and handleOutgoing (#109) ([libp2p/go-mplex#109](https://github.com/libp2p/go-mplex/pull/109)) + - remove benchmark tests (#111) ([libp2p/go-mplex#111](https://github.com/libp2p/go-mplex/pull/111)) + - release v0.6.0 (#105) ([libp2p/go-mplex#105](https://github.com/libp2p/go-mplex/pull/105)) + - fix incorrect reset of timer fired variable (#104) ([libp2p/go-mplex#104](https://github.com/libp2p/go-mplex/pull/104)) + - Mplex salvage operations, part II (#102) ([libp2p/go-mplex#102](https://github.com/libp2p/go-mplex/pull/102)) + - release v0.5.0 (#100) ([libp2p/go-mplex#100](https://github.com/libp2p/go-mplex/pull/100)) + - Salvage mplex in the age of resource management (#99) ([libp2p/go-mplex#99](https://github.com/libp2p/go-mplex/pull/99)) + - release v0.4.0 (#97) ([libp2p/go-mplex#97](https://github.com/libp2p/go-mplex/pull/97)) + - add a MemoryManager interface to control memory allocations ([libp2p/go-mplex#96](https://github.com/libp2p/go-mplex/pull/96)) + - sync: update CI config files (#93) ([libp2p/go-mplex#93](https://github.com/libp2p/go-mplex/pull/93)) + - chore: update go-log to v2 ([libp2p/go-mplex#92](https://github.com/libp2p/go-mplex/pull/92)) + - chore: remove Codecov config ([libp2p/go-mplex#91](https://github.com/libp2p/go-mplex/pull/91)) + - sync: update CI config files (#90) ([libp2p/go-mplex#90](https://github.com/libp2p/go-mplex/pull/90)) + - multiplex: add (*Multiplex).CloseChan ([libp2p/go-mplex#89](https://github.com/libp2p/go-mplex/pull/89)) + - add a Go Reference badge to the README ([libp2p/go-mplex#88](https://github.com/libp2p/go-mplex/pull/88)) + - sync: update CI config files ([libp2p/go-mplex#85](https://github.com/libp2p/go-mplex/pull/85)) + - Fixup tests & vet ([libp2p/go-mplex#84](https://github.com/libp2p/go-mplex/pull/84)) + - Bump lodash from 4.17.19 to 4.17.21 in /interop/js ([libp2p/go-mplex#83](https://github.com/libp2p/go-mplex/pull/83)) +- github.com/libp2p/go-msgio (v0.1.0 -> v0.2.0): + - release v0.2.0 (#34) ([libp2p/go-msgio#34](https://github.com/libp2p/go-msgio/pull/34)) + - print recovered panics to stderr (#33) ([libp2p/go-msgio#33](https://github.com/libp2p/go-msgio/pull/33)) + - catch panics when reading / writing protobuf messages (#31) ([libp2p/go-msgio#31](https://github.com/libp2p/go-msgio/pull/31)) + - remove outdated section about channels from README (#32) ([libp2p/go-msgio#32](https://github.com/libp2p/go-msgio/pull/32)) + - sync: update CI config files (#28) ([libp2p/go-msgio#28](https://github.com/libp2p/go-msgio/pull/28)) +- github.com/libp2p/go-netroute (v0.1.6 -> v0.2.0): + - release v0.2.0 (#21) ([libp2p/go-netroute#21](https://github.com/libp2p/go-netroute/pull/21)) + - move some functions from go-sockaddr here, remove go-sockaddr dependency ([libp2p/go-netroute#22](https://github.com/libp2p/go-netroute/pull/22)) + - ignore the error on the RouteMessage on Darwin ([libp2p/go-netroute#20](https://github.com/libp2p/go-netroute/pull/20)) + - sync: update CI config files (#19) ([libp2p/go-netroute#19](https://github.com/libp2p/go-netroute/pull/19)) + - sync: update CI config files (#18) ([libp2p/go-netroute#18](https://github.com/libp2p/go-netroute/pull/18)) + - skip loopback addr as indication of v6 routes ([libp2p/go-netroute#17](https://github.com/libp2p/go-netroute/pull/17)) + - fix staticcheck lint issues ([libp2p/go-netroute#15](https://github.com/libp2p/go-netroute/pull/15)) +- github.com/libp2p/go-stream-muxer-multistream (v0.3.0 -> v0.4.0): + - release v0.4.0 (#23) ([libp2p/go-stream-muxer-multistream#23](https://github.com/libp2p/go-stream-muxer-multistream/pull/23)) + - implement the new Multiplexer.NewConn interface ([libp2p/go-stream-muxer-multistream#22](https://github.com/libp2p/go-stream-muxer-multistream/pull/22)) + - sync: update CI config files (#19) ([libp2p/go-stream-muxer-multistream#19](https://github.com/libp2p/go-stream-muxer-multistream/pull/19)) +- github.com/libp2p/go-tcp-transport (v0.4.0 -> v0.5.1): + - release v0.5.1 (#116) ([libp2p/go-tcp-transport#116](https://github.com/libp2p/go-tcp-transport/pull/116)) + - fix: drop raw EINVAL (from keepalives) errors as well (#115) ([libp2p/go-tcp-transport#115](https://github.com/libp2p/go-tcp-transport/pull/115)) + - release v0.5.0 (#114) ([libp2p/go-tcp-transport#114](https://github.com/libp2p/go-tcp-transport/pull/114)) + - use the ResourceManager ([libp2p/go-tcp-transport#110](https://github.com/libp2p/go-tcp-transport/pull/110)) + - use the transport.Upgrader interface ([libp2p/go-tcp-transport#111](https://github.com/libp2p/go-tcp-transport/pull/111)) + - describe how to use options in README ([libp2p/go-tcp-transport#105](https://github.com/libp2p/go-tcp-transport/pull/105)) +- github.com/libp2p/go-ws-transport (v0.5.0 -> v0.6.0): + - release v0.6.0 (#113) ([libp2p/go-ws-transport#113](https://github.com/libp2p/go-ws-transport/pull/113)) + - use the resource manager ([libp2p/go-ws-transport#109](https://github.com/libp2p/go-ws-transport/pull/109)) + - chore: remove Codecov config (#112) ([libp2p/go-ws-transport#112](https://github.com/libp2p/go-ws-transport/pull/112)) + - remove contexts from libp2p constructors in README (#111) ([libp2p/go-ws-transport#111](https://github.com/libp2p/go-ws-transport/pull/111)) + - use the transport.Upgrader interface ([libp2p/go-ws-transport#110](https://github.com/libp2p/go-ws-transport/pull/110)) + - sync: update CI config files (#108) ([libp2p/go-ws-transport#108](https://github.com/libp2p/go-ws-transport/pull/108)) + - sync: update CI config files (#106) ([libp2p/go-ws-transport#106](https://github.com/libp2p/go-ws-transport/pull/106)) +- github.com/libp2p/go-yamux/v3 (null -> v3.1.1): + - release v3.1.1 (#88) ([libp2p/go-yamux#88](https://github.com/libp2p/go-yamux/pull/88)) + - feat: catch panics in yamux send/receive loops ([libp2p/go-yamux#86](https://github.com/libp2p/go-yamux/pull/86)) + - release v3.1.0 (#83) ([libp2p/go-yamux#83](https://github.com/libp2p/go-yamux/pull/83)) + - fix flaky TestPing test on Windows (#84) ([libp2p/go-yamux#84](https://github.com/libp2p/go-yamux/pull/84)) + - correctly release memory when the connection is closed (#81) ([libp2p/go-yamux#81](https://github.com/libp2p/go-yamux/pull/81)) + - release v3.0.2 ([libp2p/go-yamux#78](https://github.com/libp2p/go-yamux/pull/78)) + - fix memory accounting for window updates ([libp2p/go-yamux#77](https://github.com/libp2p/go-yamux/pull/77)) + - release v3.0.1 (#76) ([libp2p/go-yamux#76](https://github.com/libp2p/go-yamux/pull/76)) + - release v3.0.0 (#74) ([libp2p/go-yamux#74](https://github.com/libp2p/go-yamux/pull/74)) + - add a MemoryManager ([libp2p/go-yamux#69](https://github.com/libp2p/go-yamux/pull/69)) + - fix: ensure that pings don't get stuck behind writes ([libp2p/go-yamux#71](https://github.com/libp2p/go-yamux/pull/71)) + - sync: update CI config files (#68) ([libp2p/go-yamux#68](https://github.com/libp2p/go-yamux/pull/68)) + - limit the number of concurrent incoming streams ([libp2p/go-yamux#66](https://github.com/libp2p/go-yamux/pull/66)) + - drastically reduce allocations in ring buffer implementation (#64) ([libp2p/go-yamux#64](https://github.com/libp2p/go-yamux/pull/64)) +- github.com/lucas-clemente/quic-go (v0.24.0 -> v0.27.0): + - stop using the deprecated net.Error.Temporary, update golangci-lint to v1.45.2 ([lucas-clemente/quic-go#3367](https://github.com/lucas-clemente/quic-go/pull/3367)) + - add support for serializing Extended CONNECT requests (#3360) ([lucas-clemente/quic-go#3360](https://github.com/lucas-clemente/quic-go/pull/3360)) + - improve the error thrown when building with an unsupported Go version ([lucas-clemente/quic-go#3364](https://github.com/lucas-clemente/quic-go/pull/3364)) + - remove nextdns from list of projects using quic-go (#3363) ([lucas-clemente/quic-go#3363](https://github.com/lucas-clemente/quic-go/pull/3363)) + - rename the Session to Connection ([lucas-clemente/quic-go#3361](https://github.com/lucas-clemente/quic-go/pull/3361)) + - respect the request context when dialing ([lucas-clemente/quic-go#3359](https://github.com/lucas-clemente/quic-go/pull/3359)) + - update HTTP/3 Datagram to draft-ietf-masque-h3-datagram-07 (#3355) ([lucas-clemente/quic-go#3355](https://github.com/lucas-clemente/quic-go/pull/3355)) + - add support for the Extended CONNECT method (#3357) ([lucas-clemente/quic-go#3357](https://github.com/lucas-clemente/quic-go/pull/3357)) + - remove the SkipSchemeCheck RoundTripOpt (#3353) ([lucas-clemente/quic-go#3353](https://github.com/lucas-clemente/quic-go/pull/3353)) + - remove parser logic for HTTP/3 DUPLICATE_PUSH frame (#3356) ([lucas-clemente/quic-go#3356](https://github.com/lucas-clemente/quic-go/pull/3356)) + - improve code coverage of random number generator test (#3358) ([lucas-clemente/quic-go#3358](https://github.com/lucas-clemente/quic-go/pull/3358)) + - advertise multiple listeners via Alt-Svc and improve perf of SetQuicHeaders (#3352) ([lucas-clemente/quic-go#3352](https://github.com/lucas-clemente/quic-go/pull/3352)) + - avoid recursion when skipping unknown HTTP/3 frames (#3354) ([lucas-clemente/quic-go#3354](https://github.com/lucas-clemente/quic-go/pull/3354)) + - Implement http3.Server.ServeListener (#3349) ([lucas-clemente/quic-go#3349](https://github.com/lucas-clemente/quic-go/pull/3349)) + - update for Go 1.18 ([lucas-clemente/quic-go#3345](https://github.com/lucas-clemente/quic-go/pull/3345)) + - don't print a receive buffer warning for closed connections (#3346) ([lucas-clemente/quic-go#3346](https://github.com/lucas-clemente/quic-go/pull/3346)) + - move set DF implementation to separate files & avoid the need for OOBCapablePacketConn (#3334) ([lucas-clemente/quic-go#3334](https://github.com/lucas-clemente/quic-go/pull/3334)) + - add env to disable the receive buffer warning (#3339) ([lucas-clemente/quic-go#3339](https://github.com/lucas-clemente/quic-go/pull/3339)) + - fix typo (#3333) ([lucas-clemente/quic-go#3333](https://github.com/lucas-clemente/quic-go/pull/3333)) + - sendQueue: ignore "datagram too large" error (#3328) ([lucas-clemente/quic-go#3328](https://github.com/lucas-clemente/quic-go/pull/3328)) + - add OONI Probe to list of projects in README (#3324) ([lucas-clemente/quic-go#3324](https://github.com/lucas-clemente/quic-go/pull/3324)) + - remove build status badges from README (#3325) ([lucas-clemente/quic-go#3325](https://github.com/lucas-clemente/quic-go/pull/3325)) + - add a AllowConnectionWindowIncrease config option ([lucas-clemente/quic-go#3317](https://github.com/lucas-clemente/quic-go/pull/3317)) + - Update README.md (#3315) ([lucas-clemente/quic-go#3315](https://github.com/lucas-clemente/quic-go/pull/3315)) + - fix some typos in documentation and tests + - remove unneeded calls to goimports when generating mocks ([lucas-clemente/quic-go#3313](https://github.com/lucas-clemente/quic-go/pull/3313)) + - fix comment about congestionWindow value (#3310) ([lucas-clemente/quic-go#3310](https://github.com/lucas-clemente/quic-go/pull/3310)) + - fix typo *connections (#3309) ([lucas-clemente/quic-go#3309](https://github.com/lucas-clemente/quic-go/pull/3309)) + - add support for Go 1.18 ([lucas-clemente/quic-go#3298](https://github.com/lucas-clemente/quic-go/pull/3298)) +- github.com/multiformats/go-base32 (v0.0.3 -> v0.0.4): + - optimize encode ([multiformats/go-base32#1](https://github.com/multiformats/go-base32/pull/1)) + - Fix `staticcheck` issue +- github.com/multiformats/go-multiaddr (v0.4.1 -> v0.5.0): + - release v0.5.0 (#171) ([multiformats/go-multiaddr#171](https://github.com/multiformats/go-multiaddr/pull/171)) + - remove wrong (and redundant) IsIpv6LinkLocal ([multiformats/go-multiaddr#170](https://github.com/multiformats/go-multiaddr/pull/170)) + - move ResolveUnspecifiedAddress(es) and FilterAddrs here from libp2p/go-addr-util ([multiformats/go-multiaddr#168](https://github.com/multiformats/go-multiaddr/pull/168)) + - sync: update CI config files (#167) ([multiformats/go-multiaddr#167](https://github.com/multiformats/go-multiaddr/pull/167)) +- github.com/multiformats/go-multicodec (v0.3.0 -> v0.4.1): + - Version v0.4.1 ([multiformats/go-multicodec#64](https://github.com/multiformats/go-multicodec/pull/64)) + - update table with new codecs ([multiformats/go-multicodec#63](https://github.com/multiformats/go-multicodec/pull/63)) + - bump version to v0.4.0 + - sync: update CI config files (#60) ([multiformats/go-multicodec#60](https://github.com/multiformats/go-multicodec/pull/60)) + - add Code.Tag method + - add the KnownCodes API + - use "go run pkg@version" assuming Go 1.17 or later + - update submodule and re-generate + - update to newer multicodec table ([multiformats/go-multicodec#57](https://github.com/multiformats/go-multicodec/pull/57)) + - Update `multicodec` submodule to `1bcdc08` for CARv2 index codec +- github.com/multiformats/go-multistream (v0.2.2 -> v0.3.0): + - release v0.3.0 (#82) ([multiformats/go-multistream#82](https://github.com/multiformats/go-multistream/pull/82)) + - catch panics (#81) ([multiformats/go-multistream#81](https://github.com/multiformats/go-multistream/pull/81)) + - sync: update CI config files (#78) ([multiformats/go-multistream#78](https://github.com/multiformats/go-multistream/pull/78)) + - reduce the maximum read buffer size from 64 to 1 kB ([multiformats/go-multistream#77](https://github.com/multiformats/go-multistream/pull/77)) + - remove unused ls command ([multiformats/go-multistream#76](https://github.com/multiformats/go-multistream/pull/76)) + - chore: remove empty file cases.md ([multiformats/go-multistream#75](https://github.com/multiformats/go-multistream/pull/75)) + - chore: remove .gx ([multiformats/go-multistream#72](https://github.com/multiformats/go-multistream/pull/72)) + - don't commit the fuzzing binary ([multiformats/go-multistream#74](https://github.com/multiformats/go-multistream/pull/74)) + - sync: update CI config files (#71) ([multiformats/go-multistream#71](https://github.com/multiformats/go-multistream/pull/71)) + - remove Makefile ([multiformats/go-multistream#67](https://github.com/multiformats/go-multistream/pull/67)) + +
    + +### ❤ Contributors + +| Contributor | Commits | Lines ± | Files Changed | +|-------------|---------|---------|---------------| +| Marten Seemann | 350 | +14631/-12574 | 847 | +| Rod Vagg | 36 | +9362/-4300 | 231 | +| vyzo | 135 | +7963/-1785 | 233 | +| hannahhoward | 40 | +3761/-1652 | 175 | +| Will | 26 | +4771/-404 | 118 | +| Will Scott | 39 | +2885/-1784 | 93 | +| Daniel Martí | 36 | +3163/-996 | 114 | +| Adin Schmahmann | 43 | +3346/-522 | 114 | +| Steven Allen | 87 | +2465/-867 | 135 | +| Marcin Rataj | 26 | +2257/-815 | 62 | +| Masih H. Derkani | 14 | +2068/-861 | 71 | +| Gus Eggert | 22 | +2197/-680 | 94 | +| Lucas Molas | 26 | +1596/-576 | 88 | +| Raúl Kripalani | 18 | +1519/-271 | 38 | +| Brian Tiger Chow | 20 | +833/-379 | 40 | +| Jeromy Johnson | 53 | +646/-302 | 83 | +| Łukasz Magiera | 26 | +592/-245 | 43 | +| Artem Mikheev | 2 | +616/-120 | 5 | +| Franky W | 2 | +49/-525 | 9 | +| Laurent Senta | 3 | +468/-82 | 52 | +| Hector Sanjuan | 29 | +245/-176 | 58 | +| Juan Batiz-Benet | 8 | +285/-80 | 18 | +| Justin Johnson | 2 | +181/-88 | 2 | +| Thibault Meunier | 5 | +216/-28 | 8 | +| Aayush Rajasekaran | 2 | +133/-103 | 11 | +| James Wetter | 2 | +234/-1 | 2 | +| gammazero | 7 | +140/-84 | 12 | +| web3-bot | 35 | +157/-66 | 61 | +| Rachel Chen | 2 | +165/-57 | 17 | +| Toby | 2 | +107/-86 | 11 | +| Jorropo | 16 | +97/-96 | 24 | +| Dominic Della Valle | 4 | +148/-33 | 6 | +| Ian Davis | 2 | +152/-28 | 6 | +| Kyle Huntsman | 2 | +172/-6 | 5 | +| huoju | 4 | +127/-41 | 6 | +| Jeromy | 19 | +71/-58 | 31 | +| Lars Gierth | 12 | +63/-54 | 20 | +| Eric Myhre | 3 | +95/-15 | 8 | +| Caian Benedicto | 1 | +69/-12 | 6 | +| whyrusleeping | 2 | +50/-26 | 7 | +| Raúl Kripalani | 2 | +63/-13 | 2 | +| Anton Petrov | 1 | +73/-0 | 1 | +| hunjixin | 2 | +67/-2 | 5 | +| odanado | 1 | +61/-0 | 1 | +| Andrew Gillis | 2 | +61/-0 | 3 | +| Kevin Atkinson | 6 | +21/-34 | 7 | +| Richard Ramos | 1 | +51/-0 | 2 | +| Manuel Alonso | 1 | +42/-9 | 2 | +| Jakub Sztandera | 10 | +37/-13 | 13 | +| Aarsh Shah | 1 | +39/-5 | 2 | +| pymq | 1 | +32/-8 | 2 | +| Dave Justice | 1 | +32/-4 | 2 | +| Tommi Virtanen | 3 | +23/-9 | 4 | +| tarekbadr | 1 | +30/-1 | 1 | +| Petar Maymounkov | 2 | +30/-0 | 4 | +| Antonio Navarro Perez | 2 | +15/-13 | 7 | +| rht | 3 | +17/-10 | 4 | +| Miguel Mota | 1 | +23/-0 | 1 | +| Manfred Touron | 1 | +21/-2 | 2 | +| watjurk | 1 | +17/-5 | 1 | +| SukkaW | 1 | +11/-11 | 5 | +| Ho-Sheng Hsiao | 2 | +11/-10 | 6 | +| chblodg | 1 | +18/-2 | 1 | +| Friedel Ziegelmayer | 2 | +18/-0 | 2 | +| Shu Shen | 2 | +15/-2 | 3 | +| Peter Rabbitson | 1 | +15/-2 | 1 | +| ᴍᴀᴛᴛ ʙᴇʟʟ | 3 | +13/-1 | 4 | +| aarshkshah1992 | 3 | +12/-2 | 3 | +| RubenKelevra | 4 | +5/-8 | 5 | +| Feiran Yang | 1 | +11/-0 | 2 | +| zramsay | 2 | +0/-10 | 2 | +| Teran McKinney | 1 | +8/-2 | 1 | +| Richard Littauer | 2 | +5/-5 | 5 | +| Elijah | 1 | +10/-0 | 1 | +| Dimitris Apostolou | 2 | +5/-5 | 5 | +| Michael Avila | 3 | +8/-1 | 4 | +| Somajit | 1 | +4/-4 | 1 | +| Sherod Taylor | 1 | +0/-8 | 2 | +| Eclésio Junior | 1 | +8/-0 | 1 | +| godcong | 3 | +4/-3 | 3 | +| jwh | 1 | +6/-0 | 2 | +| Volker Mische | 1 | +4/-2 | 1 | +| rene | 2 | +3/-2 | 2 | +| keks | 1 | +5/-0 | 1 | +| Hlib | 1 | +4/-1 | 2 | +| Arash Payan | 1 | +5/-0 | 1 | +| siiky | 1 | +2/-2 | 1 | +| Wayback Archiver | 1 | +2/-2 | 1 | +| Ju Huo | 1 | +2/-2 | 1 | +| Ivan | 2 | +2/-2 | 2 | +| Ettore Di Giacinto | 2 | +3/-1 | 2 | +| Christian Couder | 1 | +3/-1 | 1 | +| ningmingxiao | 1 | +0/-3 | 1 | +| 市川恭佑 (ebi) | 1 | +1/-1 | 1 | +| star | 1 | +0/-2 | 1 | +| alliswell | 1 | +0/-2 | 1 | +| Preston Van Loon | 1 | +2/-0 | 1 | +| Nguyễn Gia Phong | 1 | +1/-1 | 1 | +| Nato Boram | 1 | +1/-1 | 1 | +| Mildred Ki'Lya | 1 | +2/-0 | 2 | +| Michael Burns | 1 | +1/-1 | 1 | +| Glenn | 1 | +1/-1 | 1 | +| George Antoniadis | 1 | +1/-1 | 1 | +| David Florness | 1 | +1/-1 | 1 | +| Coenie Beyers | 1 | +1/-1 | 1 | +| Benedikt Spies | 1 | +1/-1 | 1 | +| Abdul Rauf | 1 | +1/-1 | 1 | +| makeworld | 1 | +1/-0 | 1 | +| ignoramous | 1 | +0/-1 | 1 | +| galargh | 1 | +1/-0 | 1 | +| Omicron166 | 1 | +0/-1 | 1 | +| Jan Winkelmann | 1 | +1/-0 | 1 | +| Dr Ian Preston | 1 | +1/-0 | 1 | +| Baptiste Jonglez | 1 | +1/-0 | 1 | ## v0.12.2 and v0.11.1 2022-04-08 diff --git a/bin/mkreleaselog b/bin/mkreleaselog index d9f91833707..bbf570b7f63 100755 --- a/bin/mkreleaselog +++ b/bin/mkreleaselog @@ -45,6 +45,7 @@ IGNORE_FILES=( "*.pb.go" "cbor_gen.go" "ipldsch_*.go" + "*.gen.go" ) ########################################################################################## From 8c5fefad660390dd3f61094f03a4309461a7d6e5 Mon Sep 17 00:00:00 2001 From: Adin Schmahmann Date: Wed, 4 May 2022 16:23:16 -0400 Subject: [PATCH 390/414] Release v0.13.0-rc1 --- version.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/version.go b/version.go index 0018a056ecc..9bdf2c6fed0 100644 --- a/version.go +++ b/version.go @@ -11,7 +11,7 @@ import ( var CurrentCommit string // CurrentVersionNumber is the current application's version literal -const CurrentVersionNumber = "0.13.0-dev" +const CurrentVersionNumber = "0.13.0-rc1" const ApiVersion = "/go-ipfs/" + CurrentVersionNumber + "/" From f6586afa71727e15a92f13b16c2ba48d8939a963 Mon Sep 17 00:00:00 2001 From: Adin Schmahmann Date: Wed, 4 May 2022 18:47:13 -0400 Subject: [PATCH 391/414] fix: use path instead of filepath for asset embeds to support Windows (cherry picked from commit 1299bcb3fd4f6846dabf46182c8c7b712bae971d) --- assets/assets.go | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/assets/assets.go b/assets/assets.go index dea00e28915..ff87eec12ce 100644 --- a/assets/assets.go +++ b/assets/assets.go @@ -6,7 +6,7 @@ import ( "fmt" "io" "io/fs" - "path/filepath" + gopath "path" "strconv" "github.com/ipfs/go-ipfs/core" @@ -27,13 +27,13 @@ var AssetHash string // initDocPaths lists the paths for the docs we want to seed during --init var initDocPaths = []string{ - filepath.Join("init-doc", "about"), - filepath.Join("init-doc", "readme"), - filepath.Join("init-doc", "help"), - filepath.Join("init-doc", "contact"), - filepath.Join("init-doc", "security-notes"), - filepath.Join("init-doc", "quick-start"), - filepath.Join("init-doc", "ping"), + gopath.Join("init-doc", "about"), + gopath.Join("init-doc", "readme"), + gopath.Join("init-doc", "help"), + gopath.Join("init-doc", "contact"), + gopath.Join("init-doc", "security-notes"), + gopath.Join("init-doc", "quick-start"), + gopath.Join("init-doc", "ping"), } func init() { @@ -91,7 +91,7 @@ func addAssetList(nd *core.IpfsNode, l []string) (cid.Cid, error) { return cid.Cid{}, err } - fname := filepath.Base(p) + fname := gopath.Base(p) basePath, err = api.Object().AddLink(nd.Context(), basePath, fname, fp) if err != nil { From 62c64c1566d14c946c3702047b5118082be71ffb Mon Sep 17 00:00:00 2001 From: Daniel Norman <1992255+2color@users.noreply.github.com> Date: Fri, 6 May 2022 14:02:38 +0200 Subject: [PATCH 392/414] Add instructions to resolve repo migration error (#8946) Fixes #8779 Co-authored-by: Daniel N <2color@users.noreply.github.com> (cherry picked from commit d476f2d6dab6dc4c89541d49f4a417576be3c0f6) --- repo/fsrepo/fsrepo.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/repo/fsrepo/fsrepo.go b/repo/fsrepo/fsrepo.go index 7ad634c843b..c35d5458dc7 100644 --- a/repo/fsrepo/fsrepo.go +++ b/repo/fsrepo/fsrepo.go @@ -50,7 +50,7 @@ See https://github.com/ipfs/fs-repo-migrations/blob/master/run.md for details.` var ( ErrNoVersion = errors.New("no version file found, please run 0-to-1 migration tool.\n" + migrationInstructions) ErrOldRepo = errors.New("ipfs repo found in old '~/.go-ipfs' location, please run migration tool.\n" + migrationInstructions) - ErrNeedMigration = errors.New("ipfs repo needs migration") + ErrNeedMigration = errors.New("ipfs repo needs migration, please run migration tool.\n" + migrationInstructions) ) type NoRepoError struct { From 51fc526a543f46cac240fa01f4c8f6752343a51b Mon Sep 17 00:00:00 2001 From: Antonio Navarro Perez Date: Fri, 6 May 2022 17:13:24 +0200 Subject: [PATCH 393/414] Merge pull request #8934 from ajnavarro/fix/install-on-mac-m1-monterey (cherry picked from commit ae15e188949ca94afd80ef9c8f9e9af0fbb7cc0a) --- cmd/ipfs/dist/install.sh | 1 + 1 file changed, 1 insertion(+) diff --git a/cmd/ipfs/dist/install.sh b/cmd/ipfs/dist/install.sh index 9f673d05d59..470927159da 100755 --- a/cmd/ipfs/dist/install.sh +++ b/cmd/ipfs/dist/install.sh @@ -15,6 +15,7 @@ is_write_perm_missing="" for raw in $binpaths; do # Expand the $HOME variable. binpath=$(eval echo "$raw") + mkdir -p "$binpath" if mv "$bin" "$binpath/ipfs" ; then echo "Moved $bin to $binpath" exit 0 From 38c5dba662d790aa7d10aec09f97d5647a480722 Mon Sep 17 00:00:00 2001 From: Lucas Molas Date: Fri, 6 May 2022 12:23:36 -0300 Subject: [PATCH 394/414] Merge pull request #8947 from RubenKelevra/patch-7 'pin rm' helptext: rewrite description as object is not removed from local storage (immediately) (cherry picked from commit 831c33925f5096b8daf96e074658a588ba724a2a) --- core/commands/pin/pin.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/core/commands/pin/pin.go b/core/commands/pin/pin.go index 3a9caa03143..0344932f652 100644 --- a/core/commands/pin/pin.go +++ b/core/commands/pin/pin.go @@ -200,7 +200,7 @@ func pinAddMany(ctx context.Context, api coreiface.CoreAPI, enc cidenc.Encoder, var rmPinCmd = &cmds.Command{ Helptext: cmds.HelpText{ - Tagline: "Remove pinned objects from local storage.", + Tagline: "Remove object from pin-list.", ShortDescription: ` Removes the pin from the given object allowing it to be garbage collected if needed. (By default, recursively. Use -r=false for direct pins.) From a7048c45515f78a6c4f018fb0f3b9bd65ad60faa Mon Sep 17 00:00:00 2001 From: T Mo <91539446+TMoMoreau@users.noreply.github.com> Date: Fri, 6 May 2022 11:49:15 -0400 Subject: [PATCH 395/414] pubsub multibase encoding (#8933) * pubsub multibase encoding Adds clarification for pubsub multibase encoding over HTTP RPC for issue https://github.com/ipfs/ipfs-docs/issues/1007 * Grammatical change * Moved period (cherry picked from commit 9a84a4f06e89859e1c87523d604671a2db80f30f) --- core/commands/pubsub.go | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/core/commands/pubsub.go b/core/commands/pubsub.go index 570f850d097..e36b3b185b4 100644 --- a/core/commands/pubsub.go +++ b/core/commands/pubsub.go @@ -75,7 +75,7 @@ TOPIC AND DATA ENCODING `, }, Arguments: []cmds.Argument{ - cmds.StringArg("topic", true, false, "Name of topic to subscribe to."), + cmds.StringArg("topic", true, false, "Name of topic to subscribe to (multibase encoded when sent over HTTP RPC)."), }, PreRun: urlArgsEncoder, Run: func(req *cmds.Request, res cmds.ResponseEmitter, env cmds.Environment) error { @@ -170,7 +170,7 @@ HTTP RPC ENCODING `, }, Arguments: []cmds.Argument{ - cmds.StringArg("topic", true, false, "Topic to publish to."), + cmds.StringArg("topic", true, false, "Topic to publish to (multibase encoded when sent over HTTP RPC)."), cmds.FileArg("data", true, false, "The data to be published.").EnableStdin(), }, PreRun: urlArgsEncoder, From a6dc7afe4c817eaf7779cc56fd459b89469e4f9d Mon Sep 17 00:00:00 2001 From: Marcin Rataj Date: Fri, 6 May 2022 23:57:47 +0200 Subject: [PATCH 396/414] fix(ci): fix flaky t0081-repo-pinning.sh (#8919) * fix(ci): fix flaky t0081-repo-pinning.sh Sometimes docker pull fails, this will retry. * add upper bound on # retries (3) Co-authored-by: Gus Eggert (cherry picked from commit 6a4ee0a8a5a5bbf8251d57f27c9ef6770b71c9d4) --- .circleci/main.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.circleci/main.yml b/.circleci/main.yml index a3bfb6db088..7d80f03ff9d 100644 --- a/.circleci/main.yml +++ b/.circleci/main.yml @@ -177,7 +177,7 @@ jobs: git checkout FETCH_HEAD - run: cd rb-pinning-service-api && - docker-compose pull && + (for i in {1..3}; do docker-compose pull && break || sleep 5; done) && docker-compose up -d - *make_out_dirs From 93cad3b86f33abd1c583493464be5387ad6ddb2a Mon Sep 17 00:00:00 2001 From: galargh Date: Fri, 6 May 2022 15:28:09 +0200 Subject: [PATCH 397/414] ci: disable workflows in forks (cherry picked from commit 4798777377454245865b3a6a7eab128c6c811bfc) --- .github/workflows/codeql-analysis.yml | 2 ++ .github/workflows/docker-image.yml | 1 + .github/workflows/sync-release-assets.yml | 1 + .github/workflows/testground-on-push.yml | 6 +++++- 4 files changed, 9 insertions(+), 1 deletion(-) diff --git a/.github/workflows/codeql-analysis.yml b/.github/workflows/codeql-analysis.yml index 90bdd75b7bc..39f7073f5e6 100644 --- a/.github/workflows/codeql-analysis.yml +++ b/.github/workflows/codeql-analysis.yml @@ -2,6 +2,7 @@ name: "CodeQL" on: + workflow_dispatch: push: branches: [ master ] pull_request: @@ -12,6 +13,7 @@ on: jobs: analyze: + if: github.repository == 'ipfs/go-ipfs' || github.event_name == 'workflow_dispatch' name: Analyze runs-on: ubuntu-latest diff --git a/.github/workflows/docker-image.yml b/.github/workflows/docker-image.yml index f2f94739f17..1fda1c8b3aa 100644 --- a/.github/workflows/docker-image.yml +++ b/.github/workflows/docker-image.yml @@ -11,6 +11,7 @@ on: jobs: push_to_registry: + if: github.repository == 'ipfs/go-ipfs' || github.event_name == 'workflow_dispatch' name: Push Docker image to Docker Hub runs-on: ubuntu-latest env: diff --git a/.github/workflows/sync-release-assets.yml b/.github/workflows/sync-release-assets.yml index df055edd2ef..f6ca267199d 100644 --- a/.github/workflows/sync-release-assets.yml +++ b/.github/workflows/sync-release-assets.yml @@ -11,6 +11,7 @@ concurrency: jobs: sync-github-and-dist-ipfs-io: + if: github.repository == 'ipfs/go-ipfs' || github.event_name == 'workflow_dispatch' runs-on: "ubuntu-latest" steps: - uses: ipfs/download-ipfs-distribution-action@v1 diff --git a/.github/workflows/testground-on-push.yml b/.github/workflows/testground-on-push.yml index ae1c80dd99c..a73018ca7e9 100644 --- a/.github/workflows/testground-on-push.yml +++ b/.github/workflows/testground-on-push.yml @@ -1,10 +1,14 @@ --- name: Testground PR Checker -on: [push] +on: + workflow_dispatch: + push: + jobs: testground: + if: github.repository == 'ipfs/go-ipfs' || github.event_name == 'workflow_dispatch' runs-on: ubuntu-latest name: ${{ matrix.composition_file }} strategy: From ec6e6f82b9022e8b1eb99e3a9195819b44efa794 Mon Sep 17 00:00:00 2001 From: Marcin Rataj Date: Thu, 12 May 2022 14:52:17 +0200 Subject: [PATCH 398/414] fix: go-libp2p 0.19.2 with holepunch fixup (#8966) https://github.com/libp2p/go-libp2p/releases/tag/v0.19.2 (cherry picked from commit 657d4f4dd9cdb87d33c9b8b784cc89f78430b152) --- go.mod | 2 +- go.sum | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/go.mod b/go.mod index 02da160329f..c2b77d793fe 100644 --- a/go.mod +++ b/go.mod @@ -68,7 +68,7 @@ require ( github.com/jbenet/go-temp-err-catcher v0.1.0 github.com/jbenet/goprocess v0.1.4 github.com/libp2p/go-doh-resolver v0.4.0 - github.com/libp2p/go-libp2p v0.19.1 + github.com/libp2p/go-libp2p v0.19.2 github.com/libp2p/go-libp2p-core v0.15.1 github.com/libp2p/go-libp2p-discovery v0.6.0 github.com/libp2p/go-libp2p-http v0.2.1 diff --git a/go.sum b/go.sum index c34d0696896..982d04c457e 100644 --- a/go.sum +++ b/go.sum @@ -766,8 +766,8 @@ github.com/libp2p/go-libp2p v0.13.0/go.mod h1:pM0beYdACRfHO1WcJlp65WXyG2A6NqYM+t github.com/libp2p/go-libp2p v0.14.3/go.mod h1:d12V4PdKbpL0T1/gsUNN8DfgMuRPDX8bS2QxCZlwRH0= github.com/libp2p/go-libp2p v0.14.4/go.mod h1:EIRU0Of4J5S8rkockZM7eJp2S0UrCyi55m2kJVru3rM= github.com/libp2p/go-libp2p v0.16.0/go.mod h1:ump42BsirwAWxKzsCiFnTtN1Yc+DuPu76fyMX364/O4= -github.com/libp2p/go-libp2p v0.19.1 h1:ysBA1vDxhvgy9WmXpDeuk082EakewbJAwfU+ApdTG6I= -github.com/libp2p/go-libp2p v0.19.1/go.mod h1:Ki9jJXLO2YqrTIFxofV7Twyd3INWPT97+r8hGt7XPjI= +github.com/libp2p/go-libp2p v0.19.2 h1:s6XRBBuUnVYn0vBb4LZo/G6V2c/gODJ2K4/H35eGv+4= +github.com/libp2p/go-libp2p v0.19.2/go.mod h1:Ki9jJXLO2YqrTIFxofV7Twyd3INWPT97+r8hGt7XPjI= github.com/libp2p/go-libp2p-asn-util v0.0.0-20200825225859-85005c6cf052/go.mod h1:nRMRTab+kZuk0LnKZpxhOVH/ndsdr2Nr//Zltc/vwgo= github.com/libp2p/go-libp2p-asn-util v0.1.0/go.mod h1:wu+AnM9Ii2KgO5jMmS1rz9dvzTdj8BXqsPR9HR0XB7I= github.com/libp2p/go-libp2p-asn-util v0.2.0 h1:rg3+Os8jbnO5DxkC7K/Utdi+DkY3q/d1/1q+8WeNAsw= From d8d7c215e8c091eb7d613fee1a2bec64bf7c81d9 Mon Sep 17 00:00:00 2001 From: Lucas Molas Date: Thu, 12 May 2022 14:08:51 -0300 Subject: [PATCH 399/414] Merge pull request #8965 from ipfs/schomatis/fix/disable-rcmg-checks fix(node/libp2p): disable rcmgr checkImplicitDefaults (cherry picked from commit e23a4611d82e29ea6cbe3427b84c6e8f51ea3a28) --- .circleci/main.yml | 1 + core/node/libp2p/rcmgr_defaults.go | 6 +++++- 2 files changed, 6 insertions(+), 1 deletion(-) diff --git a/.circleci/main.yml b/.circleci/main.yml index 7d80f03ff9d..18c5d55cd81 100644 --- a/.circleci/main.yml +++ b/.circleci/main.yml @@ -32,6 +32,7 @@ default_environment: &default_environment CIRCLE_TEST_REPORTS: /tmp/circleci-test-results CIRCLE_ARTIFACTS: /tmp/circleci-artifacts GIT_PAGER: cat + IPFS_CHECK_RCMGR_DEFAULTS: 1 executors: golang: diff --git a/core/node/libp2p/rcmgr_defaults.go b/core/node/libp2p/rcmgr_defaults.go index e5e0cbb346f..11d24364149 100644 --- a/core/node/libp2p/rcmgr_defaults.go +++ b/core/node/libp2p/rcmgr_defaults.go @@ -4,6 +4,7 @@ import ( "encoding/json" "fmt" "math/bits" + "os" "strings" config "github.com/ipfs/go-ipfs/config" @@ -19,7 +20,10 @@ import ( // such as values in Swarm.ConnMgr.HiWater config. func adjustedDefaultLimits(cfg config.SwarmConfig) rcmgr.DefaultLimitConfig { // Run checks to avoid introducing regressions - checkImplicitDefaults() + if os.Getenv("IPFS_CHECK_RCMGR_DEFAULTS") != "" { + // FIXME: Broken. Being tracked in https://github.com/ipfs/go-ipfs/issues/8949. + checkImplicitDefaults() + } // Return to use unmodified static limits based on values from go-libp2p 0.18 // return defaultLimits From 5a1ca27ec6bbe57c07e500a5d9ea82eb0f0c1939 Mon Sep 17 00:00:00 2001 From: Marcin Rataj Date: Thu, 12 May 2022 19:32:54 +0200 Subject: [PATCH 400/414] chore: mark fuse experimental (#8962) It works only on some platforms, and does not work reliably. This corrects our error of not setting expectations right. (cherry picked from commit 53299e84e0995124c97fdb76571f8646cf03c6a7) --- cmd/ipfs/daemon.go | 2 +- core/commands/mount_nofuse.go | 1 + core/commands/mount_unix.go | 1 + core/commands/root.go | 2 +- docs/config.md | 2 ++ docs/experimental-features.md | 10 ++++++++++ docs/fuse.md | 2 ++ 7 files changed, 18 insertions(+), 2 deletions(-) diff --git a/cmd/ipfs/daemon.go b/cmd/ipfs/daemon.go index 14054c36fff..c1346059309 100644 --- a/cmd/ipfs/daemon.go +++ b/cmd/ipfs/daemon.go @@ -169,7 +169,7 @@ Headers. cmds.StringOption(initConfigOptionKwd, "Path to existing configuration file to be loaded during --init"), cmds.StringOption(initProfileOptionKwd, "Configuration profiles to apply for --init. See ipfs init --help for more"), cmds.StringOption(routingOptionKwd, "Overrides the routing option").WithDefault(routingOptionDefaultKwd), - cmds.BoolOption(mountKwd, "Mounts IPFS to the filesystem"), + cmds.BoolOption(mountKwd, "Mounts IPFS to the filesystem using FUSE (experimental)"), cmds.BoolOption(writableKwd, "Enable writing objects (with POST, PUT and DELETE)"), cmds.StringOption(ipfsMountKwd, "Path to the mountpoint for IPFS (if using --mount). Defaults to config setting."), cmds.StringOption(ipnsMountKwd, "Path to the mountpoint for IPNS (if using --mount). Defaults to config setting."), diff --git a/core/commands/mount_nofuse.go b/core/commands/mount_nofuse.go index 46e9df0cefc..c425aff0fcf 100644 --- a/core/commands/mount_nofuse.go +++ b/core/commands/mount_nofuse.go @@ -8,6 +8,7 @@ import ( ) var MountCmd = &cmds.Command{ + Status: cmds.Experimental, Helptext: cmds.HelpText{ Tagline: "Mounts ipfs to the filesystem (disabled).", ShortDescription: ` diff --git a/core/commands/mount_unix.go b/core/commands/mount_unix.go index bde049c3411..fd1c486ee3f 100644 --- a/core/commands/mount_unix.go +++ b/core/commands/mount_unix.go @@ -21,6 +21,7 @@ const ( ) var MountCmd = &cmds.Command{ + Status: cmds.Experimental, Helptext: cmds.HelpText{ Tagline: "Mounts IPFS to the filesystem (read-only).", ShortDescription: ` diff --git a/core/commands/root.go b/core/commands/root.go index 87bc3fd6f5d..71ec35e372c 100644 --- a/core/commands/root.go +++ b/core/commands/root.go @@ -52,7 +52,6 @@ TEXT ENCODING COMMANDS ADVANCED COMMANDS daemon Start a long-running daemon process - mount Mount an IPFS read-only mount point resolve Resolve any type of content path name Publish and resolve IPNS names key Create and list IPNS name keypairs @@ -61,6 +60,7 @@ ADVANCED COMMANDS stats Various operational stats p2p Libp2p stream mounting (experimental) filestore Manage the filestore (experimental) + mount Mount an IPFS read-only mount point (experimental) NETWORK COMMANDS id Show info about IPFS peers diff --git a/docs/config.md b/docs/config.md index 0a4b6c3c1bf..fbdc4540c55 100644 --- a/docs/config.md +++ b/docs/config.md @@ -1035,6 +1035,8 @@ Default: `cache` ## `Mounts` +**EXPERIMENTAL:** read about current limitations at [fuse.md](./fuse.md). + FUSE mount point configuration options. ### `Mounts.IPFS` diff --git a/docs/experimental-features.md b/docs/experimental-features.md index 4d99f58c2e2..ba12ef42bf8 100644 --- a/docs/experimental-features.md +++ b/docs/experimental-features.md @@ -19,6 +19,7 @@ the above issue. - [Private Networks](#private-networks) - [ipfs p2p](#ipfs-p2p) - [p2p http proxy](#p2p-http-proxy) +- [FUSE](#fuse) - [Plugins](#plugins) - [Directory Sharding / HAMT](#directory-sharding--hamt) - [IPNS PubSub](#ipns-pubsub) @@ -386,6 +387,15 @@ We also support the use of protocol names of the form /x/$NAME/http where $NAME - [ ] More documentation - [ ] Need better integration with the subdomain gateway feature. +## FUSE + +FUSE makes it possible to mount `/ipfs` and `/ipns` namespaces in your OS, +allowing argitrary apps access to IPFS using a subset of filesystem abstracitons. + +It is considered EXPERIMENTAL due to limited (and buggy) support on some platforms. + +See [fuse.md](./fuse.md) for more details. + ## Plugins ### In Version diff --git a/docs/fuse.md b/docs/fuse.md index a6399eeba44..8a229ead6ae 100644 --- a/docs/fuse.md +++ b/docs/fuse.md @@ -1,5 +1,7 @@ # FUSE +**EXPERIMENTAL:** FUSE support is limited, YMMV. + `go-ipfs` makes it possible to mount `/ipfs` and `/ipns` namespaces in your OS, allowing arbitrary apps access to IPFS. From 57706f218a68ed9843ed2d2ffc8c1ebe114b0631 Mon Sep 17 00:00:00 2001 From: Jorropo Date: Fri, 13 May 2022 17:46:33 +0200 Subject: [PATCH 401/414] fix: hanging goroutine in get fileArchive handler Fixes #8957 The context was only checked while reading data. Not while writing data to the http connection. So since the data flow through an io.Pipe the closing didn't flowed through and left the writer open hanging. Co-authored-by: Antonio Navarro Perez (cherry picked from commit 7892cc91f9ed17f5a6e0348334ed09c8bdb3194f) --- core/commands/get.go | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/core/commands/get.go b/core/commands/get.go index 65ab46aa57c..7f687ed228b 100644 --- a/core/commands/get.go +++ b/core/commands/get.go @@ -61,6 +61,7 @@ may also specify the level of compression by specifying '-l=<1-9>'. return err }, Run: func(req *cmds.Request, res cmds.ResponseEmitter, env cmds.Environment) error { + ctx := req.Context cmplvl, err := getCompressOptions(req) if err != nil { return err @@ -73,7 +74,7 @@ may also specify the level of compression by specifying '-l=<1-9>'. p := path.New(req.Arguments[0]) - file, err := api.Unixfs().Get(req.Context, p) + file, err := api.Unixfs().Get(ctx, p) if err != nil { return err } @@ -90,6 +91,13 @@ may also specify the level of compression by specifying '-l=<1-9>'. if err != nil { return err } + go func() { + // We cannot defer a close in the response writer (like we should) + // Because the cmd framework outsmart us and doesn't call response + // if the context is over. + <-ctx.Done() + reader.Close() + }() return res.Emit(reader) }, @@ -273,7 +281,7 @@ func (i *identityWriteCloser) Close() error { return nil } -func fileArchive(f files.Node, name string, archive bool, compression int) (io.Reader, error) { +func fileArchive(f files.Node, name string, archive bool, compression int) (io.ReadCloser, error) { cleaned := gopath.Clean(name) _, filename := gopath.Split(cleaned) From 1adb6eaff241327c502efd3cb44b11e0312dc52e Mon Sep 17 00:00:00 2001 From: siiky Date: Fri, 13 May 2022 16:52:10 +0100 Subject: [PATCH 402/414] docs: fix abstractions typo (cherry picked from commit a72753bade90c4a48c29aba6c0dc81c44785e9d2) --- docs/experimental-features.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/experimental-features.md b/docs/experimental-features.md index ba12ef42bf8..30343d48d7c 100644 --- a/docs/experimental-features.md +++ b/docs/experimental-features.md @@ -390,7 +390,7 @@ We also support the use of protocol names of the form /x/$NAME/http where $NAME ## FUSE FUSE makes it possible to mount `/ipfs` and `/ipns` namespaces in your OS, -allowing argitrary apps access to IPFS using a subset of filesystem abstracitons. +allowing argitrary apps access to IPFS using a subset of filesystem abstractions. It is considered EXPERIMENTAL due to limited (and buggy) support on some platforms. From 4449909b2da690d3677903fc0b1797c1ad00275b Mon Sep 17 00:00:00 2001 From: Marcin Rataj Date: Thu, 19 May 2022 20:11:19 +0200 Subject: [PATCH 403/414] fix: JS caching via Access-Control-Expose-Headers (#8984) This fix safelists additional headers allowing JS running on websites to read them when IPFS resource is downloaded via Fetch API. These headers provide metadata necessary for making smart caching decisions when IPFS resources are downloaded via Service Worker or a similar middleware on the edge. (cherry picked from commit 650bc246ab4a7c2a11a207e3bf9d74c07d190eb7) --- core/corehttp/gateway.go | 3 +++ test/sharness/t0112-gateway-cors.sh | 13 +++++++++++-- 2 files changed, 14 insertions(+), 2 deletions(-) diff --git a/core/corehttp/gateway.go b/core/corehttp/gateway.go index a4ae5383179..84ad13897c8 100644 --- a/core/corehttp/gateway.go +++ b/core/corehttp/gateway.go @@ -84,9 +84,12 @@ func GatewayOption(writable bool, paths ...string) ServeOption { headers[ACEHeadersName] = cleanHeaderSet( append([]string{ + "Content-Length", "Content-Range", "X-Chunked-Output", "X-Stream-Output", + "X-Ipfs-Path", + "X-Ipfs-Roots", }, headers[ACEHeadersName]...)) var gateway http.Handler = newGatewayHandler(GatewayConfig{ diff --git a/test/sharness/t0112-gateway-cors.sh b/test/sharness/t0112-gateway-cors.sh index cebb4e05aab..4bb2a509029 100755 --- a/test/sharness/t0112-gateway-cors.sh +++ b/test/sharness/t0112-gateway-cors.sh @@ -26,7 +26,10 @@ test_expect_success "GET response for Gateway resource looks good" ' grep "< Access-Control-Allow-Origin: \*" curl_output && grep "< Access-Control-Allow-Methods: GET" curl_output && grep "< Access-Control-Allow-Headers: Range" curl_output && - grep "< Access-Control-Expose-Headers: Content-Range" curl_output + grep "< Access-Control-Expose-Headers: Content-Range" curl_output && + grep "< Access-Control-Expose-Headers: Content-Length" curl_output && + grep "< Access-Control-Expose-Headers: X-Ipfs-Path" curl_output && + grep "< Access-Control-Expose-Headers: X-Ipfs-Roots" curl_output ' # HTTP OPTIONS Request @@ -40,7 +43,10 @@ test_expect_success "OPTIONS response for Gateway resource looks good" ' grep "< Access-Control-Allow-Origin: \*" curl_output && grep "< Access-Control-Allow-Methods: GET" curl_output && grep "< Access-Control-Allow-Headers: Range" curl_output && - grep "< Access-Control-Expose-Headers: Content-Range" curl_output + grep "< Access-Control-Expose-Headers: Content-Range" curl_output && + grep "< Access-Control-Expose-Headers: Content-Length" curl_output && + grep "< Access-Control-Expose-Headers: X-Ipfs-Path" curl_output && + grep "< Access-Control-Expose-Headers: X-Ipfs-Roots" curl_output ' test_kill_ipfs_daemon @@ -63,6 +69,9 @@ test_expect_success "Access-Control-Allow-Headers extends" ' grep "< Access-Control-Allow-Headers: Range" curl_output && grep "< Access-Control-Allow-Headers: X-Custom1" curl_output && grep "< Access-Control-Expose-Headers: Content-Range" curl_output && + grep "< Access-Control-Expose-Headers: Content-Length" curl_output && + grep "< Access-Control-Expose-Headers: X-Ipfs-Path" curl_output && + grep "< Access-Control-Expose-Headers: X-Ipfs-Roots" curl_output && grep "< Access-Control-Expose-Headers: X-Custom2" curl_output ' From cb72776dec434500bf657543f06f734ffb305e67 Mon Sep 17 00:00:00 2001 From: Gus Eggert Date: Thu, 19 May 2022 15:27:44 -0400 Subject: [PATCH 404/414] feat: log when resource manager limits are exceeded (#8980) This periodically logs how many times Resource Manager limits were exceeded. If they aren't exceeded, then nothing is logged. The log levels are at ERROR log level so that they are shown by default. The motivation is so that users know when they have exceeded resource manager limits. To find what is exceeding the limits, they'll need to turn on debug logging and inspect the errors being logged. This could collect the specific limits being reached, but that's more complicated to implement and could result in much longer log messages. (cherry picked from commit 5615715c55ae59a6b17877db84eac92821371c51) --- core/commands/swarm.go | 2 +- core/node/libp2p/rcmgr.go | 15 ++- core/node/libp2p/rcmgr_logging.go | 160 +++++++++++++++++++++++++ core/node/libp2p/rcmgr_logging_test.go | 58 +++++++++ go.mod | 7 +- 5 files changed, 236 insertions(+), 6 deletions(-) create mode 100644 core/node/libp2p/rcmgr_logging.go create mode 100644 core/node/libp2p/rcmgr_logging_test.go diff --git a/core/commands/swarm.go b/core/commands/swarm.go index d6a3e8d696d..f904ed67e19 100644 --- a/core/commands/swarm.go +++ b/core/commands/swarm.go @@ -409,7 +409,7 @@ Changes made via command line are persisted in the Swarm.ResourceMgr.Limits fiel return errors.New("expected a JSON file") } if err := json.NewDecoder(file).Decode(&newLimit); err != nil { - return errors.New("failed to decode JSON as ResourceMgrScopeConfig") + return fmt.Errorf("decoding JSON as ResourceMgrScopeConfig: %w", err) } return libp2p.NetSetLimit(node.ResourceManager, node.Repo, scope, newLimit) } diff --git a/core/node/libp2p/rcmgr.go b/core/node/libp2p/rcmgr.go index 28d05a131b4..4d4b29a564d 100644 --- a/core/node/libp2p/rcmgr.go +++ b/core/node/libp2p/rcmgr.go @@ -7,9 +7,11 @@ import ( "path/filepath" "strings" + "github.com/benbjohnson/clock" config "github.com/ipfs/go-ipfs/config" + "github.com/ipfs/go-ipfs/core/node/helpers" "github.com/ipfs/go-ipfs/repo" - + logging "github.com/ipfs/go-log/v2" "github.com/libp2p/go-libp2p" "github.com/libp2p/go-libp2p-core/network" "github.com/libp2p/go-libp2p-core/peer" @@ -24,8 +26,8 @@ const NetLimitTraceFilename = "rcmgr.json.gz" var NoResourceMgrError = fmt.Errorf("missing ResourceMgr: make sure the daemon is running with Swarm.ResourceMgr.Enabled") -func ResourceManager(cfg config.SwarmConfig) func(fx.Lifecycle, repo.Repo) (network.ResourceManager, Libp2pOpts, error) { - return func(lc fx.Lifecycle, repo repo.Repo) (network.ResourceManager, Libp2pOpts, error) { +func ResourceManager(cfg config.SwarmConfig) interface{} { + return func(mctx helpers.MetricsCtx, lc fx.Lifecycle, repo repo.Repo) (network.ResourceManager, Libp2pOpts, error) { var manager network.ResourceManager var opts Libp2pOpts @@ -72,6 +74,13 @@ func ResourceManager(cfg config.SwarmConfig) func(fx.Lifecycle, repo.Repo) (netw if err != nil { return nil, opts, fmt.Errorf("creating libp2p resource manager: %w", err) } + lrm := &loggingResourceManager{ + clock: clock.New(), + logger: &logging.Logger("resourcemanager").SugaredLogger, + delegate: manager, + } + lrm.start(helpers.LifecycleCtx(mctx, lc)) + manager = lrm } else { log.Debug("libp2p resource manager is disabled") manager = network.NullResourceManager diff --git a/core/node/libp2p/rcmgr_logging.go b/core/node/libp2p/rcmgr_logging.go new file mode 100644 index 00000000000..06d22c71b8c --- /dev/null +++ b/core/node/libp2p/rcmgr_logging.go @@ -0,0 +1,160 @@ +package libp2p + +import ( + "context" + "errors" + "sync" + "time" + + "github.com/benbjohnson/clock" + "github.com/libp2p/go-libp2p-core/network" + "github.com/libp2p/go-libp2p-core/peer" + "github.com/libp2p/go-libp2p-core/protocol" + rcmgr "github.com/libp2p/go-libp2p-resource-manager" + "go.uber.org/zap" +) + +type loggingResourceManager struct { + clock clock.Clock + logger *zap.SugaredLogger + delegate network.ResourceManager + logInterval time.Duration + + mut sync.Mutex + limitExceededErrs uint64 +} + +type loggingScope struct { + logger *zap.SugaredLogger + delegate network.ResourceScope + countErrs func(error) +} + +var _ network.ResourceManager = (*loggingResourceManager)(nil) + +func (n *loggingResourceManager) start(ctx context.Context) { + logInterval := n.logInterval + if logInterval == 0 { + logInterval = 10 * time.Second + } + ticker := n.clock.Ticker(logInterval) + go func() { + defer ticker.Stop() + for { + select { + case <-ticker.C: + n.mut.Lock() + errs := n.limitExceededErrs + n.limitExceededErrs = 0 + n.mut.Unlock() + if errs != 0 { + n.logger.Warnf("Resource limits were exceeded %d times, consider inspecting logs and raising the resource manager limits.", errs) + } + case <-ctx.Done(): + return + } + } + }() +} + +func (n *loggingResourceManager) countErrs(err error) { + if errors.Is(err, network.ErrResourceLimitExceeded) { + n.mut.Lock() + n.limitExceededErrs++ + n.mut.Unlock() + } +} + +func (n *loggingResourceManager) ViewSystem(f func(network.ResourceScope) error) error { + return n.delegate.ViewSystem(f) +} +func (n *loggingResourceManager) ViewTransient(f func(network.ResourceScope) error) error { + return n.delegate.ViewTransient(func(s network.ResourceScope) error { + return f(&loggingScope{logger: n.logger, delegate: s, countErrs: n.countErrs}) + }) +} +func (n *loggingResourceManager) ViewService(svc string, f func(network.ServiceScope) error) error { + return n.delegate.ViewService(svc, func(s network.ServiceScope) error { + return f(&loggingScope{logger: n.logger, delegate: s, countErrs: n.countErrs}) + }) +} +func (n *loggingResourceManager) ViewProtocol(p protocol.ID, f func(network.ProtocolScope) error) error { + return n.delegate.ViewProtocol(p, func(s network.ProtocolScope) error { + return f(&loggingScope{logger: n.logger, delegate: s, countErrs: n.countErrs}) + }) +} +func (n *loggingResourceManager) ViewPeer(p peer.ID, f func(network.PeerScope) error) error { + return n.delegate.ViewPeer(p, func(s network.PeerScope) error { + return f(&loggingScope{logger: n.logger, delegate: s, countErrs: n.countErrs}) + }) +} +func (n *loggingResourceManager) OpenConnection(dir network.Direction, usefd bool) (network.ConnManagementScope, error) { + connMgmtScope, err := n.delegate.OpenConnection(dir, usefd) + n.countErrs(err) + return connMgmtScope, err +} +func (n *loggingResourceManager) OpenStream(p peer.ID, dir network.Direction) (network.StreamManagementScope, error) { + connMgmtScope, err := n.delegate.OpenStream(p, dir) + n.countErrs(err) + return connMgmtScope, err +} +func (n *loggingResourceManager) Close() error { + return n.delegate.Close() +} + +func (s *loggingScope) ReserveMemory(size int, prio uint8) error { + err := s.delegate.ReserveMemory(size, prio) + s.countErrs(err) + return err +} +func (s *loggingScope) ReleaseMemory(size int) { + s.delegate.ReleaseMemory(size) +} +func (s *loggingScope) Stat() network.ScopeStat { + return s.delegate.Stat() +} +func (s *loggingScope) BeginSpan() (network.ResourceScopeSpan, error) { + return s.delegate.BeginSpan() +} +func (s *loggingScope) Done() { + s.delegate.(network.ResourceScopeSpan).Done() +} +func (s *loggingScope) Name() string { + return s.delegate.(network.ServiceScope).Name() +} +func (s *loggingScope) Protocol() protocol.ID { + return s.delegate.(network.ProtocolScope).Protocol() +} +func (s *loggingScope) Peer() peer.ID { + return s.delegate.(network.PeerScope).Peer() +} +func (s *loggingScope) PeerScope() network.PeerScope { + return s.delegate.(network.PeerScope) +} +func (s *loggingScope) SetPeer(p peer.ID) error { + err := s.delegate.(network.ConnManagementScope).SetPeer(p) + s.countErrs(err) + return err +} +func (s *loggingScope) ProtocolScope() network.ProtocolScope { + return s.delegate.(network.ProtocolScope) +} +func (s *loggingScope) SetProtocol(proto protocol.ID) error { + err := s.delegate.(network.StreamManagementScope).SetProtocol(proto) + s.countErrs(err) + return err +} +func (s *loggingScope) ServiceScope() network.ServiceScope { + return s.delegate.(network.ServiceScope) +} +func (s *loggingScope) SetService(srv string) error { + err := s.delegate.(network.StreamManagementScope).SetService(srv) + s.countErrs(err) + return err +} +func (s *loggingScope) Limit() rcmgr.Limit { + return s.delegate.(rcmgr.ResourceScopeLimiter).Limit() +} +func (s *loggingScope) SetLimit(limit rcmgr.Limit) { + s.delegate.(rcmgr.ResourceScopeLimiter).SetLimit(limit) +} diff --git a/core/node/libp2p/rcmgr_logging_test.go b/core/node/libp2p/rcmgr_logging_test.go new file mode 100644 index 00000000000..72f34b80885 --- /dev/null +++ b/core/node/libp2p/rcmgr_logging_test.go @@ -0,0 +1,58 @@ +package libp2p + +import ( + "context" + "testing" + "time" + + "github.com/benbjohnson/clock" + "github.com/libp2p/go-libp2p-core/network" + rcmgr "github.com/libp2p/go-libp2p-resource-manager" + "github.com/stretchr/testify/require" + "go.uber.org/zap" + "go.uber.org/zap/zaptest/observer" +) + +func TestLoggingResourceManager(t *testing.T) { + clock := clock.NewMock() + limiter := rcmgr.NewDefaultLimiter() + limiter.SystemLimits = limiter.SystemLimits.WithConnLimit(1, 1, 1) + rm, err := rcmgr.NewResourceManager(limiter) + if err != nil { + t.Fatal(err) + } + + oCore, oLogs := observer.New(zap.WarnLevel) + oLogger := zap.New(oCore) + lrm := &loggingResourceManager{ + clock: clock, + logger: oLogger.Sugar(), + delegate: rm, + logInterval: 1 * time.Second, + } + + // 2 of these should result in resource limit exceeded errors and subsequent log messages + for i := 0; i < 3; i++ { + _, _ = lrm.OpenConnection(network.DirInbound, false) + } + + // run the logger which will write an entry for those errors + ctx, cancel := context.WithCancel(context.Background()) + defer cancel() + lrm.start(ctx) + clock.Add(3 * time.Second) + + timer := time.NewTimer(1 * time.Second) + for { + select { + case <-timer.C: + t.Fatalf("expected logs never arrived") + default: + if oLogs.Len() == 0 { + continue + } + require.Equal(t, "Resource limits were exceeded 2 times, consider inspecting logs and raising the resource manager limits.", oLogs.All()[0].Message) + return + } + } +} diff --git a/go.mod b/go.mod index c2b77d793fe..b7946841b27 100644 --- a/go.mod +++ b/go.mod @@ -125,13 +125,17 @@ require ( golang.org/x/sys v0.0.0-20220412211240-33da011f77ad ) +require ( + github.com/benbjohnson/clock v1.3.0 + github.com/ipfs/go-log/v2 v2.5.1 +) + require ( github.com/AndreasBriese/bbloom v0.0.0-20190825152654-46b345b51c96 // indirect github.com/Kubuxu/go-os-helper v0.0.1 // indirect github.com/Stebalien/go-bitfield v0.0.1 // indirect github.com/alecthomas/units v0.0.0-20210927113745-59d0afb8317a // indirect github.com/alexbrainman/goissue34681 v0.0.0-20191006012335-3fc7a47baff5 // indirect - github.com/benbjohnson/clock v1.3.0 // indirect github.com/beorn7/perks v1.0.1 // indirect github.com/btcsuite/btcd v0.22.0-beta // indirect github.com/cenkalti/backoff v2.2.1+incompatible // indirect @@ -172,7 +176,6 @@ require ( github.com/ipfs/go-ipfs-delay v0.0.1 // indirect github.com/ipfs/go-ipfs-ds-help v1.1.0 // indirect github.com/ipfs/go-ipfs-pq v0.0.2 // indirect - github.com/ipfs/go-log/v2 v2.5.1 // indirect github.com/ipfs/go-peertaskqueue v0.7.1 // indirect github.com/jackpal/go-nat-pmp v1.0.2 // indirect github.com/klauspost/compress v1.15.1 // indirect From bf06e54d44f838f35dd7683aa2047c16692e9ad5 Mon Sep 17 00:00:00 2001 From: Antonio Navarro Perez Date: Wed, 25 May 2022 02:36:01 +0200 Subject: [PATCH 405/414] fix(ci): make go-ipfs-as-a-library work without external peers (#8978) * Do not connect to external nodes on ipfs as a lib example. It was causing some build timeouts error because CircleCI was throttling WAN connections. It closes #8956 * style: rename node vars since this is example, this should make things easier to follow Co-authored-by: Marcin Rataj (cherry picked from commit e8f1ce07b3d8076da5baedd772d80368804e57a7) --- docs/examples/go-ipfs-as-a-library/main.go | 156 +++++++++------------ 1 file changed, 66 insertions(+), 90 deletions(-) diff --git a/docs/examples/go-ipfs-as-a-library/main.go b/docs/examples/go-ipfs-as-a-library/main.go index 3833deb3e1d..9150325f763 100644 --- a/docs/examples/go-ipfs-as-a-library/main.go +++ b/docs/examples/go-ipfs-as-a-library/main.go @@ -86,7 +86,7 @@ func createTempRepo() (string, error) { /// ------ Spawning the node // Creates an IPFS node and returns its coreAPI -func createNode(ctx context.Context, repoPath string) (icore.CoreAPI, error) { +func createNode(ctx context.Context, repoPath string) (*core.IpfsNode, error) { // Open the repo repo, err := fsrepo.Open(repoPath) if err != nil { @@ -102,48 +102,36 @@ func createNode(ctx context.Context, repoPath string) (icore.CoreAPI, error) { Repo: repo, } - node, err := core.NewNode(ctx, nodeOptions) - if err != nil { - return nil, err - } - - // Attach the Core API to the constructed node - return coreapi.NewCoreAPI(node) + return core.NewNode(ctx, nodeOptions) } -// Spawns a node on the default repo location, if the repo exists -func spawnDefault(ctx context.Context) (icore.CoreAPI, error) { - defaultPath, err := config.PathRoot() - if err != nil { - // shouldn't be possible - return nil, err - } - - if err := setupPlugins(defaultPath); err != nil { - return nil, err - - } - - return createNode(ctx, defaultPath) -} +var loadPluginsOnce sync.Once // Spawns a node to be used just for this run (i.e. creates a tmp repo) -func spawnEphemeral(ctx context.Context) (icore.CoreAPI, error) { - if err := setupPlugins(""); err != nil { - return nil, err +func spawnEphemeral(ctx context.Context) (icore.CoreAPI, *core.IpfsNode, error) { + var onceErr error + loadPluginsOnce.Do(func() { + onceErr = setupPlugins("") + }) + if onceErr != nil { + return nil, nil, onceErr } // Create a Temporary Repo repoPath, err := createTempRepo() if err != nil { - return nil, fmt.Errorf("failed to create temp repo: %s", err) + return nil, nil, fmt.Errorf("failed to create temp repo: %s", err) } - // Spawning an ephemeral IPFS node - return createNode(ctx, repoPath) -} + node, err := createNode(ctx, repoPath) + if err != nil { + return nil, nil, err + } -// + api, err := coreapi.NewCoreAPI(node) + + return api, node, err +} func connectToPeers(ctx context.Context, ipfs icore.CoreAPI, peers []string) error { var wg sync.WaitGroup @@ -179,26 +167,6 @@ func connectToPeers(ctx context.Context, ipfs icore.CoreAPI, peers []string) err return nil } -func getUnixfsFile(path string) (files.File, error) { - file, err := os.Open(path) - if err != nil { - return nil, err - } - defer file.Close() - - st, err := file.Stat() - if err != nil { - return nil, err - } - - f, err := files.NewReaderPathFile(path, file, st) - if err != nil { - return nil, err - } - - return f, nil -} - func getUnixfsNode(path string) (files.Node, error) { st, err := os.Stat(path) if err != nil { @@ -227,18 +195,23 @@ func main() { ctx, cancel := context.WithCancel(context.Background()) defer cancel() - /* - // Spawn a node using the default path (~/.ipfs), assuming that a repo exists there already - fmt.Println("Spawning node on default repo") - ipfs, err := spawnDefault(ctx) - if err != nil { - panic(fmt.Errorf("failed to spawnDefault node: %s", err)) - } - */ + // Spawn a local peer using a temporary path, for testing purposes + ipfsA, nodeA, err := spawnEphemeral(ctx) + if err != nil { + panic(fmt.Errorf("failed to spawn peer node: %s", err)) + } + + peerCidFile, err := ipfsA.Unixfs().Add(ctx, + files.NewBytesFile([]byte("hello from ipfs 101 in go-ipfs"))) + if err != nil { + panic(fmt.Errorf("could not add File: %s", err)) + } + + fmt.Printf("Added file to peer with CID %s\n", peerCidFile.String()) // Spawn a node using a temporary path, creating a temporary repo for the run fmt.Println("Spawning node on a temporary repo") - ipfs, err := spawnEphemeral(ctx) + ipfsB, _, err := spawnEphemeral(ctx) if err != nil { panic(fmt.Errorf("failed to spawn ephemeral node: %s", err)) } @@ -255,24 +228,24 @@ func main() { someFile, err := getUnixfsNode(inputPathFile) if err != nil { - panic(fmt.Errorf("Could not get File: %s", err)) + panic(fmt.Errorf("could not get File: %s", err)) } - cidFile, err := ipfs.Unixfs().Add(ctx, someFile) + cidFile, err := ipfsB.Unixfs().Add(ctx, someFile) if err != nil { - panic(fmt.Errorf("Could not add File: %s", err)) + panic(fmt.Errorf("could not add File: %s", err)) } fmt.Printf("Added file to IPFS with CID %s\n", cidFile.String()) someDirectory, err := getUnixfsNode(inputPathDirectory) if err != nil { - panic(fmt.Errorf("Could not get File: %s", err)) + panic(fmt.Errorf("could not get File: %s", err)) } - cidDirectory, err := ipfs.Unixfs().Add(ctx, someDirectory) + cidDirectory, err := ipfsB.Unixfs().Add(ctx, someDirectory) if err != nil { - panic(fmt.Errorf("Could not add Directory: %s", err)) + panic(fmt.Errorf("could not add Directory: %s", err)) } fmt.Printf("Added directory to IPFS with CID %s\n", cidDirectory.String()) @@ -287,26 +260,26 @@ func main() { outputPathFile := outputBasePath + strings.Split(cidFile.String(), "/")[2] outputPathDirectory := outputBasePath + strings.Split(cidDirectory.String(), "/")[2] - rootNodeFile, err := ipfs.Unixfs().Get(ctx, cidFile) + rootNodeFile, err := ipfsB.Unixfs().Get(ctx, cidFile) if err != nil { - panic(fmt.Errorf("Could not get file with CID: %s", err)) + panic(fmt.Errorf("could not get file with CID: %s", err)) } err = files.WriteTo(rootNodeFile, outputPathFile) if err != nil { - panic(fmt.Errorf("Could not write out the fetched CID: %s", err)) + panic(fmt.Errorf("could not write out the fetched CID: %s", err)) } - fmt.Printf("Got file back from IPFS (IPFS path: %s) and wrote it to %s\n", cidFile.String(), outputPathFile) + fmt.Printf("got file back from IPFS (IPFS path: %s) and wrote it to %s\n", cidFile.String(), outputPathFile) - rootNodeDirectory, err := ipfs.Unixfs().Get(ctx, cidDirectory) + rootNodeDirectory, err := ipfsB.Unixfs().Get(ctx, cidDirectory) if err != nil { - panic(fmt.Errorf("Could not get file with CID: %s", err)) + panic(fmt.Errorf("could not get file with CID: %s", err)) } err = files.WriteTo(rootNodeDirectory, outputPathDirectory) if err != nil { - panic(fmt.Errorf("Could not write out the fetched CID: %s", err)) + panic(fmt.Errorf("could not write out the fetched CID: %s", err)) } fmt.Printf("Got directory back from IPFS (IPFS path: %s) and wrote it to %s\n", cidDirectory.String(), outputPathDirectory) @@ -315,49 +288,52 @@ func main() { fmt.Println("\n-- Going to connect to a few nodes in the Network as bootstrappers --") + peerMa := fmt.Sprintf("/ip4/127.0.0.1/udp/4010/p2p/%s", nodeA.Identity.String()) + bootstrapNodes := []string{ // IPFS Bootstrapper nodes. - "/dnsaddr/bootstrap.libp2p.io/p2p/QmNnooDu7bfjPFoTZYxMNLWUQJyrVwtbZg5gBMjTezGAJN", - "/dnsaddr/bootstrap.libp2p.io/p2p/QmQCU2EcMqAqQPR2i9bChDtGNJchTbq5TbXJJ16u19uLTa", - "/dnsaddr/bootstrap.libp2p.io/p2p/QmbLHAnMoJPWSCR5Zhtx6BHJX9KiKNN6tpvbUcqanj75Nb", - "/dnsaddr/bootstrap.libp2p.io/p2p/QmcZf59bWwK5XFi76CZX8cbJ4BhTzzA3gU1ZjYZcYW3dwt", + // "/dnsaddr/bootstrap.libp2p.io/p2p/QmNnooDu7bfjPFoTZYxMNLWUQJyrVwtbZg5gBMjTezGAJN", + // "/dnsaddr/bootstrap.libp2p.io/p2p/QmQCU2EcMqAqQPR2i9bChDtGNJchTbq5TbXJJ16u19uLTa", + // "/dnsaddr/bootstrap.libp2p.io/p2p/QmbLHAnMoJPWSCR5Zhtx6BHJX9KiKNN6tpvbUcqanj75Nb", + // "/dnsaddr/bootstrap.libp2p.io/p2p/QmcZf59bWwK5XFi76CZX8cbJ4BhTzzA3gU1ZjYZcYW3dwt", // IPFS Cluster Pinning nodes - "/ip4/138.201.67.219/tcp/4001/p2p/QmUd6zHcbkbcs7SMxwLs48qZVX3vpcM8errYS7xEczwRMA", - "/ip4/138.201.67.219/udp/4001/quic/p2p/QmUd6zHcbkbcs7SMxwLs48qZVX3vpcM8errYS7xEczwRMA", - "/ip4/138.201.67.220/tcp/4001/p2p/QmNSYxZAiJHeLdkBg38roksAR9So7Y5eojks1yjEcUtZ7i", - "/ip4/138.201.67.220/udp/4001/quic/p2p/QmNSYxZAiJHeLdkBg38roksAR9So7Y5eojks1yjEcUtZ7i", - "/ip4/138.201.68.74/tcp/4001/p2p/QmdnXwLrC8p1ueiq2Qya8joNvk3TVVDAut7PrikmZwubtR", - "/ip4/138.201.68.74/udp/4001/quic/p2p/QmdnXwLrC8p1ueiq2Qya8joNvk3TVVDAut7PrikmZwubtR", - "/ip4/94.130.135.167/tcp/4001/p2p/QmUEMvxS2e7iDrereVYc5SWPauXPyNwxcy9BXZrC1QTcHE", - "/ip4/94.130.135.167/udp/4001/quic/p2p/QmUEMvxS2e7iDrereVYc5SWPauXPyNwxcy9BXZrC1QTcHE", + // "/ip4/138.201.67.219/tcp/4001/p2p/QmUd6zHcbkbcs7SMxwLs48qZVX3vpcM8errYS7xEczwRMA", + // "/ip4/138.201.67.219/udp/4001/quic/p2p/QmUd6zHcbkbcs7SMxwLs48qZVX3vpcM8errYS7xEczwRMA", + // "/ip4/138.201.67.220/tcp/4001/p2p/QmNSYxZAiJHeLdkBg38roksAR9So7Y5eojks1yjEcUtZ7i", + // "/ip4/138.201.67.220/udp/4001/quic/p2p/QmNSYxZAiJHeLdkBg38roksAR9So7Y5eojks1yjEcUtZ7i", + // "/ip4/138.201.68.74/tcp/4001/p2p/QmdnXwLrC8p1ueiq2Qya8joNvk3TVVDAut7PrikmZwubtR", + // "/ip4/138.201.68.74/udp/4001/quic/p2p/QmdnXwLrC8p1ueiq2Qya8joNvk3TVVDAut7PrikmZwubtR", + // "/ip4/94.130.135.167/tcp/4001/p2p/QmUEMvxS2e7iDrereVYc5SWPauXPyNwxcy9BXZrC1QTcHE", + // "/ip4/94.130.135.167/udp/4001/quic/p2p/QmUEMvxS2e7iDrereVYc5SWPauXPyNwxcy9BXZrC1QTcHE", // You can add more nodes here, for example, another IPFS node you might have running locally, mine was: // "/ip4/127.0.0.1/tcp/4010/p2p/QmZp2fhDLxjYue2RiUvLwT9MWdnbDxam32qYFnGmxZDh5L", // "/ip4/127.0.0.1/udp/4010/quic/p2p/QmZp2fhDLxjYue2RiUvLwT9MWdnbDxam32qYFnGmxZDh5L", + peerMa, } go func() { - err := connectToPeers(ctx, ipfs, bootstrapNodes) + err := connectToPeers(ctx, ipfsB, bootstrapNodes) if err != nil { log.Printf("failed connect to peers: %s", err) } }() - exampleCIDStr := "QmUaoioqU7bxezBQZkUcgcSyokatMY71sxsALxQmRRrHrj" + exampleCIDStr := peerCidFile.Cid().String() fmt.Printf("Fetching a file from the network with CID %s\n", exampleCIDStr) outputPath := outputBasePath + exampleCIDStr testCID := icorepath.New(exampleCIDStr) - rootNode, err := ipfs.Unixfs().Get(ctx, testCID) + rootNode, err := ipfsB.Unixfs().Get(ctx, testCID) if err != nil { - panic(fmt.Errorf("Could not get file with CID: %s", err)) + panic(fmt.Errorf("could not get file with CID: %s", err)) } err = files.WriteTo(rootNode, outputPath) if err != nil { - panic(fmt.Errorf("Could not write out the fetched CID: %s", err)) + panic(fmt.Errorf("could not write out the fetched CID: %s", err)) } fmt.Printf("Wrote the file to %s\n", outputPath) From 8dffa84d77e585edecabbdbd11c3ddcb4292f2d3 Mon Sep 17 00:00:00 2001 From: Marten Seemann Date: Wed, 1 Jun 2022 17:08:22 +0200 Subject: [PATCH 406/414] chore: update go-libp2p to v0.19.3 (#8990) (cherry picked from commit f720172a2a6c92cde058880b4ae0f38400dde70f) --- go.mod | 4 ++-- go.sum | 7 ++++--- 2 files changed, 6 insertions(+), 5 deletions(-) diff --git a/go.mod b/go.mod index b7946841b27..cd56046a0ad 100644 --- a/go.mod +++ b/go.mod @@ -68,7 +68,7 @@ require ( github.com/jbenet/go-temp-err-catcher v0.1.0 github.com/jbenet/goprocess v0.1.4 github.com/libp2p/go-doh-resolver v0.4.0 - github.com/libp2p/go-libp2p v0.19.2 + github.com/libp2p/go-libp2p v0.19.3 github.com/libp2p/go-libp2p-core v0.15.1 github.com/libp2p/go-libp2p-discovery v0.6.0 github.com/libp2p/go-libp2p-http v0.2.1 @@ -203,7 +203,7 @@ require ( github.com/libp2p/go-stream-muxer-multistream v0.4.0 // indirect github.com/libp2p/go-yamux/v3 v3.1.1 // indirect github.com/libp2p/zeroconf/v2 v2.1.1 // indirect - github.com/lucas-clemente/quic-go v0.27.0 // indirect + github.com/lucas-clemente/quic-go v0.27.1 // indirect github.com/marten-seemann/qtls-go1-16 v0.1.5 // indirect github.com/marten-seemann/qtls-go1-17 v0.1.1 // indirect github.com/marten-seemann/qtls-go1-18 v0.1.1 // indirect diff --git a/go.sum b/go.sum index 982d04c457e..a74cb32907e 100644 --- a/go.sum +++ b/go.sum @@ -766,8 +766,8 @@ github.com/libp2p/go-libp2p v0.13.0/go.mod h1:pM0beYdACRfHO1WcJlp65WXyG2A6NqYM+t github.com/libp2p/go-libp2p v0.14.3/go.mod h1:d12V4PdKbpL0T1/gsUNN8DfgMuRPDX8bS2QxCZlwRH0= github.com/libp2p/go-libp2p v0.14.4/go.mod h1:EIRU0Of4J5S8rkockZM7eJp2S0UrCyi55m2kJVru3rM= github.com/libp2p/go-libp2p v0.16.0/go.mod h1:ump42BsirwAWxKzsCiFnTtN1Yc+DuPu76fyMX364/O4= -github.com/libp2p/go-libp2p v0.19.2 h1:s6XRBBuUnVYn0vBb4LZo/G6V2c/gODJ2K4/H35eGv+4= -github.com/libp2p/go-libp2p v0.19.2/go.mod h1:Ki9jJXLO2YqrTIFxofV7Twyd3INWPT97+r8hGt7XPjI= +github.com/libp2p/go-libp2p v0.19.3 h1:LqjvuBWdyYSqvkH4VVYxA78Fkphzg2Pq86VMnilqgkw= +github.com/libp2p/go-libp2p v0.19.3/go.mod h1:AGlPVLjh0+6jvEtf+a2gZEux7yHJrYXnG9IC7wcQ2NY= github.com/libp2p/go-libp2p-asn-util v0.0.0-20200825225859-85005c6cf052/go.mod h1:nRMRTab+kZuk0LnKZpxhOVH/ndsdr2Nr//Zltc/vwgo= github.com/libp2p/go-libp2p-asn-util v0.1.0/go.mod h1:wu+AnM9Ii2KgO5jMmS1rz9dvzTdj8BXqsPR9HR0XB7I= github.com/libp2p/go-libp2p-asn-util v0.2.0 h1:rg3+Os8jbnO5DxkC7K/Utdi+DkY3q/d1/1q+8WeNAsw= @@ -1109,8 +1109,9 @@ github.com/lucas-clemente/quic-go v0.21.2/go.mod h1:vF5M1XqhBAHgbjKcJOXY3JZz3GP0 github.com/lucas-clemente/quic-go v0.23.0/go.mod h1:paZuzjXCE5mj6sikVLMvqXk8lJV2AsqtJ6bDhjEfxx0= github.com/lucas-clemente/quic-go v0.24.0/go.mod h1:paZuzjXCE5mj6sikVLMvqXk8lJV2AsqtJ6bDhjEfxx0= github.com/lucas-clemente/quic-go v0.25.0/go.mod h1:YtzP8bxRVCBlO77yRanE264+fY/T2U9ZlW1AaHOsMOg= -github.com/lucas-clemente/quic-go v0.27.0 h1:v6WY87q9zD4dKASbG8hy/LpzAVNzEQzw8sEIeloJsc4= github.com/lucas-clemente/quic-go v0.27.0/go.mod h1:AzgQoPda7N+3IqMMMkywBKggIFo2KT6pfnlrQ2QieeI= +github.com/lucas-clemente/quic-go v0.27.1 h1:sOw+4kFSVrdWOYmUjufQ9GBVPqZ+tu+jMtXxXNmRJyk= +github.com/lucas-clemente/quic-go v0.27.1/go.mod h1:AzgQoPda7N+3IqMMMkywBKggIFo2KT6pfnlrQ2QieeI= github.com/lunixbochs/vtclean v1.0.0/go.mod h1:pHhQNgMf3btfWnGBVipUOjRYhoOsdGqdm/+2c2E2WMI= github.com/lyft/protoc-gen-validate v0.0.13/go.mod h1:XbGvPuh87YZc5TdIa2/I4pLk0QoUACkjt2znoq26NVQ= github.com/magiconair/properties v1.8.0/go.mod h1:PppfXfuXeibc/6YijjN8zIbojt8czPbwD3XqdrwzmxQ= From 87fca8f225130fa5104e4477bd52cc0af542c600 Mon Sep 17 00:00:00 2001 From: Gus Eggert Date: Thu, 2 Jun 2022 10:23:42 -0400 Subject: [PATCH 407/414] fix: adjust rcmgr limits for accelerated DHT client rt refresh (#8982) * fix: adjust rcmgr limits for accelerated DHT client rt refresh The Accelerated DHT client periodically refreshes its routing table, including at startup, and if Resource Manager throttling causes the client's routing table to be incomplete, then content routing may be degraded or broken for users. This adjusts the default limits to a level that empirically doesn't cause Resource Manager throttling during initial DHT client bootstrapping. Ideally the Accelerated DHT client would handle this scenario more gracefully, but this works for now to unblock the 0.13 release. * Set default outbound conns unconditionally This also sets the default overall conns as a function of the outbound and inbound conns, since they are adjusted dynamically, and it makes the intention of the value clear. * increase min FD limit (cherry picked from commit b8617b99665fe3b1ae8123fa9a71aad295771057) --- core/node/libp2p/rcmgr_defaults.go | 31 +++++++++++++++++++++--------- 1 file changed, 22 insertions(+), 9 deletions(-) diff --git a/core/node/libp2p/rcmgr_defaults.go b/core/node/libp2p/rcmgr_defaults.go index 11d24364149..3f754fce433 100644 --- a/core/node/libp2p/rcmgr_defaults.go +++ b/core/node/libp2p/rcmgr_defaults.go @@ -25,32 +25,43 @@ func adjustedDefaultLimits(cfg config.SwarmConfig) rcmgr.DefaultLimitConfig { checkImplicitDefaults() } - // Return to use unmodified static limits based on values from go-libp2p 0.18 - // return defaultLimits - // Adjust limits // (based on https://github.com/filecoin-project/lotus/pull/8318/files) // - give it more memory, up to 4G, min of 1G // - if Swarm.ConnMgr.HighWater is too high, adjust Conn/FD/Stream limits defaultLimits := rcmgr.DefaultLimits.WithSystemMemory(.125, 1<<30, 4<<30) + // Outbound conns and FDs are set very high to allow for the accelerated DHT client to (re)load its routing table. + // Currently it doesn't gracefully handle RM throttling--once it does we can lower these. + // High outbound conn limits are considered less of a DoS risk than high inbound conn limits. + // Also note that, due to the behavior of the accelerated DHT client, we don't need many streams, just conns. + if minOutbound := 65536; defaultLimits.SystemBaseLimit.ConnsOutbound < minOutbound { + defaultLimits.SystemBaseLimit.ConnsOutbound = minOutbound + } + if minFD := 4096; defaultLimits.SystemBaseLimit.FD < minFD { + defaultLimits.SystemBaseLimit.FD = minFD + } + // Do we need to adjust due to Swarm.ConnMgr.HighWater? if cfg.ConnMgr.Type == "basic" { maxconns := cfg.ConnMgr.HighWater if 2*maxconns > defaultLimits.SystemBaseLimit.ConnsInbound { - // adjust conns to 2x to allow for two conns per peer (TCP+QUIC) + // Conns should be at least 2x larger than the high water to allow for two conns per peer (TCP+QUIC). defaultLimits.SystemBaseLimit.ConnsInbound = logScale(2 * maxconns) - defaultLimits.SystemBaseLimit.ConnsOutbound = logScale(2 * maxconns) - defaultLimits.SystemBaseLimit.Conns = logScale(4 * maxconns) - defaultLimits.SystemBaseLimit.StreamsInbound = logScale(16 * maxconns) - defaultLimits.SystemBaseLimit.StreamsOutbound = logScale(64 * maxconns) - defaultLimits.SystemBaseLimit.Streams = logScale(64 * maxconns) + // We want the floor of minOutbound conns to be no less than what was set above. + if minOutbound := logScale(2 * maxconns); minOutbound > defaultLimits.SystemBaseLimit.ConnsOutbound { + defaultLimits.SystemBaseLimit.ConnsOutbound = minOutbound + } if 2*maxconns > defaultLimits.SystemBaseLimit.FD { defaultLimits.SystemBaseLimit.FD = logScale(2 * maxconns) } + defaultLimits.SystemBaseLimit.StreamsInbound = logScale(16 * maxconns) + defaultLimits.SystemBaseLimit.StreamsOutbound = logScale(64 * maxconns) + defaultLimits.SystemBaseLimit.Streams = logScale(64 * maxconns) + defaultLimits.ServiceBaseLimit.StreamsInbound = logScale(8 * maxconns) defaultLimits.ServiceBaseLimit.StreamsOutbound = logScale(32 * maxconns) defaultLimits.ServiceBaseLimit.Streams = logScale(32 * maxconns) @@ -61,6 +72,8 @@ func adjustedDefaultLimits(cfg config.SwarmConfig) rcmgr.DefaultLimitConfig { } } + defaultLimits.SystemBaseLimit.Conns = defaultLimits.SystemBaseLimit.ConnsOutbound + defaultLimits.SystemBaseLimit.ConnsInbound + return defaultLimits } From 0fe75d63ea9990aaab72e3a3759b47428d991584 Mon Sep 17 00:00:00 2001 From: Gus Eggert Date: Thu, 2 Jun 2022 10:31:06 -0400 Subject: [PATCH 408/414] feat: disable resource manager by default (#9003) * feat: disable resource manager by default We are disabling this by default for v0.13 as we work to improve the UX around Resource Manager. It is still usable and can be enabled in the IPFS config with "ipfs config --bool Swarm.ResourceMgr.Enabled true". We intend to enable Resource Manager by default in a subsequent release. * docs(config): Swarm.ResourceMgr disabled by default Co-authored-by: Marcin Rataj (cherry picked from commit b1c051d2507cec34a9d2b313ea43a092b3fdc4a4) --- CHANGELOG.md | 7 +++- core/node/libp2p/rcmgr.go | 2 +- docs/config.md | 2 +- .../t0116-prometheus-data/prometheus_metrics | 4 -- test/sharness/t0139-swarm-rcmgr.sh | 38 +++++++++---------- 5 files changed, 26 insertions(+), 27 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 463b9448aa2..1c28aa80597 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -74,16 +74,19 @@ To understand the wider context why we made these changes, read *Highlights* bel *You can now easily bound how much resource usage libp2p consumes! This aids in protecting nodes from consuming more resources then are available to them.* -The [libp2p Network Resource Manager](https://github.com/libp2p/go-libp2p-resource-manager#readme) is enabled by default, but can be disabled via: +The [libp2p Network Resource Manager](https://github.com/libp2p/go-libp2p-resource-manager#readme) is disabled by default, but can be enabled via: -`ipfs config --json Swarm.ResourceMgr.Enabled false` +`ipfs config --json Swarm.ResourceMgr.Enabled true` When enabled, it applies some safe defaults that can be inspected and adjusted with: + - `ipfs swarm stats --help` - `ipfs swarm limit --help` User changes persist to config at [`Swarm.ResourceMgr`](https://github.com/ipfs/go-ipfs/blob/master/docs/config.md#swarmresourcemgr). +The Resource Manager will be enabled by default in a future release. + #### 🔃 Relay V2 client with auto discovery (`Swarm.RelayClient`) *All the pieces are enabled for [hole-punching](https://blog.ipfs.io/2022-01-20-libp2p-hole-punching/) by default, improving connecting with nodes behind NATs and Firewalls!* diff --git a/core/node/libp2p/rcmgr.go b/core/node/libp2p/rcmgr.go index 4d4b29a564d..c6a4a5f4866 100644 --- a/core/node/libp2p/rcmgr.go +++ b/core/node/libp2p/rcmgr.go @@ -31,7 +31,7 @@ func ResourceManager(cfg config.SwarmConfig) interface{} { var manager network.ResourceManager var opts Libp2pOpts - enabled := cfg.ResourceMgr.Enabled.WithDefault(true) + enabled := cfg.ResourceMgr.Enabled.WithDefault(false) /// ENV overrides Config (if present) switch os.Getenv("LIBP2P_RCMGR") { diff --git a/docs/config.md b/docs/config.md index fbdc4540c55..8f2cee06fec 100644 --- a/docs/config.md +++ b/docs/config.md @@ -1637,7 +1637,7 @@ and tracking recource usage over time. Enables the libp2p Network Resource Manager and auguments the default limits using user-defined ones in `Swarm.ResourceMgr.Limits` (if present). -Default: `true` +Default: `false` Type: `flag` diff --git a/test/sharness/t0116-prometheus-data/prometheus_metrics b/test/sharness/t0116-prometheus-data/prometheus_metrics index adffa4c1b91..dd358e82f4f 100644 --- a/test/sharness/t0116-prometheus-data/prometheus_metrics +++ b/test/sharness/t0116-prometheus-data/prometheus_metrics @@ -656,10 +656,6 @@ leveldb_datastore_sync_latency_seconds_bucket leveldb_datastore_sync_latency_seconds_count leveldb_datastore_sync_latency_seconds_sum leveldb_datastore_sync_total -libp2p_rcmgr_memory_allocations_allowed_total -libp2p_rcmgr_memory_allocations_blocked_total -libp2p_rcmgr_peer_blocked_total -libp2p_rcmgr_peers_allowed_total process_cpu_seconds_total process_max_fds process_open_fds diff --git a/test/sharness/t0139-swarm-rcmgr.sh b/test/sharness/t0139-swarm-rcmgr.sh index 89586300476..24b9ebf6544 100755 --- a/test/sharness/t0139-swarm-rcmgr.sh +++ b/test/sharness/t0139-swarm-rcmgr.sh @@ -6,6 +6,25 @@ test_description="Test ipfs swarm ResourceMgr config and commands" test_init_ipfs +# test correct behavior when resource manager is disabled (default behavior) +test_launch_ipfs_daemon + +test_expect_success 'Swarm limit should fail since RM is disabled' ' + test_expect_code 1 ipfs swarm limit system 2> actual && + test_should_contain "missing ResourceMgr" actual +' + +test_expect_success 'Swarm stats should fail since RM is disabled' ' + test_expect_code 1 ipfs swarm stats all 2> actual && + test_should_contain "missing ResourceMgr" actual +' + +test_kill_ipfs_daemon + +test_expect_success 'Enable resource manager' ' + ipfs config --bool Swarm.ResourceMgr.Enabled true +' + # swarm limit|stats should fail in offline mode test_expect_success 'disconnected: swarm limit requires running daemon' ' @@ -127,23 +146,4 @@ test_expect_success 'Set limit for peer scope with an invalid peer ID' ' test_kill_ipfs_daemon -# test correct behavior when resource manager is disabled -test_expect_success 'Disable resource manager' ' - ipfs config --bool Swarm.ResourceMgr.Enabled false -' - -test_launch_ipfs_daemon - -test_expect_success 'Swarm limit should fail since RM is disabled' ' - test_expect_code 1 ipfs swarm limit system 2> actual && - test_should_contain "missing ResourceMgr" actual -' - -test_expect_success 'Swarm stats should fail since RM is disabled' ' - test_expect_code 1 ipfs swarm stats all 2> actual && - test_should_contain "missing ResourceMgr" actual -' - -test_kill_ipfs_daemon - test_done From a1a729c5cdcfbd1f75f7655ef9572a2e1ef28805 Mon Sep 17 00:00:00 2001 From: siiky Date: Fri, 3 Jun 2022 13:15:57 +0100 Subject: [PATCH 409/414] docs: fix typo in the `swarm/peering` help text (cherry picked from commit 0a01574ff7860eedfc8dce9354da1780ce0ba91e) --- core/commands/swarm.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/core/commands/swarm.go b/core/commands/swarm.go index f904ed67e19..fcf2a50340e 100644 --- a/core/commands/swarm.go +++ b/core/commands/swarm.go @@ -79,7 +79,7 @@ var swarmPeeringCmd = &cmds.Command{ Tagline: "Modify the peering subsystem.", ShortDescription: ` 'ipfs swarm peering' manages the peering subsystem. -Peers in the peering subsystem is maintained to be connected, reconnected +Peers in the peering subsystem are maintained to be connected, reconnected on disconnect with a back-off. The changes are not saved to the config. `, From 7449a4b9189fa62a36a80121a2927a5570d623bc Mon Sep 17 00:00:00 2001 From: Gus Eggert Date: Fri, 3 Jun 2022 16:56:30 -0400 Subject: [PATCH 410/414] feat: upgrade to go-libp2p-kad-dht@v0.16.0 (#9005) * feat: upgrade to go-libp2p-kad-dht@v0.16.0 * rename "cid format --codec" to "cid format --mc" * refactor(test): from --codec to --mc Co-authored-by: Marcin Rataj (cherry picked from commit 8d7ed002dfd814651edacc0b11581d5571376ffb) --- CHANGELOG.md | 5 ++ core/commands/cid.go | 22 ++--- go.mod | 50 +++++------ go.sum | 102 +++++++++++++--------- test/sharness/t0087-repo-robust-gc.sh | 2 +- test/sharness/t0114-gateway-subdomains.sh | 4 +- test/sharness/t0160-resolve.sh | 4 +- test/sharness/t0290-cid.sh | 22 ++++- test/sharness/t0310-tracing.sh | 2 +- tracing/tracing.go | 5 +- 10 files changed, 130 insertions(+), 88 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 1c28aa80597..66c966b994e 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -53,6 +53,11 @@ Below is an outline of all that is in this release, so you get a sense of all th - Now lists codecs from [go-multicodec](https://github.com/multiformats/go-multicodec) library. - `ipfs cid codecs --supported` can be passed to only show codecs supported in various go-ipfs commands. +#### `ipfs cid format` command +- `--codec` was removed and replaced with `--mc` to ensure existing users are aware of the following changes: + - `--mc protobuf` now correctly points to code `0x50` (was `0x70`, which is `dab-pg`) + - `--mc cbor` now correctly points to code `0x51` (was `0x71`, which is `dag-cbor`) + #### `Swarm` configuration - Daemon will refuse to start if long-deprecated RelayV1 config key `Swarm.EnableAutoRelay` or `Swarm.DisableRelay` is set to `true`. - If `Swarm.Transports.Network.Relay` is disabled, then `Swarm.RelayService` and `Swarm.RelayClient` are also disabled (unless they have been explicitly enabled). diff --git a/core/commands/cid.go b/core/commands/cid.go index 64508609094..f988d1c8c47 100644 --- a/core/commands/cid.go +++ b/core/commands/cid.go @@ -11,8 +11,9 @@ import ( cidutil "github.com/ipfs/go-cidutil" cmds "github.com/ipfs/go-ipfs-cmds" verifcid "github.com/ipfs/go-verifcid" - "github.com/ipld/go-ipld-prime/multicodec" + ipldmulticodec "github.com/ipld/go-ipld-prime/multicodec" mbase "github.com/multiformats/go-multibase" + "github.com/multiformats/go-multicodec" mc "github.com/multiformats/go-multicodec" mhash "github.com/multiformats/go-multihash" ) @@ -34,7 +35,7 @@ var CidCmd = &cmds.Command{ const ( cidFormatOptionName = "f" cidVerisonOptionName = "v" - cidCodecOptionName = "codec" + cidCodecOptionName = "mc" cidMultibaseOptionName = "b" ) @@ -53,7 +54,7 @@ The optional format string is a printf style format string: Options: []cmds.Option{ cmds.StringOption(cidFormatOptionName, "Printf style format string.").WithDefault("%s"), cmds.StringOption(cidVerisonOptionName, "CID version to convert to."), - cmds.StringOption(cidCodecOptionName, "CID codec to convert to."), + cmds.StringOption(cidCodecOptionName, "CID multicodec to convert to."), cmds.StringOption(cidMultibaseOptionName, "Multibase to display CID in."), }, Run: func(req *cmds.Request, resp cmds.ResponseEmitter, env cmds.Environment) error { @@ -70,11 +71,12 @@ The optional format string is a printf style format string: opts.fmtStr = fmtStr if codecStr != "" { - codec, ok := cid.Codecs[codecStr] - if !ok { - return fmt.Errorf("unknown IPLD codec: %q", codecStr) + var codec multicodec.Code + err := codec.Set(codecStr) + if err != nil { + return err } - opts.newCodec = codec + opts.newCodec = uint64(codec) } // otherwise, leave it as 0 (not a valid IPLD codec) switch verStr { @@ -311,7 +313,7 @@ const ( var codecsCmd = &cmds.Command{ Helptext: cmds.HelpText{ - Tagline: "List available CID codecs.", + Tagline: "List available CID multicodecs.", ShortDescription: ` 'ipfs cid codecs' relies on https://github.com/multiformats/go-multicodec `, @@ -324,10 +326,10 @@ var codecsCmd = &cmds.Command{ listSupported, _ := req.Options[codecsSupportedOptionName].(bool) supportedCodecs := make(map[uint64]struct{}) if listSupported { - for _, code := range multicodec.ListEncoders() { + for _, code := range ipldmulticodec.ListEncoders() { supportedCodecs[code] = struct{}{} } - for _, code := range multicodec.ListDecoders() { + for _, code := range ipldmulticodec.ListDecoders() { supportedCodecs[code] = struct{}{} } // add libp2p-key diff --git a/go.mod b/go.mod index cd56046a0ad..cb914b45571 100644 --- a/go.mod +++ b/go.mod @@ -4,7 +4,7 @@ require ( bazil.org/fuse v0.0.0-20200117225306-7b5117fecadc contrib.go.opencensus.io/exporter/prometheus v0.4.0 github.com/blang/semver/v4 v4.0.0 - github.com/cenkalti/backoff/v4 v4.1.2 + github.com/cenkalti/backoff/v4 v4.1.3 github.com/ceramicnetwork/go-dag-jose v0.1.0 github.com/cespare/xxhash v1.1.0 github.com/cheggaaa/pb v1.0.29 @@ -18,8 +18,8 @@ require ( github.com/ipfs/go-bitswap v0.6.0 github.com/ipfs/go-block-format v0.0.3 github.com/ipfs/go-blockservice v0.3.0 - github.com/ipfs/go-cid v0.1.0 - github.com/ipfs/go-cidutil v0.0.2 + github.com/ipfs/go-cid v0.2.0 + github.com/ipfs/go-cidutil v0.1.0 github.com/ipfs/go-datastore v0.5.1 github.com/ipfs/go-detect-race v0.0.1 github.com/ipfs/go-ds-badger v0.3.0 @@ -72,7 +72,7 @@ require ( github.com/libp2p/go-libp2p-core v0.15.1 github.com/libp2p/go-libp2p-discovery v0.6.0 github.com/libp2p/go-libp2p-http v0.2.1 - github.com/libp2p/go-libp2p-kad-dht v0.15.0 + github.com/libp2p/go-libp2p-kad-dht v0.16.0 github.com/libp2p/go-libp2p-kbucket v0.4.7 github.com/libp2p/go-libp2p-loggables v0.1.0 github.com/libp2p/go-libp2p-mplex v0.7.0 @@ -108,21 +108,21 @@ require ( github.com/whyrusleeping/go-sysinfo v0.0.0-20190219211824-4a357d4b90b1 github.com/whyrusleeping/multiaddr-filter v0.0.0-20160516205228-e903e4adabd7 go.opencensus.io v0.23.0 - go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.31.0 - go.opentelemetry.io/otel v1.6.3 - go.opentelemetry.io/otel/exporters/jaeger v1.6.3 - go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.6.3 - go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp v1.6.3 - go.opentelemetry.io/otel/exporters/stdout/stdouttrace v1.6.3 - go.opentelemetry.io/otel/exporters/zipkin v1.6.3 - go.opentelemetry.io/otel/sdk v1.6.3 - go.opentelemetry.io/otel/trace v1.6.3 + go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.32.0 + go.opentelemetry.io/otel v1.7.0 + go.opentelemetry.io/otel/exporters/jaeger v1.7.0 + go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.7.0 + go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp v1.7.0 + go.opentelemetry.io/otel/exporters/stdout/stdouttrace v1.7.0 + go.opentelemetry.io/otel/exporters/zipkin v1.7.0 + go.opentelemetry.io/otel/sdk v1.7.0 + go.opentelemetry.io/otel/trace v1.7.0 go.uber.org/dig v1.14.0 go.uber.org/fx v1.16.0 go.uber.org/zap v1.21.0 - golang.org/x/crypto v0.0.0-20220411220226-7b82a4e95df4 + golang.org/x/crypto v0.0.0-20220518034528-6f7dac969898 golang.org/x/sync v0.0.0-20210220032951-036812b2e83c - golang.org/x/sys v0.0.0-20220412211240-33da011f77ad + golang.org/x/sys v0.0.0-20220517195934-5e4e11fc645e ) require ( @@ -137,7 +137,7 @@ require ( github.com/alecthomas/units v0.0.0-20210927113745-59d0afb8317a // indirect github.com/alexbrainman/goissue34681 v0.0.0-20191006012335-3fc7a47baff5 // indirect github.com/beorn7/perks v1.0.1 // indirect - github.com/btcsuite/btcd v0.22.0-beta // indirect + github.com/btcsuite/btcd v0.22.1 // indirect github.com/cenkalti/backoff v2.2.1+incompatible // indirect github.com/cespare/xxhash/v2 v2.1.2 // indirect github.com/cheekybits/genny v1.0.0 // indirect @@ -150,7 +150,7 @@ require ( github.com/dgraph-io/ristretto v0.0.2 // indirect github.com/docker/go-units v0.4.0 // indirect github.com/elastic/gosigar v0.14.2 // indirect - github.com/felixge/httpsnoop v1.0.2 // indirect + github.com/felixge/httpsnoop v1.0.3 // indirect github.com/flynn/noise v1.0.0 // indirect github.com/francoispqt/gojay v1.2.13 // indirect github.com/go-kit/log v0.2.0 // indirect @@ -168,7 +168,7 @@ require ( github.com/gorilla/websocket v1.5.0 // indirect github.com/grpc-ecosystem/grpc-gateway/v2 v2.7.0 // indirect github.com/hannahhoward/go-pubsub v0.0.0-20200423002714-8d62886cc36e // indirect - github.com/hashicorp/errwrap v1.0.0 // indirect + github.com/hashicorp/errwrap v1.1.0 // indirect github.com/hashicorp/golang-lru v0.5.4 // indirect github.com/huin/goupnp v1.0.3 // indirect github.com/ipfs/bbloom v0.0.4 // indirect @@ -192,7 +192,7 @@ require ( github.com/libp2p/go-libp2p-nat v0.1.0 // indirect github.com/libp2p/go-libp2p-pnet v0.2.0 // indirect github.com/libp2p/go-libp2p-transport-upgrader v0.7.1 // indirect - github.com/libp2p/go-libp2p-xor v0.0.0-20210714161855-5c005aca55db // indirect + github.com/libp2p/go-libp2p-xor v0.1.0 // indirect github.com/libp2p/go-mplex v0.7.0 // indirect github.com/libp2p/go-msgio v0.2.0 // indirect github.com/libp2p/go-nat v0.1.0 // indirect @@ -248,16 +248,16 @@ require ( github.com/whyrusleeping/go-keyspace v0.0.0-20160322163242-5b898ac5add1 // indirect github.com/whyrusleeping/mdns v0.0.0-20190826153040-b9b60ed33aa9 // indirect github.com/whyrusleeping/timecache v0.0.0-20160911033111-cfcb2f1abfee // indirect - go.opentelemetry.io/otel/exporters/otlp/internal/retry v1.6.3 // indirect - go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.6.3 // indirect - go.opentelemetry.io/otel/metric v0.28.0 // indirect - go.opentelemetry.io/proto/otlp v0.15.0 // indirect + go.opentelemetry.io/otel/exporters/otlp/internal/retry v1.7.0 // indirect + go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.7.0 // indirect + go.opentelemetry.io/otel/metric v0.30.0 // indirect + go.opentelemetry.io/proto/otlp v0.16.0 // indirect go.uber.org/atomic v1.9.0 // indirect go.uber.org/multierr v1.8.0 // indirect go4.org v0.0.0-20200411211856-f5505b9728dd // indirect golang.org/x/exp v0.0.0-20210615023648-acb5c1269671 // indirect golang.org/x/mod v0.6.0-dev.0.20220106191415-9b9b3d81d5e3 // indirect - golang.org/x/net v0.0.0-20220418201149-a630d4f3e7a2 // indirect + golang.org/x/net v0.0.0-20220517181318-183a9ca12b87 // indirect golang.org/x/oauth2 v0.0.0-20220223155221-ee480838109b // indirect golang.org/x/term v0.0.0-20210927222741-03fcf44c2211 // indirect golang.org/x/text v0.3.7 // indirect @@ -265,7 +265,7 @@ require ( golang.org/x/xerrors v0.0.0-20220411194840-2f41105eb62f // indirect google.golang.org/appengine v1.6.6 // indirect google.golang.org/genproto v0.0.0-20211118181313-81c1377c94b1 // indirect - google.golang.org/grpc v1.45.0 // indirect + google.golang.org/grpc v1.46.0 // indirect google.golang.org/protobuf v1.28.0 // indirect gopkg.in/square/go-jose.v2 v2.5.1 // indirect gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7 // indirect diff --git a/go.sum b/go.sum index a74cb32907e..1d8452a801d 100644 --- a/go.sum +++ b/go.sum @@ -103,8 +103,11 @@ github.com/btcsuite/btcd v0.0.0-20190605094302-a0d1e3e36d50/go.mod h1:3J08xEfcug github.com/btcsuite/btcd v0.0.0-20190824003749-130ea5bddde3/go.mod h1:3J08xEfcugPacsc34/LKRU2yO7YmuT8yt28J8k2+rrI= github.com/btcsuite/btcd v0.20.1-beta/go.mod h1:wVuoA8VJLEcwgqHBwHmzLRazpKxTv13Px/pDuV7OomQ= github.com/btcsuite/btcd v0.21.0-beta/go.mod h1:ZSWyehm27aAuS9bvkATT+Xte3hjHZ+MRgMY/8NJ7K94= -github.com/btcsuite/btcd v0.22.0-beta h1:LTDpDKUM5EeOFBPM8IXpinEcmZ6FWfNZbE3lfrfdnWo= github.com/btcsuite/btcd v0.22.0-beta/go.mod h1:9n5ntfhhHQBIhUvlhDvD3Qg6fRUj4jkN0VB8L8svzOA= +github.com/btcsuite/btcd v0.22.1 h1:CnwP9LM/M9xuRrGSCGeMVs9iv09uMqwsVX7EeIpgV2c= +github.com/btcsuite/btcd v0.22.1/go.mod h1:wqgTSL29+50LRkmOVknEdmt8ZojIzhuWvgu/iptuN7Y= +github.com/btcsuite/btcd/chaincfg/chainhash v1.0.1 h1:q0rUy8C/TYNBQS1+CGKw68tLOFYSNEs0TFnxxnS9+4U= +github.com/btcsuite/btcd/chaincfg/chainhash v1.0.1/go.mod h1:7SFka0XMvUgj3hfZtydOrQY2mwhPclbT2snogU7SQQc= github.com/btcsuite/btclog v0.0.0-20170628155309-84c8d2346e9f/go.mod h1:TdznJufoqS23FtqVCzL0ZqgP5MqXbb4fg/WgDys70nA= github.com/btcsuite/btcutil v0.0.0-20190207003914-4c204d697803/go.mod h1:+5NJ2+qvTyV9exUAL/rxXi3DcLg2Ts+ymUAY5y4NvMg= github.com/btcsuite/btcutil v0.0.0-20190425235716-9e5f4b9a998d/go.mod h1:+5NJ2+qvTyV9exUAL/rxXi3DcLg2Ts+ymUAY5y4NvMg= @@ -121,8 +124,8 @@ github.com/buger/jsonparser v0.0.0-20181115193947-bf1c66bbce23/go.mod h1:bbYlZJ7 github.com/casbin/casbin/v2 v2.1.2/go.mod h1:YcPU1XXisHhLzuxH9coDNf2FbKpjGlbCg3n9yuLkIJQ= github.com/cenkalti/backoff v2.2.1+incompatible h1:tNowT99t7UNflLxfYYSlKYsBpXdEet03Pg2g16Swow4= github.com/cenkalti/backoff v2.2.1+incompatible/go.mod h1:90ReRw6GdpyfrHakVjL/QHaoyV4aDUVVkXQJJJ3NXXM= -github.com/cenkalti/backoff/v4 v4.1.2 h1:6Yo7N8UP2K6LWZnW94DLVSSrbobcWdVzAYOisuDPIFo= -github.com/cenkalti/backoff/v4 v4.1.2/go.mod h1:scbssz8iZGpm3xbr14ovlUdkxfGXNInqkPWOWmG2CLw= +github.com/cenkalti/backoff/v4 v4.1.3 h1:cFAlzYUlVYDysBEH2T5hyJZMh3+5+WCBvSnK6Q8UtC4= +github.com/cenkalti/backoff/v4 v4.1.3/go.mod h1:scbssz8iZGpm3xbr14ovlUdkxfGXNInqkPWOWmG2CLw= github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU= github.com/ceramicnetwork/go-dag-jose v0.1.0 h1:yJ/HVlfKpnD3LdYP03AHyTvbm3BpPiz2oZiOeReJRdU= github.com/ceramicnetwork/go-dag-jose v0.1.0/go.mod h1:qYA1nYt0X8u4XoMAVoOV3upUVKtrxy/I670Dg5F0wjI= @@ -148,6 +151,7 @@ github.com/cncf/udpa/go v0.0.0-20210930031921-04548b0d99d4/go.mod h1:6pvJx4me5XP github.com/cncf/xds/go v0.0.0-20210312221358-fbca930ec8ed/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs= github.com/cncf/xds/go v0.0.0-20210805033703-aa0b78936158/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs= github.com/cncf/xds/go v0.0.0-20210922020428-25de7278fc84/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs= +github.com/cncf/xds/go v0.0.0-20211001041855-01bcc9b48dfe/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs= github.com/cncf/xds/go v0.0.0-20211011173535-cb28da3451f1/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs= github.com/cockroachdb/datadriven v0.0.0-20190809214429-80d97fb3cbaa/go.mod h1:zn76sxSg3SzpJ0PPJaLDCu+Bu0Lg3sKTORVIj19EIF8= github.com/codahale/hdrhistogram v0.0.0-20161010025455-3a0bb77429bd/go.mod h1:sE/e/2PUdi/liOCUjSTXgM1o87ZssimdTWN964YiIeI= @@ -220,14 +224,16 @@ github.com/envoyproxy/go-control-plane v0.9.4/go.mod h1:6rpuAdCZL397s3pYoYcLgu1m github.com/envoyproxy/go-control-plane v0.9.9-0.20201210154907-fd9021fe5dad/go.mod h1:cXg6YxExXjJnVBQHBLXeUAgxn2UodCpnH306RInaBQk= github.com/envoyproxy/go-control-plane v0.9.9-0.20210512163311-63b5d3c536b0/go.mod h1:hliV/p42l8fGbc6Y9bQ70uLwIvmJyVE5k4iMKlh8wCQ= github.com/envoyproxy/go-control-plane v0.9.10-0.20210907150352-cf90f659a021/go.mod h1:AFq3mo9L8Lqqiid3OhADV3RfLJnjiw63cSpi+fDTRC0= +github.com/envoyproxy/go-control-plane v0.10.2-0.20220325020618-49ff273808a1/go.mod h1:KJwIaB5Mv44NWtYuAOFCVOjcI94vtpEz2JU/D2v6IjE= github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c= github.com/facebookgo/atomicfile v0.0.0-20151019160806-2de1f203e7d5 h1:BBso6MBKW8ncyZLv37o+KNyy0HrrHgfnOaGQC2qvN+A= github.com/facebookgo/atomicfile v0.0.0-20151019160806-2de1f203e7d5/go.mod h1:JpoxHjuQauoxiFMl1ie8Xc/7TfLuMZ5eOCONd1sUBHg= github.com/fatih/color v1.7.0/go.mod h1:Zm6kSWBoL9eyXnKyktHP6abPY2pDugNf5KwzbycvMj4= github.com/fatih/color v1.9.0 h1:8xPHl4/q1VyqGIPif1F+1V3Y3lSmrq01EabUW3CoW5s= github.com/fatih/color v1.9.0/go.mod h1:eQcE1qtQxscV5RaZvpXrrb8Drkc3/DdQ+uUYCNjL+zU= -github.com/felixge/httpsnoop v1.0.2 h1:+nS9g82KMXccJ/wp0zyRW9ZBHFETmMGtkk+2CTTrW4o= github.com/felixge/httpsnoop v1.0.2/go.mod h1:m8KPJKqk1gH5J9DgRY2ASl2lWCfGKXixSwevea8zH2U= +github.com/felixge/httpsnoop v1.0.3 h1:s/nj+GCswXYzN5v2DpNMuMQYe+0DDwt5WVCU6CWBdXk= +github.com/felixge/httpsnoop v1.0.3/go.mod h1:m8KPJKqk1gH5J9DgRY2ASl2lWCfGKXixSwevea8zH2U= github.com/flynn/go-shlex v0.0.0-20150515145356-3f9db97f8568/go.mod h1:xEzjJPgXI435gkrCt3MPfRiAkVrwSbHsst4LCFVfpJc= github.com/flynn/noise v0.0.0-20180327030543-2492fe189ae6/go.mod h1:1i71OnUq3iUe1ma7Lr6yG6/rjvM3emb6yoL7xLFzcVQ= github.com/flynn/noise v1.0.0 h1:DlTHqmzmvcEiKj+4RYo/imoswx/4r6iBlCMfVtrMXpQ= @@ -401,8 +407,9 @@ github.com/hannahhoward/go-pubsub v0.0.0-20200423002714-8d62886cc36e h1:3YKHER4n github.com/hannahhoward/go-pubsub v0.0.0-20200423002714-8d62886cc36e/go.mod h1:I8h3MITA53gN9OnWGCgaMa0JWVRdXthWw4M3CPM54OY= github.com/hashicorp/consul/api v1.3.0/go.mod h1:MmDNSzIMUjNpY/mQ398R4bk2FnqQLoPndWW5VkKPlCE= github.com/hashicorp/consul/sdk v0.3.0/go.mod h1:VKf9jXwCTEY1QZP2MOLRhb5i/I/ssyNV1vwHyQBF0x8= -github.com/hashicorp/errwrap v1.0.0 h1:hLrqtEDnRye3+sgx6z4qVLNuviH3MR5aQ0ykNJa/UYA= github.com/hashicorp/errwrap v1.0.0/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4= +github.com/hashicorp/errwrap v1.1.0 h1:OxrOeh75EUXMY8TBjag2fzXGZ40LB6IKw45YeGUDY2I= +github.com/hashicorp/errwrap v1.1.0/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4= github.com/hashicorp/go-cleanhttp v0.5.1/go.mod h1:JpRdi6/HCYpAwUzNwuwqhbovhLtngrth3wmdIIUrZ80= github.com/hashicorp/go-immutable-radix v1.0.0/go.mod h1:0y9vanUI8NX6FsYoO3zeMjhV/C5i9g4Q3DwcSNZ4P60= github.com/hashicorp/go-msgpack v0.5.3/go.mod h1:ahLV/dePpqEmjfWmKiqvPkv/twdG7iPBM1vqhUKIvfM= @@ -467,10 +474,12 @@ github.com/ipfs/go-cid v0.0.4/go.mod h1:4LLaPOQwmk5z9LBgQnpkivrx8BJjUyGwTXCd5Xfj github.com/ipfs/go-cid v0.0.5/go.mod h1:plgt+Y5MnOey4vO4UlUazGqdbEXuFYitED67FexhXog= github.com/ipfs/go-cid v0.0.6/go.mod h1:6Ux9z5e+HpkQdckYoX1PG/6xqKspzlEIR5SDmgqgC/I= github.com/ipfs/go-cid v0.0.7/go.mod h1:6Ux9z5e+HpkQdckYoX1PG/6xqKspzlEIR5SDmgqgC/I= -github.com/ipfs/go-cid v0.1.0 h1:YN33LQulcRHjfom/i25yoOZR4Telp1Hr/2RU3d0PnC0= github.com/ipfs/go-cid v0.1.0/go.mod h1:rH5/Xv83Rfy8Rw6xG+id3DYAMUVmem1MowoKwdXmN2o= -github.com/ipfs/go-cidutil v0.0.2 h1:CNOboQf1t7Qp0nuNh8QMmhJs0+Q//bRL1axtCnIB1Yo= +github.com/ipfs/go-cid v0.2.0 h1:01JTiihFq9en9Vz0lc0VDWvZe/uBonGpzo4THP0vcQ0= +github.com/ipfs/go-cid v0.2.0/go.mod h1:P+HXFDF4CVhaVayiEb4wkAy7zBHxBwsJyt0Y5U6MLro= github.com/ipfs/go-cidutil v0.0.2/go.mod h1:ewllrvrxG6AMYStla3GD7Cqn+XYSLqjK0vc+086tB6s= +github.com/ipfs/go-cidutil v0.1.0 h1:RW5hO7Vcf16dplUU60Hs0AKDkQAVPVplr7lk97CFL+Q= +github.com/ipfs/go-cidutil v0.1.0/go.mod h1:e7OEVBMIv9JaOxt9zaGEmAoSlXW9jdFZ5lP/0PwcfpA= github.com/ipfs/go-datastore v0.0.1/go.mod h1:d4KVXhMt913cLBEI/PXAy6ko+W7e9AhyAKBGh803qeE= github.com/ipfs/go-datastore v0.0.5/go.mod h1:d4KVXhMt913cLBEI/PXAy6ko+W7e9AhyAKBGh803qeE= github.com/ipfs/go-datastore v0.1.0/go.mod h1:d4KVXhMt913cLBEI/PXAy6ko+W7e9AhyAKBGh803qeE= @@ -766,6 +775,7 @@ github.com/libp2p/go-libp2p v0.13.0/go.mod h1:pM0beYdACRfHO1WcJlp65WXyG2A6NqYM+t github.com/libp2p/go-libp2p v0.14.3/go.mod h1:d12V4PdKbpL0T1/gsUNN8DfgMuRPDX8bS2QxCZlwRH0= github.com/libp2p/go-libp2p v0.14.4/go.mod h1:EIRU0Of4J5S8rkockZM7eJp2S0UrCyi55m2kJVru3rM= github.com/libp2p/go-libp2p v0.16.0/go.mod h1:ump42BsirwAWxKzsCiFnTtN1Yc+DuPu76fyMX364/O4= +github.com/libp2p/go-libp2p v0.18.0/go.mod h1:+veaZ9z1SZQhmc5PW78jvnnxZ89Mgvmh4cggO11ETmw= github.com/libp2p/go-libp2p v0.19.3 h1:LqjvuBWdyYSqvkH4VVYxA78Fkphzg2Pq86VMnilqgkw= github.com/libp2p/go-libp2p v0.19.3/go.mod h1:AGlPVLjh0+6jvEtf+a2gZEux7yHJrYXnG9IC7wcQ2NY= github.com/libp2p/go-libp2p-asn-util v0.0.0-20200825225859-85005c6cf052/go.mod h1:nRMRTab+kZuk0LnKZpxhOVH/ndsdr2Nr//Zltc/vwgo= @@ -849,8 +859,9 @@ github.com/libp2p/go-libp2p-interface-connmgr v0.0.1/go.mod h1:GarlRLH0LdeWcLnYM github.com/libp2p/go-libp2p-interface-connmgr v0.0.4/go.mod h1:GarlRLH0LdeWcLnYM/SaBykKFl9U5JFnbBGruAk/D5k= github.com/libp2p/go-libp2p-interface-connmgr v0.0.5/go.mod h1:GarlRLH0LdeWcLnYM/SaBykKFl9U5JFnbBGruAk/D5k= github.com/libp2p/go-libp2p-interface-pnet v0.0.1/go.mod h1:el9jHpQAXK5dnTpKA4yfCNBZXvrzdOU75zz+C6ryp3k= -github.com/libp2p/go-libp2p-kad-dht v0.15.0 h1:Ke+Oj78gX5UDXnA6HBdrgvi+fStJxgYTDa51U0TsCLo= github.com/libp2p/go-libp2p-kad-dht v0.15.0/go.mod h1:rZtPxYu1TnHHz6n1RggdGrxUX/tA1C2/Wiw3ZMUDrU0= +github.com/libp2p/go-libp2p-kad-dht v0.16.0 h1:epVRYl3O8dn47uV3wVD2+IobEvBPapEMVj4sWlvwQHU= +github.com/libp2p/go-libp2p-kad-dht v0.16.0/go.mod h1:YYLlG8AbpWVGbI/zFeSbiGT0n0lluH7IG0sHeounyWA= github.com/libp2p/go-libp2p-kbucket v0.3.1/go.mod h1:oyjT5O7tS9CQurok++ERgc46YLwEpuGoFq9ubvoUOio= github.com/libp2p/go-libp2p-kbucket v0.4.7 h1:spZAcgxifvFZHBD8tErvppbnNiKA5uokDu3CV7axu70= github.com/libp2p/go-libp2p-kbucket v0.4.7/go.mod h1:XyVo99AfQH0foSf176k4jY1xUJ2+jUJIZCSDm7r2YKk= @@ -867,6 +878,7 @@ github.com/libp2p/go-libp2p-mplex v0.3.0/go.mod h1:l9QWxRbbb5/hQMECEb908GbS9Sm2U github.com/libp2p/go-libp2p-mplex v0.4.0/go.mod h1:yCyWJE2sc6TBTnFpjvLuEJgTSw/u+MamvzILKdX7asw= github.com/libp2p/go-libp2p-mplex v0.4.1/go.mod h1:cmy+3GfqfM1PceHTLL7zQzAAYaryDu6iPSC+CIb094g= github.com/libp2p/go-libp2p-mplex v0.5.0/go.mod h1:eLImPJLkj3iG5t5lq68w3Vm5NAQ5BcKwrrb2VmOYb3M= +github.com/libp2p/go-libp2p-mplex v0.6.0/go.mod h1:i3usuPrBbh9FD2fLZjGpotyNkwr42KStYZQY7BeTiu4= github.com/libp2p/go-libp2p-mplex v0.7.0 h1:ONTTvHIUaFCwyPO4FRkpe4OFQJq1bDkWQLbhWiD1A44= github.com/libp2p/go-libp2p-mplex v0.7.0/go.mod h1:SeeXUXh7ZkfxnmsepnFgMPEhfEyACujuTM9k1TkErpc= github.com/libp2p/go-libp2p-nat v0.0.4/go.mod h1:N9Js/zVtAXqaeT99cXgTV9e75KpnWCvVOiGzlcHmBbY= @@ -915,6 +927,7 @@ github.com/libp2p/go-libp2p-quic-transport v0.11.2/go.mod h1:wlanzKtIh6pHrq+0U3p github.com/libp2p/go-libp2p-quic-transport v0.13.0/go.mod h1:39/ZWJ1TW/jx1iFkKzzUg00W6tDJh73FC0xYudjr7Hc= github.com/libp2p/go-libp2p-quic-transport v0.15.0/go.mod h1:wv4uGwjcqe8Mhjj7N/Ic0aKjA+/10UnMlSzLO0yRpYQ= github.com/libp2p/go-libp2p-quic-transport v0.16.0/go.mod h1:1BXjVMzr+w7EkPfiHkKnwsWjPjtfaNT0q8RS3tGDvEQ= +github.com/libp2p/go-libp2p-quic-transport v0.16.1/go.mod h1:1BXjVMzr+w7EkPfiHkKnwsWjPjtfaNT0q8RS3tGDvEQ= github.com/libp2p/go-libp2p-quic-transport v0.17.0 h1:yFh4Gf5MlToAYLuw/dRvuzYd1EnE2pX3Lq1N6KDiWRQ= github.com/libp2p/go-libp2p-quic-transport v0.17.0/go.mod h1:x4pw61P3/GRCcSLypcQJE/Q2+E9f4X+5aRcZLXf20LM= github.com/libp2p/go-libp2p-record v0.0.1/go.mod h1:grzqg263Rug/sRex85QrDOLntdFAymLDLm7lxMgU79Q= @@ -922,6 +935,7 @@ github.com/libp2p/go-libp2p-record v0.1.0/go.mod h1:ujNc8iuE5dlKWVy6wuL6dd58t0n7 github.com/libp2p/go-libp2p-record v0.1.2/go.mod h1:pal0eNcT5nqZaTV7UGhqeGqxFgGdsU/9W//C8dqjQDk= github.com/libp2p/go-libp2p-record v0.1.3 h1:R27hoScIhQf/A8XJZ8lYpnqh9LatJ5YbHs28kCIfql0= github.com/libp2p/go-libp2p-record v0.1.3/go.mod h1:yNUff/adKIfPnYQXgp6FQmNu3gLJ6EMg7+/vv2+9pY4= +github.com/libp2p/go-libp2p-resource-manager v0.1.5/go.mod h1:wJPNjeE4XQlxeidwqVY5G6DLOKqFK33u2n8blpl0I6Y= github.com/libp2p/go-libp2p-resource-manager v0.2.1/go.mod h1:K+eCkiapf+ey/LADO4TaMpMTP9/Qde/uLlrnRqV4PLQ= github.com/libp2p/go-libp2p-resource-manager v0.3.0 h1:2+cYxUNi33tcydsVLt6K5Fv2E3OTiVeafltecAj15E0= github.com/libp2p/go-libp2p-resource-manager v0.3.0/go.mod h1:K+eCkiapf+ey/LADO4TaMpMTP9/Qde/uLlrnRqV4PLQ= @@ -959,6 +973,7 @@ github.com/libp2p/go-libp2p-testing v0.4.0/go.mod h1:Q+PFXYoiYFN5CAEG2w3gLPEzotl github.com/libp2p/go-libp2p-testing v0.4.2/go.mod h1:Q+PFXYoiYFN5CAEG2w3gLPEzotlKsNSbKQ/lImlOWF0= github.com/libp2p/go-libp2p-testing v0.5.0/go.mod h1:QBk8fqIL1XNcno/l3/hhaIEn4aLRijpYOR+zVjjlh+A= github.com/libp2p/go-libp2p-testing v0.7.0/go.mod h1:OLbdn9DbgdMwv00v+tlp1l3oe2Cl+FAjoWIA2pa0X6E= +github.com/libp2p/go-libp2p-testing v0.8.0/go.mod h1:gRdsNxQSxAZowTgcLY7CC33xPmleZzoBpqSYbWenqPc= github.com/libp2p/go-libp2p-testing v0.9.0/go.mod h1:Td7kbdkWqYTJYQGTwzlgXwaqldraIanyjuRiAbK/XQU= github.com/libp2p/go-libp2p-testing v0.9.2 h1:dCpODRtRaDZKF8HXT9qqqgON+OMEB423Knrgeod8j84= github.com/libp2p/go-libp2p-testing v0.9.2/go.mod h1:Td7kbdkWqYTJYQGTwzlgXwaqldraIanyjuRiAbK/XQU= @@ -981,8 +996,9 @@ github.com/libp2p/go-libp2p-transport-upgrader v0.5.0/go.mod h1:Rc+XODlB3yce7dvF github.com/libp2p/go-libp2p-transport-upgrader v0.7.0/go.mod h1:GIR2aTRp1J5yjVlkUoFqMkdobfob6RnAwYg/RZPhrzg= github.com/libp2p/go-libp2p-transport-upgrader v0.7.1 h1:MSMe+tUfxpC9GArTz7a4G5zQKQgGh00Vio87d3j3xIg= github.com/libp2p/go-libp2p-transport-upgrader v0.7.1/go.mod h1:GIR2aTRp1J5yjVlkUoFqMkdobfob6RnAwYg/RZPhrzg= -github.com/libp2p/go-libp2p-xor v0.0.0-20210714161855-5c005aca55db h1:EDoDKW8ZAHd6SIDeo+thU51PyQppqLYkBxx0ObvFj/w= github.com/libp2p/go-libp2p-xor v0.0.0-20210714161855-5c005aca55db/go.mod h1:LSTM5yRnjGZbWNTA/hRwq2gGFrvRIbQJscoIL/u6InY= +github.com/libp2p/go-libp2p-xor v0.1.0 h1:hhQwT4uGrBcuAkUGXADuPltalOdpf9aag9kaYNT2tLA= +github.com/libp2p/go-libp2p-xor v0.1.0/go.mod h1:LSTM5yRnjGZbWNTA/hRwq2gGFrvRIbQJscoIL/u6InY= github.com/libp2p/go-libp2p-yamux v0.1.2/go.mod h1:xUoV/RmYkg6BW/qGxA9XJyg+HzXFYkeXbnhjmnYzKp8= github.com/libp2p/go-libp2p-yamux v0.1.3/go.mod h1:VGSQVrqkh6y4nm0189qqxMtvyBft44MOYYPpYKXiVt4= github.com/libp2p/go-libp2p-yamux v0.2.0/go.mod h1:Db2gU+XfLpm6E4rG5uGCFX6uXA8MEXOxFcRoXUODaK8= @@ -998,6 +1014,7 @@ github.com/libp2p/go-libp2p-yamux v0.5.4/go.mod h1:tfrXbyaTqqSU654GTvK3ocnSZL3Bu github.com/libp2p/go-libp2p-yamux v0.6.0/go.mod h1:MRhd6mAYnFRnSISp4M8i0ClV/j+mWHo2mYLifWGw33k= github.com/libp2p/go-libp2p-yamux v0.8.0/go.mod h1:yTkPgN2ib8FHyU1ZcVD7aelzyAqXXwEPbyx+aSKm9h8= github.com/libp2p/go-libp2p-yamux v0.8.1/go.mod h1:rUozF8Jah2dL9LLGyBaBeTQeARdwhefMCTQVQt6QobE= +github.com/libp2p/go-libp2p-yamux v0.8.2/go.mod h1:rUozF8Jah2dL9LLGyBaBeTQeARdwhefMCTQVQt6QobE= github.com/libp2p/go-libp2p-yamux v0.9.1 h1:oplewiRix8s45SOrI30rCPZG5mM087YZp+VYhXAh4+c= github.com/libp2p/go-libp2p-yamux v0.9.1/go.mod h1:wRc6wvyxQINFcKe7daL4BeQ02Iyp+wxyC8WCNfngBrA= github.com/libp2p/go-maddr-filter v0.0.1/go.mod h1:6eT12kSQMA9x2pvFQa+xesMKUBlj9VImZbj3B9FBH/Q= @@ -1012,6 +1029,7 @@ github.com/libp2p/go-mplex v0.1.2/go.mod h1:Xgz2RDCi3co0LeZfgjm4OgUF15+sVR8SRcu3 github.com/libp2p/go-mplex v0.2.0/go.mod h1:0Oy/A9PQlwBytDRp4wSkFnzHYDKcpLot35JQ6msjvYQ= github.com/libp2p/go-mplex v0.3.0/go.mod h1:0Oy/A9PQlwBytDRp4wSkFnzHYDKcpLot35JQ6msjvYQ= github.com/libp2p/go-mplex v0.4.0/go.mod h1:y26Lx+wNVtMYMaPu300Cbot5LkEZ4tJaNYeHeT9dh6E= +github.com/libp2p/go-mplex v0.6.0/go.mod h1:y26Lx+wNVtMYMaPu300Cbot5LkEZ4tJaNYeHeT9dh6E= github.com/libp2p/go-mplex v0.7.0 h1:BDhFZdlk5tbr0oyFq/xv/NPGfjbnrsDam1EvutpBDbY= github.com/libp2p/go-mplex v0.7.0/go.mod h1:rW8ThnRcYWft/Jb2jeORBmPd6xuG3dGxWN/W168L9EU= github.com/libp2p/go-msgio v0.0.2/go.mod h1:63lBBgOTDKQL6EWazRMCwXsEeEeK9O2Cd+0+6OOuipQ= @@ -1566,45 +1584,43 @@ go.opencensus.io v0.22.3/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw= go.opencensus.io v0.22.4/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw= go.opencensus.io v0.23.0 h1:gqCw0LfLxScz8irSi8exQc7fyQ0fKQU/qnC/X8+V/1M= go.opencensus.io v0.23.0/go.mod h1:XItmlyltB5F7CS4xOC1DcqMoFqwtC6OG2xF7mCv7P7E= -go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.31.0 h1:woM+Mb4d0A+Dxa3rYPenSN5ZeS9qHUvE8rlObiLRXTY= -go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.31.0/go.mod h1:PFmBsWbldL1kiWZk9+0LBZz2brhByaGsvp6pRICMlPE= +go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.32.0 h1:mac9BKRqwaX6zxHPDe3pvmWpwuuIM0vuXv2juCnQevE= +go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.32.0/go.mod h1:5eCOqeGphOyz6TsY3ZDNjE33SM/TFAK3RGuCL2naTgY= go.opentelemetry.io/otel v0.20.0/go.mod h1:Y3ugLH2oa81t5QO+Lty+zXf8zC9L26ax4Nzoxm/dooo= go.opentelemetry.io/otel v1.2.0/go.mod h1:aT17Fk0Z1Nor9e0uisf98LrntPGMnk4frBO9+dkf69I= -go.opentelemetry.io/otel v1.6.0/go.mod h1:bfJD2DZVw0LBxghOTlgnlI0CV3hLDu9XF/QKOUXMTQQ= -go.opentelemetry.io/otel v1.6.1/go.mod h1:blzUabWHkX6LJewxvadmzafgh/wnvBSDBdOuwkAtrWQ= -go.opentelemetry.io/otel v1.6.3 h1:FLOfo8f9JzFVFVyU+MSRJc2HdEAXQgm7pIv2uFKRSZE= go.opentelemetry.io/otel v1.6.3/go.mod h1:7BgNga5fNlF/iZjG06hM3yofffp0ofKCDwSXx1GC4dI= -go.opentelemetry.io/otel/exporters/jaeger v1.6.3 h1:7tvBU1Ydbzq080efuepYYqC1Pv3/vOFBgCSrxLb24d0= -go.opentelemetry.io/otel/exporters/jaeger v1.6.3/go.mod h1:YgX3eZWbJzgrNyNHCK0otGreAMBTIAcObtZS2VRi6sU= -go.opentelemetry.io/otel/exporters/otlp/internal/retry v1.6.3 h1:nAmg1WgsUXoXf46dJG9eS/AzOcvkCTK4xJSUYpWyHYg= -go.opentelemetry.io/otel/exporters/otlp/internal/retry v1.6.3/go.mod h1:NEu79Xo32iVb+0gVNV8PMd7GoWqnyDXRlj04yFjqz40= -go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.6.3 h1:4/UjHWMVVc5VwX/KAtqJOHErKigMCH8NexChMuanb/o= -go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.6.3/go.mod h1:UJmXdiVVBaZ63umRUTwJuCMAV//GCMvDiQwn703/GoY= -go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.6.3 h1:leYDq5psbM3K4QNcZ2juCj30LjUnvxjuYQj1mkGjXFM= -go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.6.3/go.mod h1:ycItY/esVj8c0dKgYTOztTERXtPzcfDU/0o8EdwCjoA= -go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp v1.6.3 h1:ufVuVt/g16GZ/yDOyp+AcCGebGX8u4z7kDRuwEX0DkA= -go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp v1.6.3/go.mod h1:S18p8VK4KRHHyAg5rH3iUnJUcRvIUg9xwIWtq1MWibM= -go.opentelemetry.io/otel/exporters/stdout/stdouttrace v1.6.3 h1:uSApZ0WGBOrEMNp0rtX1jtpYBh5CvktueAEHTWfLOtk= -go.opentelemetry.io/otel/exporters/stdout/stdouttrace v1.6.3/go.mod h1:LhMjYbVawqjXUIRbAT2CFuWtuQVxTPL8WEtxB/Iyg5Y= -go.opentelemetry.io/otel/exporters/zipkin v1.6.3 h1:5BzTuSYCahVIsRlxZjJO23WUsJjq/q70TnmNZz5Klk8= -go.opentelemetry.io/otel/exporters/zipkin v1.6.3/go.mod h1:JRfrU4shvi54xFL5KA9ftJv7El3FMMpkz3V2S8aZ/q0= +go.opentelemetry.io/otel v1.7.0 h1:Z2lA3Tdch0iDcrhJXDIlC94XE+bxok1F9B+4Lz/lGsM= +go.opentelemetry.io/otel v1.7.0/go.mod h1:5BdUoMIz5WEs0vt0CUEMtSSaTSHBBVwrhnz7+nrD5xk= +go.opentelemetry.io/otel/exporters/jaeger v1.7.0 h1:wXgjiRldljksZkZrldGVe6XrG9u3kYDyQmkZwmm5dI0= +go.opentelemetry.io/otel/exporters/jaeger v1.7.0/go.mod h1:PwQAOqBgqbLQRKlj466DuD2qyMjbtcPpfPfj+AqbSBs= +go.opentelemetry.io/otel/exporters/otlp/internal/retry v1.7.0 h1:7Yxsak1q4XrJ5y7XBnNwqWx9amMZvoidCctv62XOQ6Y= +go.opentelemetry.io/otel/exporters/otlp/internal/retry v1.7.0/go.mod h1:M1hVZHNxcbkAlcvrOMlpQ4YOO3Awf+4N2dxkZL3xm04= +go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.7.0 h1:cMDtmgJ5FpRvqx9x2Aq+Mm0O6K/zcUkH73SFz20TuBw= +go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.7.0/go.mod h1:ceUgdyfNv4h4gLxHR0WNfDiiVmZFodZhZSbOLhpxqXE= +go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.7.0 h1:MFAyzUPrTwLOwCi+cltN0ZVyy4phU41lwH+lyMyQTS4= +go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.7.0/go.mod h1:E+/KKhwOSw8yoPxSSuUHG6vKppkvhN+S1Jc7Nib3k3o= +go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp v1.7.0 h1:pLP0MH4MAqeTEV0g/4flxw9O8Is48uAIauAnjznbW50= +go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp v1.7.0/go.mod h1:aFXT9Ng2seM9eizF+LfKiyPBGy8xIZKwhusC1gIu3hA= +go.opentelemetry.io/otel/exporters/stdout/stdouttrace v1.7.0 h1:8hPcgCg0rUJiKE6VWahRvjgLUrNl7rW2hffUEPKXVEM= +go.opentelemetry.io/otel/exporters/stdout/stdouttrace v1.7.0/go.mod h1:K4GDXPY6TjUiwbOh+DkKaEdCF8y+lvMoM6SeAPyfCCM= +go.opentelemetry.io/otel/exporters/zipkin v1.7.0 h1:X0FZj+kaIdLi29UiyrEGDhRTYsEXj9GdEW5Y39UQFEE= +go.opentelemetry.io/otel/exporters/zipkin v1.7.0/go.mod h1:9YBXeOMFLQGwNEjsxMRiWPGoJX83usGMhbCmxUbNe5I= go.opentelemetry.io/otel/metric v0.20.0/go.mod h1:598I5tYlH1vzBjn+BTuhzTCSb/9debfNp6R3s7Pr1eU= -go.opentelemetry.io/otel/metric v0.28.0 h1:o5YNh+jxACMODoAo1bI7OES0RUW4jAMae0Vgs2etWAQ= -go.opentelemetry.io/otel/metric v0.28.0/go.mod h1:TrzsfQAmQaB1PDcdhBauLMk7nyyg9hm+GoQq/ekE9Iw= +go.opentelemetry.io/otel/metric v0.30.0 h1:Hs8eQZ8aQgs0U49diZoaS6Uaxw3+bBE3lcMUKBFIk3c= +go.opentelemetry.io/otel/metric v0.30.0/go.mod h1:/ShZ7+TS4dHzDFmfi1kSXMhMVubNoP0oIaBp70J6UXU= go.opentelemetry.io/otel/oteltest v0.20.0/go.mod h1:L7bgKf9ZB7qCwT9Up7i9/pn0PWIa9FqQ2IQ8LoxiGnw= go.opentelemetry.io/otel/sdk v0.20.0/go.mod h1:g/IcepuwNsoiX5Byy2nNV0ySUF1em498m7hBWC279Yc= go.opentelemetry.io/otel/sdk v1.2.0/go.mod h1:jNN8QtpvbsKhgaC6V5lHiejMoKD+V8uadoSafgHPx1U= -go.opentelemetry.io/otel/sdk v1.6.3 h1:prSHYdwCQOX5DrsEzxowH3nLhoAzEBdZhvrR79scfLs= -go.opentelemetry.io/otel/sdk v1.6.3/go.mod h1:A4iWF7HTXa+GWL/AaqESz28VuSBIcZ+0CV+IzJ5NMiQ= +go.opentelemetry.io/otel/sdk v1.7.0 h1:4OmStpcKVOfvDOgCt7UriAPtKolwIhxpnSNI/yK+1B0= +go.opentelemetry.io/otel/sdk v1.7.0/go.mod h1:uTEOTwaqIVuTGiJN7ii13Ibp75wJmYUDe374q6cZwUU= go.opentelemetry.io/otel/trace v0.20.0/go.mod h1:6GjCW8zgDjwGHGa6GkyeB8+/5vjT16gUEi0Nf1iBdgw= go.opentelemetry.io/otel/trace v1.2.0/go.mod h1:N5FLswTubnxKxOJHM7XZC074qpeEdLy3CgAVsdMucK0= -go.opentelemetry.io/otel/trace v1.6.0/go.mod h1:qs7BrU5cZ8dXQHBGxHMOxwME/27YH2qEp4/+tZLLwJE= -go.opentelemetry.io/otel/trace v1.6.1/go.mod h1:RkFRM1m0puWIq10oxImnGEduNBzxiN7TXluRBtE+5j0= -go.opentelemetry.io/otel/trace v1.6.3 h1:IqN4L+5b0mPNjdXIiZ90Ni4Bl5BRkDQywePLWemd9bc= go.opentelemetry.io/otel/trace v1.6.3/go.mod h1:GNJQusJlUgZl9/TQBPKU/Y/ty+0iVB5fjhKeJGZPGFs= +go.opentelemetry.io/otel/trace v1.7.0 h1:O37Iogk1lEkMRXewVtZ1BBTVn5JEp8GrJvP92bJqC6o= +go.opentelemetry.io/otel/trace v1.7.0/go.mod h1:fzLSB9nqR2eXzxPXb2JW9IKE+ScyXA48yyE4TNvoHqU= go.opentelemetry.io/proto/otlp v0.7.0/go.mod h1:PqfVotwruBrMGOCsRd/89rSnXhoiJIqeYNgFYFoEGnI= -go.opentelemetry.io/proto/otlp v0.15.0 h1:h0bKrvdrT/9sBwEJ6iWUqT/N/xPcS66bL4u3isneJ6w= -go.opentelemetry.io/proto/otlp v0.15.0/go.mod h1:H7XAot3MsfNsj7EXtrA2q5xSNQ10UqI405h3+duxN4U= +go.opentelemetry.io/proto/otlp v0.16.0 h1:WHzDWdXUvbc5bG2ObdrGfaNpQz7ft7QN9HHmJlbiB1E= +go.opentelemetry.io/proto/otlp v0.16.0/go.mod h1:H7XAot3MsfNsj7EXtrA2q5xSNQ10UqI405h3+duxN4U= go.uber.org/atomic v1.3.2/go.mod h1:gD2HeocX3+yG+ygLZcrzQJaqmWj9AIm7n08wl/qW/PE= go.uber.org/atomic v1.4.0/go.mod h1:gD2HeocX3+yG+ygLZcrzQJaqmWj9AIm7n08wl/qW/PE= go.uber.org/atomic v1.5.0/go.mod h1:sABNBOSYdrvTF6hTgEIbc7YasKWGhgEQZyfxyTvoXHQ= @@ -1680,8 +1696,9 @@ golang.org/x/crypto v0.0.0-20210711020723-a769d52b0f97/go.mod h1:GvvjBRRGRdwPK5y golang.org/x/crypto v0.0.0-20210813211128-0a44fdfbc16e/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= golang.org/x/crypto v0.0.0-20210920023735-84f357641f63/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= -golang.org/x/crypto v0.0.0-20220411220226-7b82a4e95df4 h1:kUhD7nTDoI3fVd9G4ORWrbV5NY0liEs/Jg2pv5f+bBA= golang.org/x/crypto v0.0.0-20220411220226-7b82a4e95df4/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4= +golang.org/x/crypto v0.0.0-20220518034528-6f7dac969898 h1:SLP7Q4Di66FONjDJbCYrCRrh97focO6sLogHO7/g8F0= +golang.org/x/crypto v0.0.0-20220518034528-6f7dac969898/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4= golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= golang.org/x/exp v0.0.0-20190306152737-a1d7652674e8/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= golang.org/x/exp v0.0.0-20190510132918-efd6b22b2522/go.mod h1:ZjyILWgesfNpC6sMxTJOJm9Kp84zZh5NQWvqDGG3Qr8= @@ -1783,8 +1800,9 @@ golang.org/x/net v0.0.0-20211015210444-4f30a5c0130f/go.mod h1:9nx3DQGgdP8bBQD5qx golang.org/x/net v0.0.0-20211112202133-69e39bad7dc2/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= golang.org/x/net v0.0.0-20220127200216-cd36cc0744dd/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk= golang.org/x/net v0.0.0-20220225172249-27dd8689420f/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk= -golang.org/x/net v0.0.0-20220418201149-a630d4f3e7a2 h1:6mzvA99KwZxbOrxww4EvWVQUnN1+xEu9tafK5ZxkYeA= golang.org/x/net v0.0.0-20220418201149-a630d4f3e7a2/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk= +golang.org/x/net v0.0.0-20220517181318-183a9ca12b87 h1:cCR+9mKLOGyX4Zx+uBZDXEDAQsvKQ/XbW4vreG5v1jU= +golang.org/x/net v0.0.0-20220517181318-183a9ca12b87/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk= golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= golang.org/x/oauth2 v0.0.0-20181017192945-9dcd33a902f4/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= golang.org/x/oauth2 v0.0.0-20181203162652-d668ce993890/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= @@ -1897,8 +1915,9 @@ golang.org/x/sys v0.0.0-20210903071746-97244b99971b/go.mod h1:oPkhp1MJrh7nUepCBc golang.org/x/sys v0.0.0-20211019181941-9d821ace8654/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20211216021012-1d35b9e2eb4e/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220114195835-da31bd327af9/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20220412211240-33da011f77ad h1:ntjMns5wyP/fN65tdBD4g8J5w8n015+iIIs9rtjXkY0= golang.org/x/sys v0.0.0-20220412211240-33da011f77ad/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220517195934-5e4e11fc645e h1:w36l2Uw3dRan1K3TyXriXvY+6T56GNmlKGcqiQUJDfM= +golang.org/x/sys v0.0.0-20220517195934-5e4e11fc645e/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/term v0.0.0-20201117132131-f5c789dd3221/go.mod h1:Nr5EML6q2oocZ2LXRh80K7BxOlk5/8JxuGnuhpl+muw= golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= golang.org/x/term v0.0.0-20210927222741-03fcf44c2211 h1:JGgROgKl9N8DuW20oFS5gxc+lE67/N3FcwmBPMe7ArY= @@ -2077,8 +2096,9 @@ google.golang.org/grpc v1.36.0/go.mod h1:qjiiYl8FncCW8feJPdyg3v6XW24KsRHe+dy9BAG google.golang.org/grpc v1.40.0/go.mod h1:ogyxbiOoUXAkP+4+xa6PZSE9DZgIHtSpzjDTB9KAK34= google.golang.org/grpc v1.41.0/go.mod h1:U3l9uK9J0sini8mHphKoXyaqDA/8VyGnDee1zzIUK6k= google.golang.org/grpc v1.42.0/go.mod h1:k+4IHHFw41K8+bbowsex27ge2rCb65oeWqe4jJ590SU= -google.golang.org/grpc v1.45.0 h1:NEpgUqV3Z+ZjkqMsxMg11IaDrXY4RY6CQukSGK0uI1M= google.golang.org/grpc v1.45.0/go.mod h1:lN7owxKUQEqMfSyQikvvk5tf/6zMPsrK+ONuO11+0rQ= +google.golang.org/grpc v1.46.0 h1:oCjezcn6g6A75TGoKYBPgKmVBLexhYLM6MebdrPApP8= +google.golang.org/grpc v1.46.0/go.mod h1:vN9eftEi1UMyUsIF80+uQXhHjbXYbm0uXoFCACuMGWk= google.golang.org/protobuf v0.0.0-20200109180630-ec00e32a8dfd/go.mod h1:DFci5gLYBciE7Vtevhsrf46CRTquxDuWsQurQQe4oz8= google.golang.org/protobuf v0.0.0-20200221191635-4d8936d0db64/go.mod h1:kwYJMbMJ01Woi6D6+Kah6886xMZcty6N08ah7+eCXa0= google.golang.org/protobuf v0.0.0-20200228230310-ab0ca4ff8a60/go.mod h1:cfTl7dwQJ+fmap5saPgwCLgHXTUD7jkjRqWcaiX5VyM= diff --git a/test/sharness/t0087-repo-robust-gc.sh b/test/sharness/t0087-repo-robust-gc.sh index 89cfbb9b26c..884de5774e0 100755 --- a/test/sharness/t0087-repo-robust-gc.sh +++ b/test/sharness/t0087-repo-robust-gc.sh @@ -10,7 +10,7 @@ test_description="Test robustness of garbage collector" set -e to_raw_cid() { - ipfs cid format -b b --codec raw -v 1 "$1" + ipfs cid format -b b --mc raw -v 1 "$1" } test_gc_robust_part1() { diff --git a/test/sharness/t0114-gateway-subdomains.sh b/test/sharness/t0114-gateway-subdomains.sh index 41abd4a8774..f9ab0d82427 100755 --- a/test/sharness/t0114-gateway-subdomains.sh +++ b/test/sharness/t0114-gateway-subdomains.sh @@ -116,7 +116,7 @@ test_expect_success "Add the test directory" ' test_expect_success "Publish test text file to IPNS using RSA keys" ' RSA_KEY=$(ipfs key gen --ipns-base=b58mh --type=rsa --size=2048 test_key_rsa | head -n1 | tr -d "\n") RSA_IPNS_IDv0=$(echo "$RSA_KEY" | ipfs cid format -v 0) - RSA_IPNS_IDv1=$(echo "$RSA_KEY" | ipfs cid format -v 1 --codec libp2p-key -b base36) + RSA_IPNS_IDv1=$(echo "$RSA_KEY" | ipfs cid format -v 1 --mc libp2p-key -b base36) RSA_IPNS_IDv1_DAGPB=$(echo "$RSA_IPNS_IDv0" | ipfs cid format -v 1 -b base36) test_check_peerid "${RSA_KEY}" && ipfs name publish --key test_key_rsa --allow-offline -Q "/ipfs/$CIDv1" > name_publish_out && @@ -129,7 +129,7 @@ test_expect_success "Publish test text file to IPNS using ED25519 keys" ' ED25519_KEY=$(ipfs key gen --ipns-base=b58mh --type=ed25519 test_key_ed25519 | head -n1 | tr -d "\n") ED25519_IPNS_IDv0=$ED25519_KEY ED25519_IPNS_IDv1=$(ipfs key list -l --ipns-base=base36 | grep test_key_ed25519 | cut -d " " -f1 | tr -d "\n") - ED25519_IPNS_IDv1_DAGPB=$(echo "$ED25519_IPNS_IDv1" | ipfs cid format -v 1 -b base36 --codec protobuf) + ED25519_IPNS_IDv1_DAGPB=$(echo "$ED25519_IPNS_IDv1" | ipfs cid format -v 1 -b base36 --mc dag-pb) test_check_peerid "${ED25519_KEY}" && ipfs name publish --key test_key_ed25519 --allow-offline -Q "/ipfs/$CIDv1" > name_publish_out && ipfs name resolve "$ED25519_KEY" > output && diff --git a/test/sharness/t0160-resolve.sh b/test/sharness/t0160-resolve.sh index 4b967704946..ca11947b093 100755 --- a/test/sharness/t0160-resolve.sh +++ b/test/sharness/t0160-resolve.sh @@ -121,8 +121,8 @@ test_resolve_cmd_b32() { # peer ID represented as CIDv1 require libp2p-key multicodec # https://github.com/libp2p/specs/blob/master/RFC/0001-text-peerid-cid.md - local self_hash_b32protobuf=$(echo $self_hash | ipfs cid format -v 1 -b b --codec protobuf) - local self_hash_b32libp2pkey=$(echo $self_hash | ipfs cid format -v 1 -b b --codec libp2p-key) + local self_hash_b32protobuf=$(echo $self_hash | ipfs cid format -v 1 -b b --mc dag-pb) + local self_hash_b32libp2pkey=$(echo $self_hash | ipfs cid format -v 1 -b b --mc libp2p-key) test_expect_success "resolve of /ipns/{cidv1} with multicodec other than libp2p-key returns a meaningful error" ' test_expect_code 1 ipfs resolve /ipns/$self_hash_b32protobuf 2>cidcodec_error && test_should_contain "Error: peer ID represented as CIDv1 require libp2p-key multicodec: retry with /ipns/$self_hash_b32libp2pkey" cidcodec_error diff --git a/test/sharness/t0290-cid.sh b/test/sharness/t0290-cid.sh index b6518892ef6..7f0e0e1814d 100755 --- a/test/sharness/t0290-cid.sh +++ b/test/sharness/t0290-cid.sh @@ -13,6 +13,7 @@ CIDb32="bafybeibxm2nsadl3fnxv2sxcxmxaco2jl53wpeorjdzidjwf5aqdg7wa6u" CIDbase="QmYNmQKp6SuaVrpgWRsPTgCQCnpxUYGq76YEKBXuj2N4H6" CIDb32pb="bafybeievd6mwe6vcwnkwo3eizs3h7w3a34opszbyfxziqdxguhjw7imdve" CIDb32raw="bafkreievd6mwe6vcwnkwo3eizs3h7w3a34opszbyfxziqdxguhjw7imdve" +CIDb32dagcbor="bafyreievd6mwe6vcwnkwo3eizs3h7w3a34opszbyfxziqdxguhjw7imdve" test_expect_success "cid base32 works" ' echo $CIDb32 > expected && @@ -284,13 +285,28 @@ test_expect_success "cid hashes --numeric" ' test_expect_success "cid format -c raw" ' echo $CIDb32raw > expected && - ipfs cid format --codec raw -b base32 $CIDb32pb > actual && + ipfs cid format --mc raw -b base32 $CIDb32pb > actual && test_cmp actual expected ' -test_expect_success "cid format -c protobuf -v 0" ' +test_expect_success "cid format --mc dag-pb -v 0" ' echo $CIDbase > expected && - ipfs cid format --codec protobuf -v 0 $CIDb32raw > actual && + ipfs cid format --mc dag-pb -v 0 $CIDb32raw > actual && + test_cmp actual expected +' + +test_expect_success "cid format --mc dag-cbor" ' + echo $CIDb32dagcbor > expected && + ipfs cid format --mc dag-cbor $CIDb32pb > actual && + test_cmp actual expected +' + +# this was an old flag that we removed, explicitly to force an error +# so the user would read about the new multicodec names introduced +# by https://github.com/ipfs/go-cid/commit/b2064d74a8b098193b316689a715cdf4e4934805 +test_expect_success "cid format --codec fails" ' + echo "Error: unknown option \"codec\"" > expected && + test_expect_code 1 ipfs cid format --codec protobuf 2> actual && test_cmp actual expected ' diff --git a/test/sharness/t0310-tracing.sh b/test/sharness/t0310-tracing.sh index 42846c9d076..96d07ae8da2 100755 --- a/test/sharness/t0310-tracing.sh +++ b/test/sharness/t0310-tracing.sh @@ -39,7 +39,7 @@ EOF rm -rf traces.json && touch traces.json && chmod 777 traces.json test_expect_success "run opentelemetry collector" ' - docker run --rm -d -v "$PWD/collector-config.yaml":/config.yaml -v "$PWD":/traces --net=host --name=ipfs-test-otel-collector otel/opentelemetry-collector-contrib:0.48.0 --config /config.yaml + docker run --rm -d -v "$PWD/collector-config.yaml":/config.yaml -v "$PWD":/traces --net=host --name=ipfs-test-otel-collector otel/opentelemetry-collector-contrib:0.52.0 --config /config.yaml ' test_launch_ipfs_daemon diff --git a/tracing/tracing.go b/tracing/tracing.go index 99b340236f5..84eabc5e78e 100644 --- a/tracing/tracing.go +++ b/tracing/tracing.go @@ -15,7 +15,7 @@ import ( "go.opentelemetry.io/otel/exporters/zipkin" "go.opentelemetry.io/otel/sdk/resource" "go.opentelemetry.io/otel/sdk/trace" - semconv "go.opentelemetry.io/otel/semconv/v1.7.0" + semconv "go.opentelemetry.io/otel/semconv/v1.4.0" traceapi "go.opentelemetry.io/otel/trace" ) @@ -129,8 +129,7 @@ func NewTracerProvider(ctx context.Context) (shutdownTracerProvider, error) { r, err := resource.Merge( resource.Default(), - resource.NewWithAttributes( - semconv.SchemaURL, + resource.NewSchemaless( semconv.ServiceNameKey.String("go-ipfs"), semconv.ServiceVersionKey.String(version.CurrentVersionNumber), ), From 85e3fa60c599225ea6cef24dc27a9393013a685f Mon Sep 17 00:00:00 2001 From: Gus Eggert Date: Fri, 3 Jun 2022 16:58:37 -0400 Subject: [PATCH 411/414] chore: upgrade to go-libp2p v0.19.4 (cherry picked from commit 2e170a4302152a54bd5ab07946854bbc731f31d5) --- go.mod | 4 ++-- go.sum | 7 ++++--- 2 files changed, 6 insertions(+), 5 deletions(-) diff --git a/go.mod b/go.mod index cb914b45571..bcdd9069ec7 100644 --- a/go.mod +++ b/go.mod @@ -68,7 +68,7 @@ require ( github.com/jbenet/go-temp-err-catcher v0.1.0 github.com/jbenet/goprocess v0.1.4 github.com/libp2p/go-doh-resolver v0.4.0 - github.com/libp2p/go-libp2p v0.19.3 + github.com/libp2p/go-libp2p v0.19.4 github.com/libp2p/go-libp2p-core v0.15.1 github.com/libp2p/go-libp2p-discovery v0.6.0 github.com/libp2p/go-libp2p-http v0.2.1 @@ -201,7 +201,7 @@ require ( github.com/libp2p/go-reuseport v0.1.0 // indirect github.com/libp2p/go-reuseport-transport v0.1.0 // indirect github.com/libp2p/go-stream-muxer-multistream v0.4.0 // indirect - github.com/libp2p/go-yamux/v3 v3.1.1 // indirect + github.com/libp2p/go-yamux/v3 v3.1.2 // indirect github.com/libp2p/zeroconf/v2 v2.1.1 // indirect github.com/lucas-clemente/quic-go v0.27.1 // indirect github.com/marten-seemann/qtls-go1-16 v0.1.5 // indirect diff --git a/go.sum b/go.sum index 1d8452a801d..09757be3eb4 100644 --- a/go.sum +++ b/go.sum @@ -776,8 +776,8 @@ github.com/libp2p/go-libp2p v0.14.3/go.mod h1:d12V4PdKbpL0T1/gsUNN8DfgMuRPDX8bS2 github.com/libp2p/go-libp2p v0.14.4/go.mod h1:EIRU0Of4J5S8rkockZM7eJp2S0UrCyi55m2kJVru3rM= github.com/libp2p/go-libp2p v0.16.0/go.mod h1:ump42BsirwAWxKzsCiFnTtN1Yc+DuPu76fyMX364/O4= github.com/libp2p/go-libp2p v0.18.0/go.mod h1:+veaZ9z1SZQhmc5PW78jvnnxZ89Mgvmh4cggO11ETmw= -github.com/libp2p/go-libp2p v0.19.3 h1:LqjvuBWdyYSqvkH4VVYxA78Fkphzg2Pq86VMnilqgkw= -github.com/libp2p/go-libp2p v0.19.3/go.mod h1:AGlPVLjh0+6jvEtf+a2gZEux7yHJrYXnG9IC7wcQ2NY= +github.com/libp2p/go-libp2p v0.19.4 h1:50YL0YwPhWKDd+qbZQDEdnsmVAAkaCQrWUjpdHv4hNA= +github.com/libp2p/go-libp2p v0.19.4/go.mod h1:MIt8y481VDhUe4ErWi1a4bvt/CjjFfOq6kZTothWIXY= github.com/libp2p/go-libp2p-asn-util v0.0.0-20200825225859-85005c6cf052/go.mod h1:nRMRTab+kZuk0LnKZpxhOVH/ndsdr2Nr//Zltc/vwgo= github.com/libp2p/go-libp2p-asn-util v0.1.0/go.mod h1:wu+AnM9Ii2KgO5jMmS1rz9dvzTdj8BXqsPR9HR0XB7I= github.com/libp2p/go-libp2p-asn-util v0.2.0 h1:rg3+Os8jbnO5DxkC7K/Utdi+DkY3q/d1/1q+8WeNAsw= @@ -1116,8 +1116,9 @@ github.com/libp2p/go-yamux/v2 v2.2.0/go.mod h1:3So6P6TV6r75R9jiBpiIKgU/66lOarCZj github.com/libp2p/go-yamux/v2 v2.3.0/go.mod h1:iTU+lOIn/2h0AgKcL49clNTwfEw+WSfDYrXe05EyKIs= github.com/libp2p/go-yamux/v3 v3.0.1/go.mod h1:s2LsDhHbh+RfCsQoICSYt58U2f8ijtPANFD8BmE74Bo= github.com/libp2p/go-yamux/v3 v3.0.2/go.mod h1:s2LsDhHbh+RfCsQoICSYt58U2f8ijtPANFD8BmE74Bo= -github.com/libp2p/go-yamux/v3 v3.1.1 h1:X0qSVodCZciOu/f4KTp9V+O0LAqcqP2tdaUGB0+0lng= github.com/libp2p/go-yamux/v3 v3.1.1/go.mod h1:jeLEQgLXqE2YqX1ilAClIfCMDY+0uXQUKmmb/qp0gT4= +github.com/libp2p/go-yamux/v3 v3.1.2 h1:lNEy28MBk1HavUAlzKgShp+F6mn/ea1nDYWftZhFW9Q= +github.com/libp2p/go-yamux/v3 v3.1.2/go.mod h1:jeLEQgLXqE2YqX1ilAClIfCMDY+0uXQUKmmb/qp0gT4= github.com/libp2p/zeroconf/v2 v2.1.1 h1:XAuSczA96MYkVwH+LqqqCUZb2yH3krobMJ1YE+0hG2s= github.com/libp2p/zeroconf/v2 v2.1.1/go.mod h1:fuJqLnUwZTshS3U/bMRJ3+ow/v9oid1n0DmyYyNO1Xs= github.com/lightstep/lightstep-tracer-common/golang/gogo v0.0.0-20190605223551-bc2310a04743/go.mod h1:qklhhLq1aX+mtWk9cPHPzaBjWImj5ULL6C7HFJtXQMM= From 6e1de05cd1cfba669406d906e5615d69c48f3c12 Mon Sep 17 00:00:00 2001 From: Adin Schmahmann Date: Wed, 8 Jun 2022 15:33:06 -0400 Subject: [PATCH 412/414] chore: bump Go to 1.18.3 (#9021) (cherry picked from commit 9db6641efd46f48a3596409009f8001bad4d5917) --- .circleci/main.yml | 10 +++++----- Dockerfile | 2 +- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/.circleci/main.yml b/.circleci/main.yml index 18c5d55cd81..49591d50c30 100644 --- a/.circleci/main.yml +++ b/.circleci/main.yml @@ -37,7 +37,7 @@ default_environment: &default_environment executors: golang: docker: - - image: cimg/go:1.18.1 + - image: cimg/go:1.18.3 working_directory: ~/ipfs/go-ipfs environment: <<: *default_environment @@ -62,7 +62,7 @@ executors: E2E_IPFSD_TYPE: go dockerizer: docker: - - image: cimg/go:1.18.1 + - image: cimg/go:1.18.3 environment: IMAGE_NAME: ipfs/go-ipfs WIP_IMAGE_TAG: wip @@ -162,8 +162,8 @@ jobs: - run: sudo apt update - run: | mkdir ~/localgo && cd ~/localgo - wget https://golang.org/dl/go1.18.1.linux-amd64.tar.gz - tar xfz go1.18.1.linux-amd64.tar.gz + wget https://golang.org/dl/go1.18.3.linux-amd64.tar.gz + tar xfz go1.18.3.linux-amd64.tar.gz echo "export PATH=$(pwd)/go/bin:\$PATH" >> ~/.bashrc - run: go version - run: sudo apt install socat net-tools @@ -229,7 +229,7 @@ jobs: - *store_gomod interop: docker: - - image: cimg/go:1.18.1-node + - image: cimg/go:1.18.3-node parallelism: 4 resource_class: large steps: diff --git a/Dockerfile b/Dockerfile index 81d43825270..913cde19b68 100644 --- a/Dockerfile +++ b/Dockerfile @@ -1,5 +1,5 @@ # Note: when updating the go minor version here, also update the go-channel in snap/snapcraft.yml -FROM golang:1.18.1-buster +FROM golang:1.18.3-buster LABEL maintainer="Steven Allen " # Install deps From 56145237bb3d636448ab0d54b267958279b622c8 Mon Sep 17 00:00:00 2001 From: Gus Eggert Date: Wed, 8 Jun 2022 13:52:58 -0400 Subject: [PATCH 413/414] docs: v0.13.0 release notes --- CHANGELOG.md | 155 +++++++++++++++++++++++---------------------------- 1 file changed, 71 insertions(+), 84 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 66c966b994e..fd796ff66ee 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -298,9 +298,25 @@ The more fully featured yamux stream multiplexer is now prioritized over mplex f
    Full Changelog - - github.com/ipfs/go-ipfs: - - docs: v0.13.0 changelog + - feat: upgrade to go-libp2p-kad-dht@v0.16.0 (#9005) ([ipfs/go-ipfs#9005](https://github.com/ipfs/go-ipfs/pull/9005)) + - docs: fix typo in the `swarm/peering` help text + - feat: disable resource manager by default (#9003) ([ipfs/go-ipfs#9003](https://github.com/ipfs/go-ipfs/pull/9003)) + - fix: adjust rcmgr limits for accelerated DHT client rt refresh (#8982) ([ipfs/go-ipfs#8982](https://github.com/ipfs/go-ipfs/pull/8982)) + - fix(ci): make go-ipfs-as-a-library work without external peers (#8978) ([ipfs/go-ipfs#8978](https://github.com/ipfs/go-ipfs/pull/8978)) + - feat: log when resource manager limits are exceeded (#8980) ([ipfs/go-ipfs#8980](https://github.com/ipfs/go-ipfs/pull/8980)) + - fix: JS caching via Access-Control-Expose-Headers (#8984) ([ipfs/go-ipfs#8984](https://github.com/ipfs/go-ipfs/pull/8984)) + - docs: fix abstractions typo + - fix: hanging goroutine in get fileArchive handler + - fix(node/libp2p): disable rcmgr checkImplicitDefaults ([ipfs/go-ipfs#8965](https://github.com/ipfs/go-ipfs/pull/8965)) + - pubsub multibase encoding (#8933) ([ipfs/go-ipfs#8933](https://github.com/ipfs/go-ipfs/pull/8933)) + - 'pin rm' helptext: rewrite description as object is not removed from local storage (immediately) ([ipfs/go-ipfs#8947](https://github.com/ipfs/go-ipfs/pull/8947)) + - ([ipfs/go-ipfs#8934](https://github.com/ipfs/go-ipfs/pull/8934)) + - Add instructions to resolve repo migration error (#8946) ([ipfs/go-ipfs#8946](https://github.com/ipfs/go-ipfs/pull/8946)) + - fix: use path instead of filepath for asset embeds to support Windows + - Release v0.13.0-rc1 + - docs: v0.13.0 changelog ([ipfs/go-ipfs#8941](https://github.com/ipfs/go-ipfs/pull/8941)) + - chore: build with go 1.18.1 ([ipfs/go-ipfs#8932](https://github.com/ipfs/go-ipfs/pull/8932)) - docs(tracing): update env var docs for new tracing env vars - feat: enable Resource Manager by default - chore: Update test/dependencies to match go-ipfs dependencies. (#8928) ([ipfs/go-ipfs#8928](https://github.com/ipfs/go-ipfs/pull/8928)) @@ -350,8 +366,7 @@ The more fully featured yamux stream multiplexer is now prioritized over mplex f - feat: add gateway histogram metrics (#8443) ([ipfs/go-ipfs#8443](https://github.com/ipfs/go-ipfs/pull/8443)) - ErrNotFound changes: bubble tagged libraries. ([ipfs/go-ipfs#8803](https://github.com/ipfs/go-ipfs/pull/8803)) - Fix typos - - Bubble ErrNotFound improvements. - ([ipfs/go-ipfs#8757](https://github.com/ipfs/go-ipfs/pull/8757)) + ([ipfs/go-ipfs#8757](https://github.com/ipfs/go-ipfs/pull/8757)) - feat(gateway): Block and CAR response formats (#8758) ([ipfs/go-ipfs#8758](https://github.com/ipfs/go-ipfs/pull/8758)) - fix: allow ipfs-companion browser extension to access RPC API (#8690) ([ipfs/go-ipfs#8690](https://github.com/ipfs/go-ipfs/pull/8690)) - fix(core/node): unwrap fx error in node construction ([ipfs/go-ipfs#8638](https://github.com/ipfs/go-ipfs/pull/8638)) @@ -363,8 +378,7 @@ The more fully featured yamux stream multiplexer is now prioritized over mplex f - docs: note the default reprovider strategy as all (#8603) ([ipfs/go-ipfs#8603](https://github.com/ipfs/go-ipfs/pull/8603)) - fix: listen on loopback for API and gateway ports in docker-compose.yaml (#8773) ([ipfs/go-ipfs#8773](https://github.com/ipfs/go-ipfs/pull/8773)) - fix(discovery): fix daemon not starting due to mdns startup failure (#8704) ([ipfs/go-ipfs#8704](https://github.com/ipfs/go-ipfs/pull/8704)) - - Move go-ipfs-config back into go-ipfs, - ([ipfs/go-ipfs#8756](https://github.com/ipfs/go-ipfs/pull/8756)) + ([ipfs/go-ipfs#8756](https://github.com/ipfs/go-ipfs/pull/8756)) - feat: ipfs-webui v2.15 (#8712) ([ipfs/go-ipfs#8712](https://github.com/ipfs/go-ipfs/pull/8712)) - feat: X-Ipfs-Roots for smarter HTTP caches (#8720) ([ipfs/go-ipfs#8720](https://github.com/ipfs/go-ipfs/pull/8720)) - chore: add instructions for Chocolatey release @@ -403,6 +417,20 @@ The more fully featured yamux stream multiplexer is now prioritized over mplex f - v0.3.0 - s/log/logger - Use ipld.ErrNotFound instead of ErrNotFound +- github.com/ipfs/go-cid (v0.1.0 -> v0.2.0): + - fix: remove invalid multicodec2string mappings (#137) ([ipfs/go-cid#137](https://github.com/ipfs/go-cid/pull/137)) + - sync: update CI config files (#136) ([ipfs/go-cid#136](https://github.com/ipfs/go-cid/pull/136)) + - Benchmark existing ways to check for `IDENTITY` CIDs + - avoid double alloc in NewCidV1 + - sync: update CI config files ([ipfs/go-cid#131](https://github.com/ipfs/go-cid/pull/131)) +- github.com/ipfs/go-cidutil (v0.0.2 -> v0.1.0): + ([ipfs/go-cidutil#36](https://github.com/ipfs/go-cidutil/pull/36)) + - sync: update CI config files ([ipfs/go-cidutil#35](https://github.com/ipfs/go-cidutil/pull/35)) + - sync: update CI config files (#34) ([ipfs/go-cidutil#34](https://github.com/ipfs/go-cidutil/pull/34)) + - fix staticcheck ([ipfs/go-cidutil#31](https://github.com/ipfs/go-cidutil/pull/31)) + - add license file so it can be found by go-licenses ([ipfs/go-cidutil#27](https://github.com/ipfs/go-cidutil/pull/27)) + - test: fix for base32 switch ([ipfs/go-cidutil#16](https://github.com/ipfs/go-cidutil/pull/16)) + - doc: add a lead maintainer - github.com/ipfs/go-filestore (v1.1.0 -> v1.2.0): - v1.2.0 - refactor: follow the happy left practice in Filestore.DeleteBlock @@ -555,43 +583,6 @@ The more fully featured yamux stream multiplexer is now prioritized over mplex f - v0.6.0 - Update tests to use ipld.IsNotFound to check for notfound errors - sync: update CI config files (#79) ([ipfs/interface-go-ipfs-core#79](https://github.com/ipfs/interface-go-ipfs-core/pull/79)) -- github.com/ipld/go-car/v2 (null -> v2.1.1): - - Update v2 to context datastores (#275) ([ipld/go-car#275](https://github.com/ipld/go-car/pull/275)) - - update context datastore ([ipld/go-car#273](https://github.com/ipld/go-car/pull/273)) - - Traversal-based car creation (#269) ([ipld/go-car#269](https://github.com/ipld/go-car/pull/269)) - - Seek to start before index generation in `ReadOnly` blockstore - - support extraction of unixfs content stored in car files (#263) ([ipld/go-car#263](https://github.com/ipld/go-car/pull/263)) - - Add a barebones readme to the car CLI (#262) ([ipld/go-car#262](https://github.com/ipld/go-car/pull/262)) - - sync: update CI config files (#261) ([ipld/go-car#261](https://github.com/ipld/go-car/pull/261)) - - fix!: use -version=n instead of -v1 for index command - - feat: fix get-dag and add version=1 option - - creation of car from file / directory (#246) ([ipld/go-car#246](https://github.com/ipld/go-car/pull/246)) - - forEach iterates over index in stable order (#258) ([ipld/go-car#258](https://github.com/ipld/go-car/pull/258)) - - Expose selector traversal options for SelectiveCar ([ipld/go-car#251](https://github.com/ipld/go-car/pull/251)) - - Implement API to allow replacing root CIDs in a CARv1 or CARv2 - - blockstore: OpenReadWrite should not modify if it refuses to resume - - clarify the relation between StoreIdentityCIDs and SetFullyIndexed - - Implement options to handle `IDENTITY` CIDs gracefully - - Combine API options for simplicity and logical coherence - - Add test script for car verify (#236) ([ipld/go-car#236](https://github.com/ipld/go-car/pull/236)) - - cmd/car: add first testscript tests - - integrate `car/` cli into `cmd/car` (#233) ([ipld/go-car#233](https://github.com/ipld/go-car/pull/233)) - - Add `car get-dag` command (#232) ([ipld/go-car#232](https://github.com/ipld/go-car/pull/232)) - - Separate CLI to separate module (#231) ([ipld/go-car#231](https://github.com/ipld/go-car/pull/231)) - - add `get block` to car cli (#230) ([ipld/go-car#230](https://github.com/ipld/go-car/pull/230)) - - use file size when loading from v1 car (#229) ([ipld/go-car#229](https://github.com/ipld/go-car/pull/229)) - - add interface describing iteration (#228) ([ipld/go-car#228](https://github.com/ipld/go-car/pull/228)) - - Add `list` and `filter` commands (#227) ([ipld/go-car#227](https://github.com/ipld/go-car/pull/227)) - - Add `car split` command (#226) ([ipld/go-car#226](https://github.com/ipld/go-car/pull/226)) - - Make `MultihashIndexSorted` the default index codec for CARv2 - - Add carve utility for updating the index of a car{v1,v2} file (#219) ([ipld/go-car#219](https://github.com/ipld/go-car/pull/219)) - - Ignore records with `IDENTITY` CID in `IndexSorted` - - Fix index GetAll infinite loop if function always returns `true` - - Expose the ability to iterate over records in `MultihasIndexSorted` - - avoid another alloc per read byte - - avoid allocating on every byte read - - Implement new index type that also includes mutltihash code - - Return `nil` as Index reader when reading indexless CARv2 - github.com/ipld/go-codec-dagpb (v1.3.2 -> v1.4.0): - bump to v1.4.0 given that we updated ipld-prime - add a decode-then-encode roundtrip fuzzer @@ -640,8 +631,6 @@ The more fully featured yamux stream multiplexer is now prioritized over mplex f - Update to context datastores (#312) ([ipld/go-ipld-prime#312](https://github.com/ipld/go-ipld-prime/pull/312)) - schema: add support for struct tuple reprs - Allow parsing padding in dag-json bytes fields (#309) ([ipld/go-ipld-prime#309](https://github.com/ipld/go-ipld-prime/pull/309)) -- github.com/ipld/go-ipld-prime/storage/bsadapter (null -> v0.0.0-20211210234204-ce2a1c70cd73): - failed to fetch repo - github.com/libp2p/go-doh-resolver (v0.3.1 -> v0.4.0): - Release v0.4.0 (#16) ([libp2p/go-doh-resolver#16](https://github.com/libp2p/go-doh-resolver/pull/16)) - sync: update CI config files (#14) ([libp2p/go-doh-resolver#14](https://github.com/libp2p/go-doh-resolver/pull/14)) @@ -649,7 +638,11 @@ The more fully featured yamux stream multiplexer is now prioritized over mplex f - Perform test locally instead of using a live dns resolution ([libp2p/go-doh-resolver#13](https://github.com/libp2p/go-doh-resolver/pull/13)) - sync: update CI config files (#7) ([libp2p/go-doh-resolver#7](https://github.com/libp2p/go-doh-resolver/pull/7)) - fix staticcheck ([libp2p/go-doh-resolver#6](https://github.com/libp2p/go-doh-resolver/pull/6)) -- github.com/libp2p/go-libp2p (v0.16.0 -> v0.19.1): +- github.com/libp2p/go-libp2p (v0.16.0 -> v0.19.4): + - update go-yamux to v3.1.2, release v0.19.4 (#1590) ([libp2p/go-libp2p#1590](https://github.com/libp2p/go-libp2p/pull/1590)) + - update quic-go to v0.27.1, release v0.19.3 (#1518) ([libp2p/go-libp2p#1518](https://github.com/libp2p/go-libp2p/pull/1518)) + - release v0.19.2 + - holepunch: fix incorrect message type for the SYNC message (#1478) ([libp2p/go-libp2p#1478](https://github.com/libp2p/go-libp2p/pull/1478)) - fix race condition in holepunch service, release v0.19.1 ([libp2p/go-libp2p#1474](https://github.com/libp2p/go-libp2p/pull/1474)) - release v0.19.0 (#1408) ([libp2p/go-libp2p#1408](https://github.com/libp2p/go-libp2p/pull/1408)) - Close resource manager when host closes (#1343) ([libp2p/go-libp2p#1343](https://github.com/libp2p/go-libp2p/pull/1343)) @@ -757,6 +750,12 @@ The more fully featured yamux stream multiplexer is now prioritized over mplex f - release v0.12.0 (#223) ([libp2p/go-libp2p-core#223](https://github.com/libp2p/go-libp2p-core/pull/223)) - generate ecdsa public key from an input public key (#219) ([libp2p/go-libp2p-core#219](https://github.com/libp2p/go-libp2p-core/pull/219)) - add RemovePeer method to PeerMetadata, Metrics, ProtoBook and Keybook (#218) ([libp2p/go-libp2p-core#218](https://github.com/libp2p/go-libp2p-core/pull/218)) +- github.com/libp2p/go-libp2p-kad-dht (v0.15.0 -> v0.16.0): + - Version 0.16.0 (#774) ([libp2p/go-libp2p-kad-dht#774](https://github.com/libp2p/go-libp2p-kad-dht/pull/774)) + - feat: add error log when resource manager throttles crawler (#772) ([libp2p/go-libp2p-kad-dht#772](https://github.com/libp2p/go-libp2p-kad-dht/pull/772)) + - fix: incorrect format handling ([libp2p/go-libp2p-kad-dht#771](https://github.com/libp2p/go-libp2p-kad-dht/pull/771)) + - Upgrade to go-libp2p v0.16.0 (#756) ([libp2p/go-libp2p-kad-dht#756](https://github.com/libp2p/go-libp2p-kad-dht/pull/756)) + - sync: update CI config files ([libp2p/go-libp2p-kad-dht#758](https://github.com/libp2p/go-libp2p-kad-dht/pull/758)) - github.com/libp2p/go-libp2p-mplex (v0.4.1 -> v0.7.0): - release v0.7.0 (#36) ([libp2p/go-libp2p-mplex#36](https://github.com/libp2p/go-libp2p-mplex/pull/36)) - release v0.6.0 (#32) ([libp2p/go-libp2p-mplex#32](https://github.com/libp2p/go-libp2p-mplex/pull/32)) @@ -916,22 +915,8 @@ The more fully featured yamux stream multiplexer is now prioritized over mplex f - use the transport.Upgrader interface ([libp2p/go-ws-transport#110](https://github.com/libp2p/go-ws-transport/pull/110)) - sync: update CI config files (#108) ([libp2p/go-ws-transport#108](https://github.com/libp2p/go-ws-transport/pull/108)) - sync: update CI config files (#106) ([libp2p/go-ws-transport#106](https://github.com/libp2p/go-ws-transport/pull/106)) -- github.com/libp2p/go-yamux/v3 (null -> v3.1.1): - - release v3.1.1 (#88) ([libp2p/go-yamux#88](https://github.com/libp2p/go-yamux/pull/88)) - - feat: catch panics in yamux send/receive loops ([libp2p/go-yamux#86](https://github.com/libp2p/go-yamux/pull/86)) - - release v3.1.0 (#83) ([libp2p/go-yamux#83](https://github.com/libp2p/go-yamux/pull/83)) - - fix flaky TestPing test on Windows (#84) ([libp2p/go-yamux#84](https://github.com/libp2p/go-yamux/pull/84)) - - correctly release memory when the connection is closed (#81) ([libp2p/go-yamux#81](https://github.com/libp2p/go-yamux/pull/81)) - - release v3.0.2 ([libp2p/go-yamux#78](https://github.com/libp2p/go-yamux/pull/78)) - - fix memory accounting for window updates ([libp2p/go-yamux#77](https://github.com/libp2p/go-yamux/pull/77)) - - release v3.0.1 (#76) ([libp2p/go-yamux#76](https://github.com/libp2p/go-yamux/pull/76)) - - release v3.0.0 (#74) ([libp2p/go-yamux#74](https://github.com/libp2p/go-yamux/pull/74)) - - add a MemoryManager ([libp2p/go-yamux#69](https://github.com/libp2p/go-yamux/pull/69)) - - fix: ensure that pings don't get stuck behind writes ([libp2p/go-yamux#71](https://github.com/libp2p/go-yamux/pull/71)) - - sync: update CI config files (#68) ([libp2p/go-yamux#68](https://github.com/libp2p/go-yamux/pull/68)) - - limit the number of concurrent incoming streams ([libp2p/go-yamux#66](https://github.com/libp2p/go-yamux/pull/66)) - - drastically reduce allocations in ring buffer implementation (#64) ([libp2p/go-yamux#64](https://github.com/libp2p/go-yamux/pull/64)) -- github.com/lucas-clemente/quic-go (v0.24.0 -> v0.27.0): +- github.com/lucas-clemente/quic-go (v0.24.0 -> v0.27.1): + - don't send path MTU probe packets on a timer - stop using the deprecated net.Error.Temporary, update golangci-lint to v1.45.2 ([lucas-clemente/quic-go#3367](https://github.com/lucas-clemente/quic-go/pull/3367)) - add support for serializing Extended CONNECT requests (#3360) ([lucas-clemente/quic-go#3360](https://github.com/lucas-clemente/quic-go/pull/3360)) - improve the error thrown when building with an unsupported Go version ([lucas-clemente/quic-go#3364](https://github.com/lucas-clemente/quic-go/pull/3364)) @@ -991,44 +976,42 @@ The more fully featured yamux stream multiplexer is now prioritized over mplex f - don't commit the fuzzing binary ([multiformats/go-multistream#74](https://github.com/multiformats/go-multistream/pull/74)) - sync: update CI config files (#71) ([multiformats/go-multistream#71](https://github.com/multiformats/go-multistream/pull/71)) - remove Makefile ([multiformats/go-multistream#67](https://github.com/multiformats/go-multistream/pull/67)) -
    ### ❤ Contributors - | Contributor | Commits | Lines ± | Files Changed | |-------------|---------|---------|---------------| -| Marten Seemann | 350 | +14631/-12574 | 847 | -| Rod Vagg | 36 | +9362/-4300 | 231 | -| vyzo | 135 | +7963/-1785 | 233 | +| Marten Seemann | 347 | +14453/-12552 | 842 | +| Rod Vagg | 28 | +8848/-4033 | 214 | +| vyzo | 133 | +7959/-1783 | 231 | | hannahhoward | 40 | +3761/-1652 | 175 | -| Will | 26 | +4771/-404 | 118 | | Will Scott | 39 | +2885/-1784 | 93 | -| Daniel Martí | 36 | +3163/-996 | 114 | -| Adin Schmahmann | 43 | +3346/-522 | 114 | -| Steven Allen | 87 | +2465/-867 | 135 | -| Marcin Rataj | 26 | +2257/-815 | 62 | -| Masih H. Derkani | 14 | +2068/-861 | 71 | -| Gus Eggert | 22 | +2197/-680 | 94 | -| Lucas Molas | 26 | +1596/-576 | 88 | +| Daniel Martí | 32 | +3043/-969 | 103 | +| Adin Schmahmann | 48 | +3439/-536 | 121 | +| Gus Eggert | 29 | +2644/-788 | 123 | +| Steven Allen | 87 | +2417/-840 | 135 | +| Marcin Rataj | 29 | +2312/-942 | 75 | +| Will | 11 | +2520/-62 | 56 | +| Lucas Molas | 28 | +1602/-578 | 90 | | Raúl Kripalani | 18 | +1519/-271 | 38 | | Brian Tiger Chow | 20 | +833/-379 | 40 | +| Masih H. Derkani | 5 | +514/-460 | 8 | | Jeromy Johnson | 53 | +646/-302 | 83 | | Łukasz Magiera | 26 | +592/-245 | 43 | | Artem Mikheev | 2 | +616/-120 | 5 | | Franky W | 2 | +49/-525 | 9 | | Laurent Senta | 3 | +468/-82 | 52 | -| Hector Sanjuan | 29 | +245/-176 | 58 | +| Hector Sanjuan | 32 | +253/-187 | 62 | | Juan Batiz-Benet | 8 | +285/-80 | 18 | | Justin Johnson | 2 | +181/-88 | 2 | | Thibault Meunier | 5 | +216/-28 | 8 | -| Aayush Rajasekaran | 2 | +133/-103 | 11 | | James Wetter | 2 | +234/-1 | 2 | +| web3-bot | 36 | +158/-66 | 62 | | gammazero | 7 | +140/-84 | 12 | -| web3-bot | 35 | +157/-66 | 61 | | Rachel Chen | 2 | +165/-57 | 17 | +| Jorropo | 18 | +108/-99 | 26 | | Toby | 2 | +107/-86 | 11 | -| Jorropo | 16 | +97/-96 | 24 | +| Antonio Navarro Perez | 4 | +82/-103 | 9 | | Dominic Della Valle | 4 | +148/-33 | 6 | | Ian Davis | 2 | +152/-28 | 6 | | Kyle Huntsman | 2 | +172/-6 | 5 | @@ -1037,7 +1020,6 @@ The more fully featured yamux stream multiplexer is now prioritized over mplex f | Lars Gierth | 12 | +63/-54 | 20 | | Eric Myhre | 3 | +95/-15 | 8 | | Caian Benedicto | 1 | +69/-12 | 6 | -| whyrusleeping | 2 | +50/-26 | 7 | | Raúl Kripalani | 2 | +63/-13 | 2 | | Anton Petrov | 1 | +73/-0 | 1 | | hunjixin | 2 | +67/-2 | 5 | @@ -1048,22 +1030,23 @@ The more fully featured yamux stream multiplexer is now prioritized over mplex f | Manuel Alonso | 1 | +42/-9 | 2 | | Jakub Sztandera | 10 | +37/-13 | 13 | | Aarsh Shah | 1 | +39/-5 | 2 | -| pymq | 1 | +32/-8 | 2 | | Dave Justice | 1 | +32/-4 | 2 | | Tommi Virtanen | 3 | +23/-9 | 4 | | tarekbadr | 1 | +30/-1 | 1 | +| whyrusleeping | 1 | +26/-4 | 3 | | Petar Maymounkov | 2 | +30/-0 | 4 | -| Antonio Navarro Perez | 2 | +15/-13 | 7 | | rht | 3 | +17/-10 | 4 | | Miguel Mota | 1 | +23/-0 | 1 | | Manfred Touron | 1 | +21/-2 | 2 | | watjurk | 1 | +17/-5 | 1 | | SukkaW | 1 | +11/-11 | 5 | +| Nicholas Bollweg | 1 | +21/-0 | 1 | | Ho-Sheng Hsiao | 2 | +11/-10 | 6 | | chblodg | 1 | +18/-2 | 1 | | Friedel Ziegelmayer | 2 | +18/-0 | 2 | | Shu Shen | 2 | +15/-2 | 3 | | Peter Rabbitson | 1 | +15/-2 | 1 | +| galargh | 2 | +15/-0 | 2 | | ᴍᴀᴛᴛ ʙᴇʟʟ | 3 | +13/-1 | 4 | | aarshkshah1992 | 3 | +12/-2 | 3 | | RubenKelevra | 4 | +5/-8 | 5 | @@ -1074,18 +1057,22 @@ The more fully featured yamux stream multiplexer is now prioritized over mplex f | Elijah | 1 | +10/-0 | 1 | | Dimitris Apostolou | 2 | +5/-5 | 5 | | Michael Avila | 3 | +8/-1 | 4 | +| siiky | 3 | +4/-4 | 3 | | Somajit | 1 | +4/-4 | 1 | | Sherod Taylor | 1 | +0/-8 | 2 | | Eclésio Junior | 1 | +8/-0 | 1 | | godcong | 3 | +4/-3 | 3 | +| Piotr Galar | 3 | +3/-4 | 3 | | jwh | 1 | +6/-0 | 2 | +| dependabot[bot] | 1 | +3/-3 | 1 | | Volker Mische | 1 | +4/-2 | 1 | +| Aayush Rajasekaran | 1 | +3/-3 | 1 | | rene | 2 | +3/-2 | 2 | | keks | 1 | +5/-0 | 1 | | Hlib | 1 | +4/-1 | 2 | | Arash Payan | 1 | +5/-0 | 1 | -| siiky | 1 | +2/-2 | 1 | | Wayback Archiver | 1 | +2/-2 | 1 | +| T Mo | 1 | +2/-2 | 1 | | Ju Huo | 1 | +2/-2 | 1 | | Ivan | 2 | +2/-2 | 2 | | Ettore Di Giacinto | 2 | +3/-1 | 2 | @@ -1102,12 +1089,12 @@ The more fully featured yamux stream multiplexer is now prioritized over mplex f | Glenn | 1 | +1/-1 | 1 | | George Antoniadis | 1 | +1/-1 | 1 | | David Florness | 1 | +1/-1 | 1 | +| Daniel Norman | 1 | +1/-1 | 1 | | Coenie Beyers | 1 | +1/-1 | 1 | | Benedikt Spies | 1 | +1/-1 | 1 | | Abdul Rauf | 1 | +1/-1 | 1 | | makeworld | 1 | +1/-0 | 1 | | ignoramous | 1 | +0/-1 | 1 | -| galargh | 1 | +1/-0 | 1 | | Omicron166 | 1 | +0/-1 | 1 | | Jan Winkelmann | 1 | +1/-0 | 1 | | Dr Ian Preston | 1 | +1/-0 | 1 | From 3b88b441b02c48a55d34c158706a4592db5e2eac Mon Sep 17 00:00:00 2001 From: Gus Eggert Date: Wed, 8 Jun 2022 13:53:24 -0400 Subject: [PATCH 414/414] Release v0.13.0 --- version.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/version.go b/version.go index 9bdf2c6fed0..944af1c3898 100644 --- a/version.go +++ b/version.go @@ -11,7 +11,7 @@ import ( var CurrentCommit string // CurrentVersionNumber is the current application's version literal -const CurrentVersionNumber = "0.13.0-rc1" +const CurrentVersionNumber = "0.13.0" const ApiVersion = "/go-ipfs/" + CurrentVersionNumber + "/"

    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