@cryptotaxi247 / kubo / commits / 0e312f5ca

initial vendoring of libp2p outside of the repo with gx

License: MIT Signed-off-by: Jeromy <jeromyj@gmail.com>

Jeromy committed Jan 27, 2016 at 14:28 UTC 0e312f5caff049073b3a6d8c9ff693c3c7389495
382 files changed +475 -16988
Godeps/_workspace/src/bazil.org/fuse/fs/bench/bench_test.go
+1 -1
@@ -10,7 +10,7 @@ import (
10 "github.com/ipfs/go-ipfs/Godeps/_workspace/src/bazil.org/fuse"
11 "github.com/ipfs/go-ipfs/Godeps/_workspace/src/bazil.org/fuse/fs"
12 "github.com/ipfs/go-ipfs/Godeps/_workspace/src/bazil.org/fuse/fs/fstestutil"
13 - "github.com/ipfs/go-ipfs/Godeps/_workspace/src/golang.org/x/net/context"
13 + "gx/ipfs/QmZy2y8t9zQH2a1b8q2ZSLKp17ATuJoCNxxyMFG5qFExpt/go-net/context"
14 )
15
16 type benchConfig struct {
Godeps/_workspace/src/bazil.org/fuse/fs/fstestutil/record/record.go
+1 -1
@@ -6,7 +6,7 @@ import (
6
7 "github.com/ipfs/go-ipfs/Godeps/_workspace/src/bazil.org/fuse"
8 "github.com/ipfs/go-ipfs/Godeps/_workspace/src/bazil.org/fuse/fs"
9 - "github.com/ipfs/go-ipfs/Godeps/_workspace/src/golang.org/x/net/context"
9 + "gx/ipfs/QmZy2y8t9zQH2a1b8q2ZSLKp17ATuJoCNxxyMFG5qFExpt/go-net/context"
10 )
11
12 // Writes gathers data from FUSE Write calls.
Godeps/_workspace/src/bazil.org/fuse/fs/fstestutil/record/wait.go
+1 -1
@@ -6,7 +6,7 @@ import (
6
7 "github.com/ipfs/go-ipfs/Godeps/_workspace/src/bazil.org/fuse"
8 "github.com/ipfs/go-ipfs/Godeps/_workspace/src/bazil.org/fuse/fs"
9 - "github.com/ipfs/go-ipfs/Godeps/_workspace/src/golang.org/x/net/context"
9 + "gx/ipfs/QmZy2y8t9zQH2a1b8q2ZSLKp17ATuJoCNxxyMFG5qFExpt/go-net/context"
10 )
11
12 type nothing struct{}
Godeps/_workspace/src/bazil.org/fuse/fs/fstestutil/testfs.go
+1 -1
@@ -5,7 +5,7 @@ import (
5
6 "github.com/ipfs/go-ipfs/Godeps/_workspace/src/bazil.org/fuse"
7 "github.com/ipfs/go-ipfs/Godeps/_workspace/src/bazil.org/fuse/fs"
8 - "github.com/ipfs/go-ipfs/Godeps/_workspace/src/golang.org/x/net/context"
8 + "gx/ipfs/QmZy2y8t9zQH2a1b8q2ZSLKp17ATuJoCNxxyMFG5qFExpt/go-net/context"
9 )
10
11 // SimpleFS is a trivial FS that just implements the Root method.
Godeps/_workspace/src/bazil.org/fuse/fs/serve.go
+1 -1
@@ -14,7 +14,7 @@ import (
14 "sync"
15 "time"
16
17 - "github.com/ipfs/go-ipfs/Godeps/_workspace/src/golang.org/x/net/context"
17 + "gx/ipfs/QmZy2y8t9zQH2a1b8q2ZSLKp17ATuJoCNxxyMFG5qFExpt/go-net/context"
18 )
19
20 import (
Godeps/_workspace/src/bazil.org/fuse/fs/serve_test.go
+1 -1
@@ -21,7 +21,7 @@ import (
21 "github.com/ipfs/go-ipfs/Godeps/_workspace/src/bazil.org/fuse/fs/fstestutil/record"
22 "github.com/ipfs/go-ipfs/Godeps/_workspace/src/bazil.org/fuse/fuseutil"
23 "github.com/ipfs/go-ipfs/Godeps/_workspace/src/bazil.org/fuse/syscallx"
24 - "github.com/ipfs/go-ipfs/Godeps/_workspace/src/golang.org/x/net/context"
24 + "gx/ipfs/QmZy2y8t9zQH2a1b8q2ZSLKp17ATuJoCNxxyMFG5qFExpt/go-net/context"
25 )
26
27 // TO TEST:
Godeps/_workspace/src/bazil.org/fuse/fs/tree.go
+1 -1
@@ -7,7 +7,7 @@ import (
7 pathpkg "path"
8 "strings"
9
10 - "github.com/ipfs/go-ipfs/Godeps/_workspace/src/golang.org/x/net/context"
10 + "gx/ipfs/QmZy2y8t9zQH2a1b8q2ZSLKp17ATuJoCNxxyMFG5qFExpt/go-net/context"
11 )
12
13 import (
Godeps/_workspace/src/bazil.org/fuse/hellofs/hello.go
+1 -1
@@ -10,7 +10,7 @@ import (
10 "github.com/ipfs/go-ipfs/Godeps/_workspace/src/bazil.org/fuse"
11 "github.com/ipfs/go-ipfs/Godeps/_workspace/src/bazil.org/fuse/fs"
12 _ "github.com/ipfs/go-ipfs/Godeps/_workspace/src/bazil.org/fuse/fs/fstestutil"
13 - "github.com/ipfs/go-ipfs/Godeps/_workspace/src/golang.org/x/net/context"
13 + "gx/ipfs/QmZy2y8t9zQH2a1b8q2ZSLKp17ATuJoCNxxyMFG5qFExpt/go-net/context"
14 )
15
16 var Usage = func() {
Godeps/_workspace/src/bazil.org/fuse/options_test.go
+1 -1
@@ -9,7 +9,7 @@ import (
9 "github.com/ipfs/go-ipfs/Godeps/_workspace/src/bazil.org/fuse"
10 "github.com/ipfs/go-ipfs/Godeps/_workspace/src/bazil.org/fuse/fs"
11 "github.com/ipfs/go-ipfs/Godeps/_workspace/src/bazil.org/fuse/fs/fstestutil"
12 - "github.com/ipfs/go-ipfs/Godeps/_workspace/src/golang.org/x/net/context"
12 + "gx/ipfs/QmZy2y8t9zQH2a1b8q2ZSLKp17ATuJoCNxxyMFG5qFExpt/go-net/context"
13 )
14
15 func init() {
Godeps/_workspace/src/github.com/alecthomas/kingpin/app_test.go
+1 -1
@@ -3,7 +3,7 @@ package kingpin
3 import (
4 "io/ioutil"
5
6 - "github.com/stretchr/testify/assert"
6 + "gx/ipfs/QmZwjfAKWe7vWZ8f48u7AGA1xYfzR1iCD9A2XSCYFRBWot/testify/assert"
7
8 "testing"
9 "time"
Godeps/_workspace/src/github.com/alecthomas/kingpin/args_test.go
+1 -1
@@ -4,7 +4,7 @@ import (
4 "io/ioutil"
5 "testing"
6
7 - "github.com/stretchr/testify/assert"
7 + "gx/ipfs/QmZwjfAKWe7vWZ8f48u7AGA1xYfzR1iCD9A2XSCYFRBWot/testify/assert"
8 )
9
10 func TestArgRemainder(t *testing.T) {
Godeps/_workspace/src/github.com/alecthomas/kingpin/cmd_test.go
+1 -1
@@ -3,7 +3,7 @@ package kingpin
3 import (
4 "strings"
5
6 - "github.com/stretchr/testify/assert"
6 + "gx/ipfs/QmZwjfAKWe7vWZ8f48u7AGA1xYfzR1iCD9A2XSCYFRBWot/testify/assert"
7
8 "testing"
9 )
Godeps/_workspace/src/github.com/alecthomas/kingpin/flags_test.go
+1 -1
@@ -4,7 +4,7 @@ import (
4 "io/ioutil"
5 "os"
6
7 - "github.com/stretchr/testify/assert"
7 + "gx/ipfs/QmZwjfAKWe7vWZ8f48u7AGA1xYfzR1iCD9A2XSCYFRBWot/testify/assert"
8
9 "testing"
10 )
Godeps/_workspace/src/github.com/alecthomas/kingpin/parser_test.go
+1 -1
@@ -5,7 +5,7 @@ import (
5 "os"
6 "testing"
7
8 - "github.com/stretchr/testify/assert"
8 + "gx/ipfs/QmZwjfAKWe7vWZ8f48u7AGA1xYfzR1iCD9A2XSCYFRBWot/testify/assert"
9 )
10
11 func TestParserExpandFromFile(t *testing.T) {
Godeps/_workspace/src/github.com/alecthomas/kingpin/parsers_test.go
+1 -1
@@ -6,7 +6,7 @@ import (
6 "net/url"
7 "os"
8
9 - "github.com/stretchr/testify/assert"
9 + "gx/ipfs/QmZwjfAKWe7vWZ8f48u7AGA1xYfzR1iCD9A2XSCYFRBWot/testify/assert"
10
11 "testing"
12 )
Godeps/_workspace/src/github.com/alecthomas/kingpin/usage_test.go
+1 -1
@@ -5,7 +5,7 @@ import (
5 "strings"
6 "testing"
7
8 - "github.com/stretchr/testify/assert"
8 + "gx/ipfs/QmZwjfAKWe7vWZ8f48u7AGA1xYfzR1iCD9A2XSCYFRBWot/testify/assert"
9 )
10
11 func TestFormatTwoColumns(t *testing.T) {
Godeps/_workspace/src/github.com/alecthomas/kingpin/values_test.go
+1 -1
@@ -1,7 +1,7 @@
1 package kingpin
2
3 import (
4 - "github.com/stretchr/testify/assert"
4 + "gx/ipfs/QmZwjfAKWe7vWZ8f48u7AGA1xYfzR1iCD9A2XSCYFRBWot/testify/assert"
5
6 "testing"
7 )
Godeps/_workspace/src/github.com/alecthomas/units/bytes_test.go
+1 -1
@@ -3,7 +3,7 @@ package units
3 import (
4 "testing"
5
6 - "github.com/stretchr/testify/assert"
6 + "gx/ipfs/QmZwjfAKWe7vWZ8f48u7AGA1xYfzR1iCD9A2XSCYFRBWot/testify/assert"
7 )
8
9 func TestBase2BytesString(t *testing.T) {
Godeps/_workspace/src/github.com/anacrolix/missinggo/addr_test.go
+1 -1
@@ -3,7 +3,7 @@ package missinggo
3 import (
4 "testing"
5
6 - "github.com/stretchr/testify/assert"
6 + "gx/ipfs/QmZwjfAKWe7vWZ8f48u7AGA1xYfzR1iCD9A2XSCYFRBWot/testify/assert"
7 )
8
9 func TestSplitHostPort(t *testing.T) {
Godeps/_workspace/src/github.com/anacrolix/missinggo/filecache/cache_test.go
+2 -2
@@ -7,8 +7,8 @@ import (
7 "path/filepath"
8 "testing"
9
10 - "github.com/stretchr/testify/assert"
11 - "github.com/stretchr/testify/require"
10 + "gx/ipfs/QmZwjfAKWe7vWZ8f48u7AGA1xYfzR1iCD9A2XSCYFRBWot/testify/assert"
11 + "gx/ipfs/QmZwjfAKWe7vWZ8f48u7AGA1xYfzR1iCD9A2XSCYFRBWot/testify/require"
12
13 "github.com/ipfs/go-ipfs/Godeps/_workspace/src/github.com/anacrolix/missinggo"
14 )
Godeps/_workspace/src/github.com/anacrolix/missinggo/filecache/lruitems.go
+1 -1
@@ -4,7 +4,7 @@ import (
4 "container/list"
5 "io"
6
7 - "github.com/cznic/b"
7 + "gx/ipfs/QmVgtwPh2NNoZTSyYkr4Y3epaYACBKf26r8hV6EFA7xS6c/b"
8 )
9
10 type Iterator interface {
Godeps/_workspace/src/github.com/anacrolix/missinggo/httpcontentrange_test.go
+1 -1
@@ -3,7 +3,7 @@ package missinggo
3 import (
4 "testing"
5
6 - "github.com/stretchr/testify/assert"
6 + "gx/ipfs/QmZwjfAKWe7vWZ8f48u7AGA1xYfzR1iCD9A2XSCYFRBWot/testify/assert"
7 )
8
9 func TestParseHTTPContentRange(t *testing.T) {
Godeps/_workspace/src/github.com/anacrolix/missinggo/itertools/groupby_test.go
+1 -1
@@ -3,7 +3,7 @@ package itertools
3 import (
4 "testing"
5
6 - "github.com/stretchr/testify/require"
6 + "gx/ipfs/QmZwjfAKWe7vWZ8f48u7AGA1xYfzR1iCD9A2XSCYFRBWot/testify/require"
7 )
8
9 func TestGroupByKey(t *testing.T) {
Godeps/_workspace/src/github.com/anacrolix/missinggo/itertools/iterator_test.go
+1 -1
@@ -3,7 +3,7 @@ package itertools
3 import (
4 "testing"
5
6 - "github.com/stretchr/testify/require"
6 + "gx/ipfs/QmZwjfAKWe7vWZ8f48u7AGA1xYfzR1iCD9A2XSCYFRBWot/testify/require"
7 )
8
9 func TestIterator(t *testing.T) {
Godeps/_workspace/src/github.com/anacrolix/missinggo/perf/perf_test.go
+1 -1
@@ -7,7 +7,7 @@ import (
7 "time"
8
9 "github.com/ipfs/go-ipfs/Godeps/_workspace/src/github.com/bradfitz/iter"
10 - "github.com/stretchr/testify/assert"
10 + "gx/ipfs/QmZwjfAKWe7vWZ8f48u7AGA1xYfzR1iCD9A2XSCYFRBWot/testify/assert"
11 )
12
13 func TestTimer(t *testing.T) {
Godeps/_workspace/src/github.com/anacrolix/missinggo/pubsub/pubsub_test.go
+2 -2
@@ -5,8 +5,8 @@ import (
5 "testing"
6
7 "github.com/ipfs/go-ipfs/Godeps/_workspace/src/github.com/bradfitz/iter"
8 - "github.com/stretchr/testify/assert"
9 - "github.com/stretchr/testify/require"
8 + "gx/ipfs/QmZwjfAKWe7vWZ8f48u7AGA1xYfzR1iCD9A2XSCYFRBWot/testify/assert"
9 + "gx/ipfs/QmZwjfAKWe7vWZ8f48u7AGA1xYfzR1iCD9A2XSCYFRBWot/testify/require"
10 )
11
12 func TestDoubleClose(t *testing.T) {
Godeps/_workspace/src/github.com/anacrolix/missinggo/wolf_test.go
+1 -1
@@ -3,7 +3,7 @@ package missinggo
3 import (
4 "testing"
5
6 - "github.com/stretchr/testify/require"
6 + "gx/ipfs/QmZwjfAKWe7vWZ8f48u7AGA1xYfzR1iCD9A2XSCYFRBWot/testify/require"
7 )
8
9 func cryHeard() bool {
Godeps/_workspace/src/github.com/anacrolix/utp/cmd/ucat/ucat.go
+1 -1
@@ -9,7 +9,7 @@ import (
9 "os"
10 "os/signal"
11
12 - "github.com/anacrolix/envpprof"
12 + "gx/ipfs/QmazECKVXFsA3J6cHAqf8HeTDUB8zARjfo75nxE6o63AAp/envpprof"
13
14 "github.com/ipfs/go-ipfs/Godeps/_workspace/src/github.com/anacrolix/utp"
15 )
Godeps/_workspace/src/github.com/anacrolix/utp/utp_test.go
+2 -2
@@ -11,10 +11,10 @@ import (
11 "testing"
12 "time"
13
14 - _ "github.com/anacrolix/envpprof"
14 "github.com/ipfs/go-ipfs/Godeps/_workspace/src/github.com/anacrolix/missinggo"
15 "github.com/ipfs/go-ipfs/Godeps/_workspace/src/github.com/bradfitz/iter"
17 - "github.com/stretchr/testify/require"
16 + "gx/ipfs/QmZwjfAKWe7vWZ8f48u7AGA1xYfzR1iCD9A2XSCYFRBWot/testify/require"
17 + _ "gx/ipfs/QmazECKVXFsA3J6cHAqf8HeTDUB8zARjfo75nxE6o63AAp/envpprof"
18 )
19
20 func init() {
Godeps/_workspace/src/github.com/docker/spdystream/ws/connection.go
+1 -1
@@ -1,7 +1,7 @@
1 package ws
2
3 import (
4 - "github.com/gorilla/websocket"
4 + "gx/ipfs/QmUe1Ljrtwz5NSKqJRw5mgjthSSfW7g94hkGRqiQs5aJna/websocket"
5 "io"
6 "log"
7 "time"
Godeps/_workspace/src/github.com/docker/spdystream/ws/ws_test.go
+1 -1
@@ -2,8 +2,8 @@ package ws
2
3 import (
4 "bytes"
5 - "github.com/gorilla/websocket"
5 "github.com/ipfs/go-ipfs/Godeps/_workspace/src/github.com/docker/spdystream"
6 + "gx/ipfs/QmUe1Ljrtwz5NSKqJRw5mgjthSSfW7g94hkGRqiQs5aJna/websocket"
7 "io"
8 "log"
9 "net/http"
Godeps/_workspace/src/github.com/gogo/protobuf/io/io_test.go
+1 -1
@@ -31,8 +31,8 @@ package io_test
31 import (
32 "bytes"
33 "encoding/binary"
34 - "github.com/gogo/protobuf/test"
34 "github.com/ipfs/go-ipfs/Godeps/_workspace/src/github.com/gogo/protobuf/io"
35 + "gx/ipfs/QmZ4Qi3GaRbjcx28Sme5eMH7RQjGkt8wHxt2a65oLaeFEV/gogo-protobuf/test"
36 goio "io"
37 "math/rand"
38 "testing"
Godeps/_workspace/src/github.com/ipfs/go-datastore/flatfs/flatfs.go
+1 -1
@@ -17,7 +17,7 @@ import (
17 "github.com/ipfs/go-ipfs/Godeps/_workspace/src/github.com/ipfs/go-datastore/query"
18 "github.com/ipfs/go-ipfs/Godeps/_workspace/src/github.com/jbenet/go-os-rename"
19
20 - logging "github.com/ipfs/go-ipfs/vendor/QmQg1J6vikuXF9oDvm4wpdeAUvvkVEKW1EYDw9HhTMnP2b/go-log"
20 + logging "gx/ipfs/QmaPaGNE2GqnfJjRRpQuQuFHuJn4FZvsrGxdik4kgxCkBi/go-log"
21 )
22
23 var log = logging.Logger("flatfs")
Godeps/_workspace/src/github.com/jbenet/go-context/frac/fracctx.go
+1 -1
@@ -4,7 +4,7 @@ package ctxext
4 import (
5 "time"
6
7 - context "github.com/ipfs/go-ipfs/Godeps/_workspace/src/golang.org/x/net/context"
7 + context "gx/ipfs/QmZy2y8t9zQH2a1b8q2ZSLKp17ATuJoCNxxyMFG5qFExpt/go-net/context"
8 )
9
10 // WithDeadlineFraction returns a Context with a fraction of the
Godeps/_workspace/src/github.com/jbenet/go-context/frac/fracctx_test.go
+1 -1
@@ -5,7 +5,7 @@ import (
5 "testing"
6 "time"
7
8 - context "github.com/ipfs/go-ipfs/Godeps/_workspace/src/golang.org/x/net/context"
8 + context "gx/ipfs/QmZy2y8t9zQH2a1b8q2ZSLKp17ATuJoCNxxyMFG5qFExpt/go-net/context"
9 )
10
11 // this test is on the context tool itself, not our stuff. it's for sanity on ours.
Godeps/_workspace/src/github.com/jbenet/go-context/io/ctxio.go
+1 -1
@@ -13,7 +13,7 @@ package ctxio
13 import (
14 "io"
15
16 - context "github.com/ipfs/go-ipfs/Godeps/_workspace/src/golang.org/x/net/context"
16 + context "gx/ipfs/QmZy2y8t9zQH2a1b8q2ZSLKp17ATuJoCNxxyMFG5qFExpt/go-net/context"
17 )
18
19 type ioret struct {
Godeps/_workspace/src/github.com/jbenet/go-context/io/ctxio_test.go
+1 -1
@@ -6,7 +6,7 @@ import (
6 "testing"
7 "time"
8
9 - context "github.com/ipfs/go-ipfs/Godeps/_workspace/src/golang.org/x/net/context"
9 + context "gx/ipfs/QmZy2y8t9zQH2a1b8q2ZSLKp17ATuJoCNxxyMFG5qFExpt/go-net/context"
10 )
11
12 func TestReader(t *testing.T) {
Godeps/_workspace/src/github.com/jbenet/go-msgio/chan_test.go
+1 -1
@@ -2,7 +2,7 @@ package msgio
2
3 import (
4 "bytes"
5 - randbuf "github.com/jbenet/go-randbuf"
5 + randbuf "gx/ipfs/QmYNGtJHgaGZkpzq8yG6Wxqm6EQTKqgpBfnyyGBKbZeDUi/go-randbuf"
6 "io"
7 "math/rand"
8 "testing"
Godeps/_workspace/src/github.com/jbenet/go-msgio/msgio_test.go
+1 -1
@@ -3,7 +3,7 @@ package msgio
3 import (
4 "bytes"
5 "fmt"
6 - randbuf "github.com/jbenet/go-randbuf"
6 + randbuf "gx/ipfs/QmYNGtJHgaGZkpzq8yG6Wxqm6EQTKqgpBfnyyGBKbZeDUi/go-randbuf"
7 "io"
8 "math/rand"
9 "sync"
Godeps/_workspace/src/github.com/jbenet/go-multiaddr-net/convert.go
+2 -2
@@ -5,8 +5,8 @@ import (
5 "net"
6 "strings"
7
8 - ma "github.com/ipfs/go-ipfs/Godeps/_workspace/src/github.com/jbenet/go-multiaddr"
9 - utp "github.com/ipfs/go-ipfs/Godeps/_workspace/src/github.com/jbenet/go-multiaddr-net/utp"
8 + ma "gx/ipfs/QmR3JkmZBKYXgNMNsNZawm914455Qof3PEopwuVSeXG7aV/go-multiaddr"
9 + utp "gx/ipfs/QmYtzQmUwPFGxjCXctJ8e6GXS8sYfoXy2pdeMbS5SFWqRi/go-multiaddr-net/utp"
10 )
11
12 var errIncorrectNetAddr = fmt.Errorf("incorrect network addr conversion")
Godeps/_workspace/src/github.com/jbenet/go-multiaddr-net/convert_test.go
+2 -2
@@ -4,8 +4,8 @@ import (
4 "net"
5 "testing"
6
7 - ma "github.com/ipfs/go-ipfs/Godeps/_workspace/src/github.com/jbenet/go-multiaddr"
8 - mautp "github.com/ipfs/go-ipfs/Godeps/_workspace/src/github.com/jbenet/go-multiaddr-net/utp"
7 + ma "gx/ipfs/QmR3JkmZBKYXgNMNsNZawm914455Qof3PEopwuVSeXG7aV/go-multiaddr"
8 + mautp "gx/ipfs/QmYtzQmUwPFGxjCXctJ8e6GXS8sYfoXy2pdeMbS5SFWqRi/go-multiaddr-net/utp"
9 )
10
11 type GenFunc func() (ma.Multiaddr, error)
Godeps/_workspace/src/github.com/jbenet/go-multiaddr-net/ip.go
+1 -1
@@ -3,7 +3,7 @@ package manet
3 import (
4 "bytes"
5
6 - ma "github.com/ipfs/go-ipfs/Godeps/_workspace/src/github.com/jbenet/go-multiaddr"
6 + ma "gx/ipfs/QmR3JkmZBKYXgNMNsNZawm914455Qof3PEopwuVSeXG7aV/go-multiaddr"
7 )
8
9 // Loopback Addresses
Godeps/_workspace/src/github.com/jbenet/go-multiaddr-net/multiaddr/multiaddr.go
+2 -2
@@ -6,8 +6,8 @@ import (
6 "fmt"
7 "os"
8
9 - ma "github.com/ipfs/go-ipfs/Godeps/_workspace/src/github.com/jbenet/go-multiaddr"
10 - manet "github.com/ipfs/go-ipfs/Godeps/_workspace/src/github.com/jbenet/go-multiaddr-net"
9 + ma "gx/ipfs/QmR3JkmZBKYXgNMNsNZawm914455Qof3PEopwuVSeXG7aV/go-multiaddr"
10 + manet "gx/ipfs/QmYtzQmUwPFGxjCXctJ8e6GXS8sYfoXy2pdeMbS5SFWqRi/go-multiaddr-net"
11 )
12
13 // flags
Godeps/_workspace/src/github.com/jbenet/go-multiaddr-net/net.go
+2 -2
@@ -4,8 +4,8 @@ import (
4 "fmt"
5 "net"
6
7 - ma "github.com/ipfs/go-ipfs/Godeps/_workspace/src/github.com/jbenet/go-multiaddr"
8 - mautp "github.com/ipfs/go-ipfs/Godeps/_workspace/src/github.com/jbenet/go-multiaddr-net/utp"
7 + ma "gx/ipfs/QmR3JkmZBKYXgNMNsNZawm914455Qof3PEopwuVSeXG7aV/go-multiaddr"
8 + mautp "gx/ipfs/QmYtzQmUwPFGxjCXctJ8e6GXS8sYfoXy2pdeMbS5SFWqRi/go-multiaddr-net/utp"
9 )
10
11 // Conn is the equivalent of a net.Conn object. It is the
Godeps/_workspace/src/github.com/jbenet/go-multiaddr-net/net_test.go
+1 -1
@@ -7,7 +7,7 @@ import (
7 "sync"
8 "testing"
9
10 - ma "github.com/ipfs/go-ipfs/Godeps/_workspace/src/github.com/jbenet/go-multiaddr"
10 + ma "gx/ipfs/QmR3JkmZBKYXgNMNsNZawm914455Qof3PEopwuVSeXG7aV/go-multiaddr"
11 )
12
13 func newMultiaddr(t *testing.T, m string) ma.Multiaddr {
Godeps/_workspace/src/github.com/jbenet/go-reuseport/test/main.go
+1 -1
@@ -7,7 +7,7 @@ import (
7 "os"
8
9 reuse "github.com/ipfs/go-ipfs/Godeps/_workspace/src/github.com/jbenet/go-reuseport"
10 - resolve "github.com/jbenet/go-net-resolve-addr"
10 + resolve "gx/ipfs/Qma73Sqt13DzHzveZ667BBfraM7MuMrPepUXjmv812JhRS/go-net-resolve-addr"
11 )
12
13 func main() {
Godeps/_workspace/src/github.com/jbenet/go-stream-muxer/muxado/muxado.go
+1 -1
@@ -3,8 +3,8 @@ package peerstream_muxado
3 import (
4 "net"
5
6 - muxado "github.com/inconshreveable/muxado"
6 smux "github.com/ipfs/go-ipfs/Godeps/_workspace/src/github.com/jbenet/go-stream-muxer"
7 + muxado "gx/ipfs/QmaZ9WavcC9EKocNHof8onR8JHci2Qt8AuybkFaxJdr51Q/muxado"
8 )
9
10 // stream implements smux.Stream using a ss.Stream
Godeps/_workspace/src/github.com/jbenet/goprocess/context/context.go
+1 -1
@@ -2,7 +2,7 @@ package goprocessctx
2
3 import (
4 goprocess "github.com/ipfs/go-ipfs/Godeps/_workspace/src/github.com/jbenet/goprocess"
5 - context "github.com/ipfs/go-ipfs/Godeps/_workspace/src/golang.org/x/net/context"
5 + context "gx/ipfs/QmZy2y8t9zQH2a1b8q2ZSLKp17ATuJoCNxxyMFG5qFExpt/go-net/context"
6 )
7
8 // WithContext constructs and returns a Process that respects
Godeps/_workspace/src/github.com/jbenet/goprocess/context/derive.go
+1 -1
@@ -5,7 +5,7 @@ import (
5 "time"
6
7 goprocess "github.com/ipfs/go-ipfs/Godeps/_workspace/src/github.com/jbenet/goprocess"
8 - "github.com/ipfs/go-ipfs/Godeps/_workspace/src/golang.org/x/net/context"
8 + "gx/ipfs/QmZy2y8t9zQH2a1b8q2ZSLKp17ATuJoCNxxyMFG5qFExpt/go-net/context"
9 )
10
11 const (
Godeps/_workspace/src/github.com/jbenet/goprocess/periodic/periodic_test.go
+1 -1
@@ -5,7 +5,7 @@ import (
5 "time"
6
7 gp "github.com/ipfs/go-ipfs/Godeps/_workspace/src/github.com/jbenet/goprocess"
8 - ci "github.com/jbenet/go-cienv"
8 + ci "gx/ipfs/QmZcUXuzsUSvxNj9pmU112V8L5kGUFMTYCdFcAbQ3Zj5cp/go-cienv"
9 )
10
11 var (
Godeps/_workspace/src/github.com/whyrusleeping/multiaddr-filter/mask.go
+1 -1
@@ -6,7 +6,7 @@ import (
6 "net"
7 "strings"
8
9 - manet "github.com/ipfs/go-ipfs/Godeps/_workspace/src/github.com/jbenet/go-multiaddr-net"
9 + manet "gx/ipfs/QmYtzQmUwPFGxjCXctJ8e6GXS8sYfoXy2pdeMbS5SFWqRi/go-multiaddr-net"
10 )
11
12 var ErrInvalidFormat = errors.New("invalid multiaddr-filter format")
Godeps/_workspace/src/golang.org/x/net/context/withtimeout_test.go
+1 -1
@@ -8,7 +8,7 @@ import (
8 "fmt"
9 "time"
10
11 - "github.com/ipfs/go-ipfs/Godeps/_workspace/src/golang.org/x/net/context"
11 + "gx/ipfs/QmZy2y8t9zQH2a1b8q2ZSLKp17ATuJoCNxxyMFG5qFExpt/go-net/context"
12 )
13
14 func ExampleWithTimeout() {
Godeps/_workspace/src/golang.org/x/net/ipv4/example_test.go
+1 -1
@@ -14,7 +14,7 @@ import (
14
15 "github.com/ipfs/go-ipfs/Godeps/_workspace/src/golang.org/x/net/internal/iana"
16 "github.com/ipfs/go-ipfs/Godeps/_workspace/src/golang.org/x/net/ipv4"
17 - "golang.org/x/net/icmp"
17 + "gx/ipfs/QmZy2y8t9zQH2a1b8q2ZSLKp17ATuJoCNxxyMFG5qFExpt/go-net/icmp"
18 )
19
20 func ExampleConn_markingTCP() {
Godeps/_workspace/src/golang.org/x/net/ipv4/icmp_test.go
+1 -1
@@ -11,7 +11,7 @@ import (
11 "testing"
12
13 "github.com/ipfs/go-ipfs/Godeps/_workspace/src/golang.org/x/net/ipv4"
14 - "golang.org/x/net/internal/nettest"
14 + "gx/ipfs/QmZy2y8t9zQH2a1b8q2ZSLKp17ATuJoCNxxyMFG5qFExpt/go-net/internal/nettest"
15 )
16
17 var icmpStringTests = []struct {
Godeps/_workspace/src/golang.org/x/net/ipv4/multicast_test.go
+2 -2
@@ -14,8 +14,8 @@ import (
14
15 "github.com/ipfs/go-ipfs/Godeps/_workspace/src/golang.org/x/net/internal/iana"
16 "github.com/ipfs/go-ipfs/Godeps/_workspace/src/golang.org/x/net/ipv4"
17 - "golang.org/x/net/icmp"
18 - "golang.org/x/net/internal/nettest"
17 + "gx/ipfs/QmZy2y8t9zQH2a1b8q2ZSLKp17ATuJoCNxxyMFG5qFExpt/go-net/icmp"
18 + "gx/ipfs/QmZy2y8t9zQH2a1b8q2ZSLKp17ATuJoCNxxyMFG5qFExpt/go-net/internal/nettest"
19 )
20
21 var packetConnReadWriteMulticastUDPTests = []struct {
Godeps/_workspace/src/golang.org/x/net/ipv4/multicastlistener_test.go
+1 -1
@@ -10,7 +10,7 @@ import (
10 "testing"
11
12 "github.com/ipfs/go-ipfs/Godeps/_workspace/src/golang.org/x/net/ipv4"
13 - "golang.org/x/net/internal/nettest"
13 + "gx/ipfs/QmZy2y8t9zQH2a1b8q2ZSLKp17ATuJoCNxxyMFG5qFExpt/go-net/internal/nettest"
14 )
15
16 var udpMultipleGroupListenerTests = []net.Addr{
Godeps/_workspace/src/golang.org/x/net/ipv4/multicastsockopt_test.go
+1 -1
@@ -10,7 +10,7 @@ import (
10 "testing"
11
12 "github.com/ipfs/go-ipfs/Godeps/_workspace/src/golang.org/x/net/ipv4"
13 - "golang.org/x/net/internal/nettest"
13 + "gx/ipfs/QmZy2y8t9zQH2a1b8q2ZSLKp17ATuJoCNxxyMFG5qFExpt/go-net/internal/nettest"
14 )
15
16 var packetConnMulticastSocketOptionTests = []struct {
Godeps/_workspace/src/golang.org/x/net/ipv4/readwrite_test.go
+1 -1
@@ -12,7 +12,7 @@ import (
12 "testing"
13
14 "github.com/ipfs/go-ipfs/Godeps/_workspace/src/golang.org/x/net/ipv4"
15 - "golang.org/x/net/internal/nettest"
15 + "gx/ipfs/QmZy2y8t9zQH2a1b8q2ZSLKp17ATuJoCNxxyMFG5qFExpt/go-net/internal/nettest"
16 )
17
18 func benchmarkUDPListener() (net.PacketConn, net.Addr, error) {
Godeps/_workspace/src/golang.org/x/net/ipv4/unicast_test.go
+2 -2
@@ -14,8 +14,8 @@ import (
14
15 "github.com/ipfs/go-ipfs/Godeps/_workspace/src/golang.org/x/net/internal/iana"
16 "github.com/ipfs/go-ipfs/Godeps/_workspace/src/golang.org/x/net/ipv4"
17 - "golang.org/x/net/icmp"
18 - "golang.org/x/net/internal/nettest"
17 + "gx/ipfs/QmZy2y8t9zQH2a1b8q2ZSLKp17ATuJoCNxxyMFG5qFExpt/go-net/icmp"
18 + "gx/ipfs/QmZy2y8t9zQH2a1b8q2ZSLKp17ATuJoCNxxyMFG5qFExpt/go-net/internal/nettest"
19 )
20
21 func TestPacketConnReadWriteUnicastUDP(t *testing.T) {
Godeps/_workspace/src/golang.org/x/net/ipv4/unicastsockopt_test.go
+1 -1
@@ -11,7 +11,7 @@ import (
11
12 "github.com/ipfs/go-ipfs/Godeps/_workspace/src/golang.org/x/net/internal/iana"
13 "github.com/ipfs/go-ipfs/Godeps/_workspace/src/golang.org/x/net/ipv4"
14 - "golang.org/x/net/internal/nettest"
14 + "gx/ipfs/QmZy2y8t9zQH2a1b8q2ZSLKp17ATuJoCNxxyMFG5qFExpt/go-net/internal/nettest"
15 )
16
17 func TestConnUnicastSocketOptions(t *testing.T) {
Godeps/_workspace/src/golang.org/x/net/ipv6/example_test.go
+1 -1
@@ -13,7 +13,7 @@ import (
13
14 "github.com/ipfs/go-ipfs/Godeps/_workspace/src/golang.org/x/net/internal/iana"
15 "github.com/ipfs/go-ipfs/Godeps/_workspace/src/golang.org/x/net/ipv6"
16 - "golang.org/x/net/icmp"
16 + "gx/ipfs/QmZy2y8t9zQH2a1b8q2ZSLKp17ATuJoCNxxyMFG5qFExpt/go-net/icmp"
17 )
18
19 func ExampleConn_markingTCP() {
Godeps/_workspace/src/golang.org/x/net/ipv6/icmp_test.go
+1 -1
@@ -11,7 +11,7 @@ import (
11 "testing"
12
13 "github.com/ipfs/go-ipfs/Godeps/_workspace/src/golang.org/x/net/ipv6"
14 - "golang.org/x/net/internal/nettest"
14 + "gx/ipfs/QmZy2y8t9zQH2a1b8q2ZSLKp17ATuJoCNxxyMFG5qFExpt/go-net/internal/nettest"
15 )
16
17 var icmpStringTests = []struct {
Godeps/_workspace/src/golang.org/x/net/ipv6/multicast_test.go
+2 -2
@@ -14,8 +14,8 @@ import (
14
15 "github.com/ipfs/go-ipfs/Godeps/_workspace/src/golang.org/x/net/internal/iana"
16 "github.com/ipfs/go-ipfs/Godeps/_workspace/src/golang.org/x/net/ipv6"
17 - "golang.org/x/net/icmp"
18 - "golang.org/x/net/internal/nettest"
17 + "gx/ipfs/QmZy2y8t9zQH2a1b8q2ZSLKp17ATuJoCNxxyMFG5qFExpt/go-net/icmp"
18 + "gx/ipfs/QmZy2y8t9zQH2a1b8q2ZSLKp17ATuJoCNxxyMFG5qFExpt/go-net/internal/nettest"
19 )
20
21 var packetConnReadWriteMulticastUDPTests = []struct {
Godeps/_workspace/src/golang.org/x/net/ipv6/multicastlistener_test.go
+1 -1
@@ -11,7 +11,7 @@ import (
11 "testing"
12
13 "github.com/ipfs/go-ipfs/Godeps/_workspace/src/golang.org/x/net/ipv6"
14 - "golang.org/x/net/internal/nettest"
14 + "gx/ipfs/QmZy2y8t9zQH2a1b8q2ZSLKp17ATuJoCNxxyMFG5qFExpt/go-net/internal/nettest"
15 )
16
17 var udpMultipleGroupListenerTests = []net.Addr{
Godeps/_workspace/src/golang.org/x/net/ipv6/multicastsockopt_test.go
+1 -1
@@ -10,7 +10,7 @@ import (
10 "testing"
11
12 "github.com/ipfs/go-ipfs/Godeps/_workspace/src/golang.org/x/net/ipv6"
13 - "golang.org/x/net/internal/nettest"
13 + "gx/ipfs/QmZy2y8t9zQH2a1b8q2ZSLKp17ATuJoCNxxyMFG5qFExpt/go-net/internal/nettest"
14 )
15
16 var packetConnMulticastSocketOptionTests = []struct {
Godeps/_workspace/src/golang.org/x/net/ipv6/readwrite_test.go
+1 -1
@@ -13,7 +13,7 @@ import (
13
14 "github.com/ipfs/go-ipfs/Godeps/_workspace/src/golang.org/x/net/internal/iana"
15 "github.com/ipfs/go-ipfs/Godeps/_workspace/src/golang.org/x/net/ipv6"
16 - "golang.org/x/net/internal/nettest"
16 + "gx/ipfs/QmZy2y8t9zQH2a1b8q2ZSLKp17ATuJoCNxxyMFG5qFExpt/go-net/internal/nettest"
17 )
18
19 func benchmarkUDPListener() (net.PacketConn, net.Addr, error) {
Godeps/_workspace/src/golang.org/x/net/ipv6/sockopt_test.go
+1 -1
@@ -12,7 +12,7 @@ import (
12
13 "github.com/ipfs/go-ipfs/Godeps/_workspace/src/golang.org/x/net/internal/iana"
14 "github.com/ipfs/go-ipfs/Godeps/_workspace/src/golang.org/x/net/ipv6"
15 - "golang.org/x/net/internal/nettest"
15 + "gx/ipfs/QmZy2y8t9zQH2a1b8q2ZSLKp17ATuJoCNxxyMFG5qFExpt/go-net/internal/nettest"
16 )
17
18 var supportsIPv6 bool = nettest.SupportsIPv6()
Godeps/_workspace/src/golang.org/x/net/ipv6/unicast_test.go
+2 -2
@@ -14,8 +14,8 @@ import (
14
15 "github.com/ipfs/go-ipfs/Godeps/_workspace/src/golang.org/x/net/internal/iana"
16 "github.com/ipfs/go-ipfs/Godeps/_workspace/src/golang.org/x/net/ipv6"
17 - "golang.org/x/net/icmp"
18 - "golang.org/x/net/internal/nettest"
17 + "gx/ipfs/QmZy2y8t9zQH2a1b8q2ZSLKp17ATuJoCNxxyMFG5qFExpt/go-net/icmp"
18 + "gx/ipfs/QmZy2y8t9zQH2a1b8q2ZSLKp17ATuJoCNxxyMFG5qFExpt/go-net/internal/nettest"
19 )
20
21 func TestPacketConnReadWriteUnicastUDP(t *testing.T) {
Godeps/_workspace/src/golang.org/x/net/ipv6/unicastsockopt_test.go
+1 -1
@@ -11,7 +11,7 @@ import (
11
12 "github.com/ipfs/go-ipfs/Godeps/_workspace/src/golang.org/x/net/internal/iana"
13 "github.com/ipfs/go-ipfs/Godeps/_workspace/src/golang.org/x/net/ipv6"
14 - "golang.org/x/net/internal/nettest"
14 + "gx/ipfs/QmZy2y8t9zQH2a1b8q2ZSLKp17ATuJoCNxxyMFG5qFExpt/go-net/internal/nettest"
15 )
16
17 func TestConnUnicastSocketOptions(t *testing.T) {
assets/assets_test.go
+2
@@ -9,10 +9,12 @@ import (
9
10 // TestEmbeddedDocs makes sure we don't forget to regenerate after documentation change
11 func TestEmbeddedDocs(t *testing.T) {
12 + t.Skip("skipping for now, paths are hard")
13 testNFiles(initDocPaths, 6, t, "documents")
14 }
15
16 func TestDirIndex(t *testing.T) {
17 + t.Skip("skipping for now, paths are hard")
18 testNFiles(initDirIndex, 2, t, "assets")
19 }
20
blocks/blockstore/blockstore.go
+2 -2
@@ -11,10 +11,10 @@ import (
11 dsns "github.com/ipfs/go-ipfs/Godeps/_workspace/src/github.com/ipfs/go-datastore/namespace"
12 dsq "github.com/ipfs/go-ipfs/Godeps/_workspace/src/github.com/ipfs/go-datastore/query"
13 mh "github.com/ipfs/go-ipfs/Godeps/_workspace/src/github.com/jbenet/go-multihash"
14 - context "github.com/ipfs/go-ipfs/Godeps/_workspace/src/golang.org/x/net/context"
14 + context "gx/ipfs/QmZy2y8t9zQH2a1b8q2ZSLKp17ATuJoCNxxyMFG5qFExpt/go-net/context"
15 blocks "github.com/ipfs/go-ipfs/blocks"
16 key "github.com/ipfs/go-ipfs/blocks/key"
17 - logging "github.com/ipfs/go-ipfs/vendor/QmQg1J6vikuXF9oDvm4wpdeAUvvkVEKW1EYDw9HhTMnP2b/go-log"
17 + logging "gx/ipfs/QmaPaGNE2GqnfJjRRpQuQuFHuJn4FZvsrGxdik4kgxCkBi/go-log"
18 )
19
20 var log = logging.Logger("blockstore")
blocks/blockstore/blockstore_test.go
+1 -1
@@ -8,7 +8,7 @@ import (
8 ds "github.com/ipfs/go-ipfs/Godeps/_workspace/src/github.com/ipfs/go-datastore"
9 dsq "github.com/ipfs/go-ipfs/Godeps/_workspace/src/github.com/ipfs/go-datastore/query"
10 ds_sync "github.com/ipfs/go-ipfs/Godeps/_workspace/src/github.com/ipfs/go-datastore/sync"
11 - context "github.com/ipfs/go-ipfs/Godeps/_workspace/src/golang.org/x/net/context"
11 + context "gx/ipfs/QmZy2y8t9zQH2a1b8q2ZSLKp17ATuJoCNxxyMFG5qFExpt/go-net/context"
12
13 blocks "github.com/ipfs/go-ipfs/blocks"
14 key "github.com/ipfs/go-ipfs/blocks/key"
blocks/blockstore/write_cache.go
+1 -1
@@ -2,7 +2,7 @@ package blockstore
2
3 import (
4 "github.com/ipfs/go-ipfs/Godeps/_workspace/src/github.com/hashicorp/golang-lru"
5 - context "github.com/ipfs/go-ipfs/Godeps/_workspace/src/golang.org/x/net/context"
5 + context "gx/ipfs/QmZy2y8t9zQH2a1b8q2ZSLKp17ATuJoCNxxyMFG5qFExpt/go-net/context"
6 "github.com/ipfs/go-ipfs/blocks"
7 key "github.com/ipfs/go-ipfs/blocks/key"
8 )
blocks/set/set.go
+1 -1
@@ -4,7 +4,7 @@ package set
4 import (
5 "github.com/ipfs/go-ipfs/blocks/bloom"
6 key "github.com/ipfs/go-ipfs/blocks/key"
7 - logging "github.com/ipfs/go-ipfs/vendor/QmQg1J6vikuXF9oDvm4wpdeAUvvkVEKW1EYDw9HhTMnP2b/go-log"
7 + logging "gx/ipfs/QmaPaGNE2GqnfJjRRpQuQuFHuJn4FZvsrGxdik4kgxCkBi/go-log"
8 )
9
10 var log = logging.Logger("blockset")
blockservice/blockservice.go
+2 -2
@@ -6,12 +6,12 @@ package blockservice
6 import (
7 "errors"
8
9 - context "github.com/ipfs/go-ipfs/Godeps/_workspace/src/golang.org/x/net/context"
9 + context "gx/ipfs/QmZy2y8t9zQH2a1b8q2ZSLKp17ATuJoCNxxyMFG5qFExpt/go-net/context"
10 blocks "github.com/ipfs/go-ipfs/blocks"
11 "github.com/ipfs/go-ipfs/blocks/blockstore"
12 key "github.com/ipfs/go-ipfs/blocks/key"
13 exchange "github.com/ipfs/go-ipfs/exchange"
14 - logging "github.com/ipfs/go-ipfs/vendor/QmQg1J6vikuXF9oDvm4wpdeAUvvkVEKW1EYDw9HhTMnP2b/go-log"
14 + logging "gx/ipfs/QmaPaGNE2GqnfJjRRpQuQuFHuJn4FZvsrGxdik4kgxCkBi/go-log"
15 )
16
17 var log = logging.Logger("blockservice")
blockservice/test/blocks_test.go
+1 -1
@@ -7,7 +7,7 @@ import (
7
8 ds "github.com/ipfs/go-ipfs/Godeps/_workspace/src/github.com/ipfs/go-datastore"
9 dssync "github.com/ipfs/go-ipfs/Godeps/_workspace/src/github.com/ipfs/go-datastore/sync"
10 - "github.com/ipfs/go-ipfs/Godeps/_workspace/src/golang.org/x/net/context"
10 + "gx/ipfs/QmZy2y8t9zQH2a1b8q2ZSLKp17ATuJoCNxxyMFG5qFExpt/go-net/context"
11 blocks "github.com/ipfs/go-ipfs/blocks"
12 blockstore "github.com/ipfs/go-ipfs/blocks/blockstore"
13 blocksutil "github.com/ipfs/go-ipfs/blocks/blocksutil"
cmd/ipfs/daemon.go
+4 -4
@@ -12,8 +12,8 @@ import (
12 "sync"
13
14 _ "github.com/ipfs/go-ipfs/Godeps/_workspace/src/github.com/codahale/metrics/runtime"
15 - ma "github.com/ipfs/go-ipfs/Godeps/_workspace/src/github.com/jbenet/go-multiaddr"
16 - "github.com/ipfs/go-ipfs/Godeps/_workspace/src/github.com/jbenet/go-multiaddr-net"
15 + ma "gx/ipfs/QmR3JkmZBKYXgNMNsNZawm914455Qof3PEopwuVSeXG7aV/go-multiaddr"
16 + "gx/ipfs/QmYtzQmUwPFGxjCXctJ8e6GXS8sYfoXy2pdeMbS5SFWqRi/go-multiaddr-net"
17
18 cmds "github.com/ipfs/go-ipfs/commands"
19 "github.com/ipfs/go-ipfs/core"
@@ -21,10 +21,10 @@ import (
21 corehttp "github.com/ipfs/go-ipfs/core/corehttp"
22 corerepo "github.com/ipfs/go-ipfs/core/corerepo"
23 "github.com/ipfs/go-ipfs/core/corerouting"
24 - conn "github.com/ipfs/go-ipfs/p2p/net/conn"
25 - peer "github.com/ipfs/go-ipfs/p2p/peer"
24 fsrepo "github.com/ipfs/go-ipfs/repo/fsrepo"
25 util "github.com/ipfs/go-ipfs/util"
26 + conn "gx/ipfs/QmY3NAw959vbE1oJooP9HchcRdBsbxhgQsEZTRhKgvoSuC/go-libp2p/p2p/net/conn"
27 + peer "gx/ipfs/QmY3NAw959vbE1oJooP9HchcRdBsbxhgQsEZTRhKgvoSuC/go-libp2p/p2p/peer"
28 )
29
30 const (
cmd/ipfs/init.go
+1 -1
@@ -7,7 +7,7 @@ import (
7 "os"
8 "path"
9
10 - context "github.com/ipfs/go-ipfs/Godeps/_workspace/src/golang.org/x/net/context"
10 + context "gx/ipfs/QmZy2y8t9zQH2a1b8q2ZSLKp17ATuJoCNxxyMFG5qFExpt/go-net/context"
11 assets "github.com/ipfs/go-ipfs/assets"
12 cmds "github.com/ipfs/go-ipfs/commands"
13 core "github.com/ipfs/go-ipfs/core"
cmd/ipfs/main.go
+4 -4
@@ -17,10 +17,10 @@ import (
17 "syscall"
18 "time"
19
20 - ma "github.com/ipfs/go-ipfs/Godeps/_workspace/src/github.com/jbenet/go-multiaddr"
21 - manet "github.com/ipfs/go-ipfs/Godeps/_workspace/src/github.com/jbenet/go-multiaddr-net"
20 + ma "gx/ipfs/QmR3JkmZBKYXgNMNsNZawm914455Qof3PEopwuVSeXG7aV/go-multiaddr"
21 + manet "gx/ipfs/QmYtzQmUwPFGxjCXctJ8e6GXS8sYfoXy2pdeMbS5SFWqRi/go-multiaddr-net"
22
23 - context "github.com/ipfs/go-ipfs/Godeps/_workspace/src/golang.org/x/net/context"
23 + context "gx/ipfs/QmZy2y8t9zQH2a1b8q2ZSLKp17ATuJoCNxxyMFG5qFExpt/go-net/context"
24 cmds "github.com/ipfs/go-ipfs/commands"
25 cmdsCli "github.com/ipfs/go-ipfs/commands/cli"
26 cmdsHttp "github.com/ipfs/go-ipfs/commands/http"
@@ -30,7 +30,7 @@ import (
30 config "github.com/ipfs/go-ipfs/repo/config"
31 fsrepo "github.com/ipfs/go-ipfs/repo/fsrepo"
32 u "github.com/ipfs/go-ipfs/util"
33 - logging "github.com/ipfs/go-ipfs/vendor/QmQg1J6vikuXF9oDvm4wpdeAUvvkVEKW1EYDw9HhTMnP2b/go-log"
33 + logging "gx/ipfs/QmaPaGNE2GqnfJjRRpQuQuFHuJn4FZvsrGxdik4kgxCkBi/go-log"
34 )
35
36 // log is the command logger
cmd/ipfswatch/main.go
+1 -1
@@ -9,7 +9,7 @@ import (
9
10 process "github.com/ipfs/go-ipfs/Godeps/_workspace/src/github.com/jbenet/goprocess"
11 homedir "github.com/ipfs/go-ipfs/Godeps/_workspace/src/github.com/mitchellh/go-homedir"
12 - context "github.com/ipfs/go-ipfs/Godeps/_workspace/src/golang.org/x/net/context"
12 + context "gx/ipfs/QmZy2y8t9zQH2a1b8q2ZSLKp17ATuJoCNxxyMFG5qFExpt/go-net/context"
13 fsnotify "github.com/ipfs/go-ipfs/Godeps/_workspace/src/gopkg.in/fsnotify.v1"
14 commands "github.com/ipfs/go-ipfs/commands"
15 core "github.com/ipfs/go-ipfs/core"
cmd/seccat/seccat.go
+5 -5
@@ -18,11 +18,11 @@ import (
18 "os/signal"
19 "syscall"
20
21 - context "github.com/ipfs/go-ipfs/Godeps/_workspace/src/golang.org/x/net/context"
22 - ci "github.com/ipfs/go-ipfs/p2p/crypto"
23 - secio "github.com/ipfs/go-ipfs/p2p/crypto/secio"
24 - peer "github.com/ipfs/go-ipfs/p2p/peer"
25 - logging "github.com/ipfs/go-ipfs/vendor/QmQg1J6vikuXF9oDvm4wpdeAUvvkVEKW1EYDw9HhTMnP2b/go-log"
21 + context "gx/ipfs/QmZy2y8t9zQH2a1b8q2ZSLKp17ATuJoCNxxyMFG5qFExpt/go-net/context"
22 + logging "gx/ipfs/QmaPaGNE2GqnfJjRRpQuQuFHuJn4FZvsrGxdik4kgxCkBi/go-log"
23 + ci "gx/ipfs/QmY3NAw959vbE1oJooP9HchcRdBsbxhgQsEZTRhKgvoSuC/go-libp2p/p2p/crypto"
24 + secio "gx/ipfs/QmY3NAw959vbE1oJooP9HchcRdBsbxhgQsEZTRhKgvoSuC/go-libp2p/p2p/crypto/secio"
25 + peer "gx/ipfs/QmY3NAw959vbE1oJooP9HchcRdBsbxhgQsEZTRhKgvoSuC/go-libp2p/p2p/peer"
26 )
27
28 var verbose = false
cmd/seccat/util.go
+1 -1
@@ -5,7 +5,7 @@ import (
5 "io"
6 "os"
7
8 - logging "github.com/ipfs/go-ipfs/vendor/QmQg1J6vikuXF9oDvm4wpdeAUvvkVEKW1EYDw9HhTMnP2b/go-log"
8 + logging "gx/ipfs/QmaPaGNE2GqnfJjRRpQuQuFHuJn4FZvsrGxdik4kgxCkBi/go-log"
9 )
10
11 var log = logging.Logger("seccat")
commands/command.go
+1 -1
@@ -15,7 +15,7 @@ import (
15 "reflect"
16
17 "github.com/ipfs/go-ipfs/path"
18 - logging "github.com/ipfs/go-ipfs/vendor/QmQg1J6vikuXF9oDvm4wpdeAUvvkVEKW1EYDw9HhTMnP2b/go-log"
18 + logging "gx/ipfs/QmaPaGNE2GqnfJjRRpQuQuFHuJn4FZvsrGxdik4kgxCkBi/go-log"
19 )
20
21 var log = logging.Logger("command")
commands/http/client.go
+1 -1
@@ -15,7 +15,7 @@ import (
15 cmds "github.com/ipfs/go-ipfs/commands"
16 config "github.com/ipfs/go-ipfs/repo/config"
17
18 - context "github.com/ipfs/go-ipfs/Godeps/_workspace/src/golang.org/x/net/context"
18 + context "gx/ipfs/QmZy2y8t9zQH2a1b8q2ZSLKp17ATuJoCNxxyMFG5qFExpt/go-net/context"
19 )
20
21 const (
commands/http/handler.go
+2 -2
@@ -12,11 +12,11 @@ import (
12 "sync"
13
14 cors "github.com/ipfs/go-ipfs/Godeps/_workspace/src/github.com/rs/cors"
15 - context "github.com/ipfs/go-ipfs/Godeps/_workspace/src/golang.org/x/net/context"
15 + context "gx/ipfs/QmZy2y8t9zQH2a1b8q2ZSLKp17ATuJoCNxxyMFG5qFExpt/go-net/context"
16 "github.com/ipfs/go-ipfs/repo/config"
17
18 cmds "github.com/ipfs/go-ipfs/commands"
19 - logging "github.com/ipfs/go-ipfs/vendor/QmQg1J6vikuXF9oDvm4wpdeAUvvkVEKW1EYDw9HhTMnP2b/go-log"
19 + logging "gx/ipfs/QmaPaGNE2GqnfJjRRpQuQuFHuJn4FZvsrGxdik4kgxCkBi/go-log"
20 )
21
22 var log = logging.Logger("commands/http")
commands/request.go
+1 -1
@@ -9,7 +9,7 @@ import (
9 "strconv"
10 "time"
11
12 - context "github.com/ipfs/go-ipfs/Godeps/_workspace/src/golang.org/x/net/context"
12 + context "gx/ipfs/QmZy2y8t9zQH2a1b8q2ZSLKp17ATuJoCNxxyMFG5qFExpt/go-net/context"
13 "github.com/ipfs/go-ipfs/commands/files"
14 "github.com/ipfs/go-ipfs/core"
15 "github.com/ipfs/go-ipfs/repo/config"
core/bootstrap.go
+4 -4
@@ -8,17 +8,17 @@ import (
8 "sync"
9 "time"
10
11 - host "github.com/ipfs/go-ipfs/p2p/host"
12 - inet "github.com/ipfs/go-ipfs/p2p/net"
13 - peer "github.com/ipfs/go-ipfs/p2p/peer"
11 config "github.com/ipfs/go-ipfs/repo/config"
12 math2 "github.com/ipfs/go-ipfs/thirdparty/math2"
13 lgbl "github.com/ipfs/go-ipfs/util/eventlog/loggables"
14 + host "gx/ipfs/QmY3NAw959vbE1oJooP9HchcRdBsbxhgQsEZTRhKgvoSuC/go-libp2p/p2p/host"
15 + inet "gx/ipfs/QmY3NAw959vbE1oJooP9HchcRdBsbxhgQsEZTRhKgvoSuC/go-libp2p/p2p/net"
16 + peer "gx/ipfs/QmY3NAw959vbE1oJooP9HchcRdBsbxhgQsEZTRhKgvoSuC/go-libp2p/p2p/peer"
17
18 goprocess "github.com/ipfs/go-ipfs/Godeps/_workspace/src/github.com/jbenet/goprocess"
19 procctx "github.com/ipfs/go-ipfs/Godeps/_workspace/src/github.com/jbenet/goprocess/context"
20 periodicproc "github.com/ipfs/go-ipfs/Godeps/_workspace/src/github.com/jbenet/goprocess/periodic"
21 - context "github.com/ipfs/go-ipfs/Godeps/_workspace/src/golang.org/x/net/context"
21 + context "gx/ipfs/QmZy2y8t9zQH2a1b8q2ZSLKp17ATuJoCNxxyMFG5qFExpt/go-net/context"
22 )
23
24 // ErrNotEnoughBootstrapPeers signals that we do not have enough bootstrap
core/bootstrap_test.go
+1 -1
@@ -4,9 +4,9 @@ import (
4 "fmt"
5 "testing"
6
7 - peer "github.com/ipfs/go-ipfs/p2p/peer"
7 config "github.com/ipfs/go-ipfs/repo/config"
8 testutil "github.com/ipfs/go-ipfs/util/testutil"
9 + peer "gx/ipfs/QmY3NAw959vbE1oJooP9HchcRdBsbxhgQsEZTRhKgvoSuC/go-libp2p/p2p/peer"
10 )
11
12 func TestSubsetWhenMaxIsGreaterThanLengthOfSlice(t *testing.T) {
core/builder.go
+3 -3
@@ -8,18 +8,18 @@ import (
8 ds "github.com/ipfs/go-ipfs/Godeps/_workspace/src/github.com/ipfs/go-datastore"
9 dsync "github.com/ipfs/go-ipfs/Godeps/_workspace/src/github.com/ipfs/go-datastore/sync"
10 goprocessctx "github.com/ipfs/go-ipfs/Godeps/_workspace/src/github.com/jbenet/goprocess/context"
11 - context "github.com/ipfs/go-ipfs/Godeps/_workspace/src/golang.org/x/net/context"
11 + context "gx/ipfs/QmZy2y8t9zQH2a1b8q2ZSLKp17ATuJoCNxxyMFG5qFExpt/go-net/context"
12 bstore "github.com/ipfs/go-ipfs/blocks/blockstore"
13 key "github.com/ipfs/go-ipfs/blocks/key"
14 bserv "github.com/ipfs/go-ipfs/blockservice"
15 offline "github.com/ipfs/go-ipfs/exchange/offline"
16 dag "github.com/ipfs/go-ipfs/merkledag"
17 - ci "github.com/ipfs/go-ipfs/p2p/crypto"
18 - peer "github.com/ipfs/go-ipfs/p2p/peer"
17 path "github.com/ipfs/go-ipfs/path"
18 pin "github.com/ipfs/go-ipfs/pin"
19 repo "github.com/ipfs/go-ipfs/repo"
20 cfg "github.com/ipfs/go-ipfs/repo/config"
21 + ci "gx/ipfs/QmY3NAw959vbE1oJooP9HchcRdBsbxhgQsEZTRhKgvoSuC/go-libp2p/p2p/crypto"
22 + peer "gx/ipfs/QmY3NAw959vbE1oJooP9HchcRdBsbxhgQsEZTRhKgvoSuC/go-libp2p/p2p/peer"
23 )
24
25 type BuildCfg struct {
core/commands/bitswap.go
+1 -1
@@ -10,8 +10,8 @@ import (
10 key "github.com/ipfs/go-ipfs/blocks/key"
11 cmds "github.com/ipfs/go-ipfs/commands"
12 bitswap "github.com/ipfs/go-ipfs/exchange/bitswap"
13 - peer "github.com/ipfs/go-ipfs/p2p/peer"
13 u "github.com/ipfs/go-ipfs/util"
14 + peer "gx/ipfs/QmY3NAw959vbE1oJooP9HchcRdBsbxhgQsEZTRhKgvoSuC/go-libp2p/p2p/peer"
15 )
16
17 var BitswapCmd = &cmds.Command{
core/commands/cat.go
+1 -1
@@ -8,7 +8,7 @@ import (
8 "github.com/ipfs/go-ipfs/core/corerepo"
9 coreunix "github.com/ipfs/go-ipfs/core/coreunix"
10
11 - context "github.com/ipfs/go-ipfs/Godeps/_workspace/src/golang.org/x/net/context"
11 + context "gx/ipfs/QmZy2y8t9zQH2a1b8q2ZSLKp17ATuJoCNxxyMFG5qFExpt/go-net/context"
12 )
13
14 const progressBarMinSize = 1024 * 1024 * 8 // show progress bar for outputs > 8MiB
core/commands/dht.go
+1 -1
@@ -10,10 +10,10 @@ import (
10 key "github.com/ipfs/go-ipfs/blocks/key"
11 cmds "github.com/ipfs/go-ipfs/commands"
12 notif "github.com/ipfs/go-ipfs/notifications"
13 - peer "github.com/ipfs/go-ipfs/p2p/peer"
13 path "github.com/ipfs/go-ipfs/path"
14 ipdht "github.com/ipfs/go-ipfs/routing/dht"
15 u "github.com/ipfs/go-ipfs/util"
16 + peer "gx/ipfs/QmY3NAw959vbE1oJooP9HchcRdBsbxhgQsEZTRhKgvoSuC/go-libp2p/p2p/peer"
17 )
18
19 var ErrNotDHT = errors.New("routing service is not a DHT")
core/commands/files/files.go
+2 -2
@@ -16,8 +16,8 @@ import (
16 path "github.com/ipfs/go-ipfs/path"
17 ft "github.com/ipfs/go-ipfs/unixfs"
18
19 - context "github.com/ipfs/go-ipfs/Godeps/_workspace/src/golang.org/x/net/context"
20 - logging "github.com/ipfs/go-ipfs/vendor/QmQg1J6vikuXF9oDvm4wpdeAUvvkVEKW1EYDw9HhTMnP2b/go-log"
19 + context "gx/ipfs/QmZy2y8t9zQH2a1b8q2ZSLKp17ATuJoCNxxyMFG5qFExpt/go-net/context"
20 + logging "gx/ipfs/QmaPaGNE2GqnfJjRRpQuQuFHuJn4FZvsrGxdik4kgxCkBi/go-log"
21 )
22
23 var log = logging.Logger("cmds/files")
core/commands/id.go
+4 -4
@@ -12,11 +12,11 @@ import (
12
13 cmds "github.com/ipfs/go-ipfs/commands"
14 core "github.com/ipfs/go-ipfs/core"
15 - ic "github.com/ipfs/go-ipfs/p2p/crypto"
16 - "github.com/ipfs/go-ipfs/p2p/peer"
17 - identify "github.com/ipfs/go-ipfs/p2p/protocol/identify"
15 kb "github.com/ipfs/go-ipfs/routing/kbucket"
16 u "github.com/ipfs/go-ipfs/util"
17 + ic "gx/ipfs/QmY3NAw959vbE1oJooP9HchcRdBsbxhgQsEZTRhKgvoSuC/go-libp2p/p2p/crypto"
18 + "gx/ipfs/QmY3NAw959vbE1oJooP9HchcRdBsbxhgQsEZTRhKgvoSuC/go-libp2p/p2p/peer"
19 + identify "gx/ipfs/QmY3NAw959vbE1oJooP9HchcRdBsbxhgQsEZTRhKgvoSuC/go-libp2p/p2p/protocol/identify"
20 )
21
22 const offlineIdErrorMessage = `ID command fails when run without daemon, we are working to fix this.
@@ -199,7 +199,7 @@ func printSelf(node *core.IpfsNode) (interface{}, error) {
199 info.Addresses = append(info.Addresses, s)
200 }
201 }
202 - info.ProtocolVersion = identify.IpfsVersion
202 + info.ProtocolVersion = identify.LibP2PVersion
203 info.AgentVersion = identify.ClientVersion
204 return info, nil
205 }
core/commands/log.go
+1 -1
@@ -5,7 +5,7 @@ import (
5 "io"
6
7 cmds "github.com/ipfs/go-ipfs/commands"
8 - logging "github.com/ipfs/go-ipfs/vendor/QmQg1J6vikuXF9oDvm4wpdeAUvvkVEKW1EYDw9HhTMnP2b/go-log"
8 + logging "gx/ipfs/QmaPaGNE2GqnfJjRRpQuQuFHuJn4FZvsrGxdik4kgxCkBi/go-log"
9 )
10
11 // Golang os.Args overrides * and replaces the character argument with
core/commands/pin.go
+1 -1
@@ -7,7 +7,7 @@ import (
7
8 key "github.com/ipfs/go-ipfs/blocks/key"
9 cmds "github.com/ipfs/go-ipfs/commands"
10 - context "github.com/ipfs/go-ipfs/Godeps/_workspace/src/golang.org/x/net/context"
10 + context "gx/ipfs/QmZy2y8t9zQH2a1b8q2ZSLKp17ATuJoCNxxyMFG5qFExpt/go-net/context"
11 core "github.com/ipfs/go-ipfs/core"
12 corerepo "github.com/ipfs/go-ipfs/core/corerepo"
13 dag "github.com/ipfs/go-ipfs/merkledag"
core/commands/ping.go
+3 -3
@@ -10,11 +10,11 @@ import (
10
11 cmds "github.com/ipfs/go-ipfs/commands"
12 core "github.com/ipfs/go-ipfs/core"
13 - peer "github.com/ipfs/go-ipfs/p2p/peer"
13 u "github.com/ipfs/go-ipfs/util"
14 + peer "gx/ipfs/QmY3NAw959vbE1oJooP9HchcRdBsbxhgQsEZTRhKgvoSuC/go-libp2p/p2p/peer"
15
16 - ma "github.com/ipfs/go-ipfs/Godeps/_workspace/src/github.com/jbenet/go-multiaddr"
17 - context "github.com/ipfs/go-ipfs/Godeps/_workspace/src/golang.org/x/net/context"
16 + context "gx/ipfs/QmZy2y8t9zQH2a1b8q2ZSLKp17ATuJoCNxxyMFG5qFExpt/go-net/context"
17 + ma "gx/ipfs/QmR3JkmZBKYXgNMNsNZawm914455Qof3PEopwuVSeXG7aV/go-multiaddr"
18 )
19
20 const kPingTimeout = 10 * time.Second
core/commands/publish.go
+2 -2
@@ -7,13 +7,13 @@ import (
7 "strings"
8 "time"
9
10 - context "github.com/ipfs/go-ipfs/Godeps/_workspace/src/golang.org/x/net/context"
10 + context "gx/ipfs/QmZy2y8t9zQH2a1b8q2ZSLKp17ATuJoCNxxyMFG5qFExpt/go-net/context"
11
12 key "github.com/ipfs/go-ipfs/blocks/key"
13 cmds "github.com/ipfs/go-ipfs/commands"
14 core "github.com/ipfs/go-ipfs/core"
15 - crypto "github.com/ipfs/go-ipfs/p2p/crypto"
15 path "github.com/ipfs/go-ipfs/path"
16 + crypto "gx/ipfs/QmY3NAw959vbE1oJooP9HchcRdBsbxhgQsEZTRhKgvoSuC/go-libp2p/p2p/crypto"
17 )
18
19 var errNotOnline = errors.New("This command must be run in online mode. Try running 'ipfs daemon' first.")
core/commands/refs.go
+1 -1
@@ -7,7 +7,7 @@ import (
7 "io"
8 "strings"
9
10 - context "github.com/ipfs/go-ipfs/Godeps/_workspace/src/golang.org/x/net/context"
10 + context "gx/ipfs/QmZy2y8t9zQH2a1b8q2ZSLKp17ATuJoCNxxyMFG5qFExpt/go-net/context"
11 key "github.com/ipfs/go-ipfs/blocks/key"
12 cmds "github.com/ipfs/go-ipfs/commands"
13 "github.com/ipfs/go-ipfs/core"
core/commands/root.go
+1 -1
@@ -8,7 +8,7 @@ import (
8 files "github.com/ipfs/go-ipfs/core/commands/files"
9 ocmd "github.com/ipfs/go-ipfs/core/commands/object"
10 unixfs "github.com/ipfs/go-ipfs/core/commands/unixfs"
11 - logging "github.com/ipfs/go-ipfs/vendor/QmQg1J6vikuXF9oDvm4wpdeAUvvkVEKW1EYDw9HhTMnP2b/go-log"
11 + logging "gx/ipfs/QmaPaGNE2GqnfJjRRpQuQuFHuJn4FZvsrGxdik4kgxCkBi/go-log"
12 )
13
14 var log = logging.Logger("core/commands")
core/commands/stat.go
+3 -3
@@ -10,10 +10,10 @@ import (
10 humanize "github.com/ipfs/go-ipfs/Godeps/_workspace/src/github.com/dustin/go-humanize"
11
12 cmds "github.com/ipfs/go-ipfs/commands"
13 - metrics "github.com/ipfs/go-ipfs/metrics"
14 - peer "github.com/ipfs/go-ipfs/p2p/peer"
15 - protocol "github.com/ipfs/go-ipfs/p2p/protocol"
13 u "github.com/ipfs/go-ipfs/util"
14 + metrics "gx/ipfs/QmY3NAw959vbE1oJooP9HchcRdBsbxhgQsEZTRhKgvoSuC/go-libp2p/p2p/metrics"
15 + peer "gx/ipfs/QmY3NAw959vbE1oJooP9HchcRdBsbxhgQsEZTRhKgvoSuC/go-libp2p/p2p/peer"
16 + protocol "gx/ipfs/QmY3NAw959vbE1oJooP9HchcRdBsbxhgQsEZTRhKgvoSuC/go-libp2p/p2p/protocol"
17 )
18
19 var StatsCmd = &cmds.Command{
core/commands/swarm.go
+3 -3
@@ -9,12 +9,12 @@ import (
9 "sort"
10
11 cmds "github.com/ipfs/go-ipfs/commands"
12 - swarm "github.com/ipfs/go-ipfs/p2p/net/swarm"
13 - peer "github.com/ipfs/go-ipfs/p2p/peer"
12 iaddr "github.com/ipfs/go-ipfs/util/ipfsaddr"
13 + swarm "gx/ipfs/QmY3NAw959vbE1oJooP9HchcRdBsbxhgQsEZTRhKgvoSuC/go-libp2p/p2p/net/swarm"
14 + peer "gx/ipfs/QmY3NAw959vbE1oJooP9HchcRdBsbxhgQsEZTRhKgvoSuC/go-libp2p/p2p/peer"
15
16 - ma "github.com/ipfs/go-ipfs/Godeps/_workspace/src/github.com/jbenet/go-multiaddr"
16 mafilter "github.com/ipfs/go-ipfs/Godeps/_workspace/src/github.com/whyrusleeping/multiaddr-filter"
17 + ma "gx/ipfs/QmR3JkmZBKYXgNMNsNZawm914455Qof3PEopwuVSeXG7aV/go-multiaddr"
18 )
19
20 type stringList struct {
core/commands/sysdiag.go
+1 -1
@@ -8,7 +8,7 @@ import (
8 cmds "github.com/ipfs/go-ipfs/commands"
9 config "github.com/ipfs/go-ipfs/repo/config"
10
11 - manet "github.com/ipfs/go-ipfs/Godeps/_workspace/src/github.com/jbenet/go-multiaddr-net"
11 + manet "gx/ipfs/QmYtzQmUwPFGxjCXctJ8e6GXS8sYfoXy2pdeMbS5SFWqRi/go-multiaddr-net"
12 sysi "github.com/ipfs/go-ipfs/Godeps/_workspace/src/github.com/whyrusleeping/go-sysinfo"
13 )
14
core/core.go
+13 -13
@@ -18,22 +18,22 @@ import (
18
19 ds "github.com/ipfs/go-ipfs/Godeps/_workspace/src/github.com/ipfs/go-datastore"
20 b58 "github.com/ipfs/go-ipfs/Godeps/_workspace/src/github.com/jbenet/go-base58"
21 - ma "github.com/ipfs/go-ipfs/Godeps/_workspace/src/github.com/jbenet/go-multiaddr"
21 goprocess "github.com/ipfs/go-ipfs/Godeps/_workspace/src/github.com/jbenet/goprocess"
22 mamask "github.com/ipfs/go-ipfs/Godeps/_workspace/src/github.com/whyrusleeping/multiaddr-filter"
24 - context "github.com/ipfs/go-ipfs/Godeps/_workspace/src/golang.org/x/net/context"
23 + context "gx/ipfs/QmZy2y8t9zQH2a1b8q2ZSLKp17ATuJoCNxxyMFG5qFExpt/go-net/context"
24 diag "github.com/ipfs/go-ipfs/diagnostics"
26 - metrics "github.com/ipfs/go-ipfs/metrics"
27 - ic "github.com/ipfs/go-ipfs/p2p/crypto"
28 - discovery "github.com/ipfs/go-ipfs/p2p/discovery"
29 - p2phost "github.com/ipfs/go-ipfs/p2p/host"
30 - p2pbhost "github.com/ipfs/go-ipfs/p2p/host/basic"
31 - rhost "github.com/ipfs/go-ipfs/p2p/host/routed"
32 - swarm "github.com/ipfs/go-ipfs/p2p/net/swarm"
33 - addrutil "github.com/ipfs/go-ipfs/p2p/net/swarm/addr"
34 - peer "github.com/ipfs/go-ipfs/p2p/peer"
35 - ping "github.com/ipfs/go-ipfs/p2p/protocol/ping"
36 - logging "github.com/ipfs/go-ipfs/vendor/QmQg1J6vikuXF9oDvm4wpdeAUvvkVEKW1EYDw9HhTMnP2b/go-log"
25 + ma "gx/ipfs/QmR3JkmZBKYXgNMNsNZawm914455Qof3PEopwuVSeXG7aV/go-multiaddr"
26 + ic "gx/ipfs/QmY3NAw959vbE1oJooP9HchcRdBsbxhgQsEZTRhKgvoSuC/go-libp2p/p2p/crypto"
27 + discovery "gx/ipfs/QmY3NAw959vbE1oJooP9HchcRdBsbxhgQsEZTRhKgvoSuC/go-libp2p/p2p/discovery"
28 + p2phost "gx/ipfs/QmY3NAw959vbE1oJooP9HchcRdBsbxhgQsEZTRhKgvoSuC/go-libp2p/p2p/host"
29 + p2pbhost "gx/ipfs/QmY3NAw959vbE1oJooP9HchcRdBsbxhgQsEZTRhKgvoSuC/go-libp2p/p2p/host/basic"
30 + rhost "gx/ipfs/QmY3NAw959vbE1oJooP9HchcRdBsbxhgQsEZTRhKgvoSuC/go-libp2p/p2p/host/routed"
31 + metrics "gx/ipfs/QmY3NAw959vbE1oJooP9HchcRdBsbxhgQsEZTRhKgvoSuC/go-libp2p/p2p/metrics"
32 + swarm "gx/ipfs/QmY3NAw959vbE1oJooP9HchcRdBsbxhgQsEZTRhKgvoSuC/go-libp2p/p2p/net/swarm"
33 + addrutil "gx/ipfs/QmY3NAw959vbE1oJooP9HchcRdBsbxhgQsEZTRhKgvoSuC/go-libp2p/p2p/net/swarm/addr"
34 + peer "gx/ipfs/QmY3NAw959vbE1oJooP9HchcRdBsbxhgQsEZTRhKgvoSuC/go-libp2p/p2p/peer"
35 + ping "gx/ipfs/QmY3NAw959vbE1oJooP9HchcRdBsbxhgQsEZTRhKgvoSuC/go-libp2p/p2p/protocol/ping"
36 + logging "gx/ipfs/QmaPaGNE2GqnfJjRRpQuQuFHuJn4FZvsrGxdik4kgxCkBi/go-log"
37
38 routing "github.com/ipfs/go-ipfs/routing"
39 dht "github.com/ipfs/go-ipfs/routing/dht"
core/core_test.go
+1 -1
@@ -3,7 +3,7 @@ package core
3 import (
4 "testing"
5
6 - context "github.com/ipfs/go-ipfs/Godeps/_workspace/src/golang.org/x/net/context"
6 + context "gx/ipfs/QmZy2y8t9zQH2a1b8q2ZSLKp17ATuJoCNxxyMFG5qFExpt/go-net/context"
7 "github.com/ipfs/go-ipfs/repo"
8 config "github.com/ipfs/go-ipfs/repo/config"
9 "github.com/ipfs/go-ipfs/util/testutil"
core/corehttp/corehttp.go
+3 -3
@@ -10,11 +10,11 @@ import (
10 "net/http"
11 "time"
12
13 - ma "github.com/ipfs/go-ipfs/Godeps/_workspace/src/github.com/jbenet/go-multiaddr"
14 - manet "github.com/ipfs/go-ipfs/Godeps/_workspace/src/github.com/jbenet/go-multiaddr-net"
13 + ma "gx/ipfs/QmR3JkmZBKYXgNMNsNZawm914455Qof3PEopwuVSeXG7aV/go-multiaddr"
14 + manet "gx/ipfs/QmYtzQmUwPFGxjCXctJ8e6GXS8sYfoXy2pdeMbS5SFWqRi/go-multiaddr-net"
15 "github.com/ipfs/go-ipfs/Godeps/_workspace/src/github.com/jbenet/goprocess"
16 core "github.com/ipfs/go-ipfs/core"
17 - logging "github.com/ipfs/go-ipfs/vendor/QmQg1J6vikuXF9oDvm4wpdeAUvvkVEKW1EYDw9HhTMnP2b/go-log"
17 + logging "gx/ipfs/QmaPaGNE2GqnfJjRRpQuQuFHuJn4FZvsrGxdik4kgxCkBi/go-log"
18 )
19
20 var log = logging.Logger("core/server")
core/corehttp/gateway.go
+2 -2
@@ -7,8 +7,8 @@ import (
7 "sync"
8
9 core "github.com/ipfs/go-ipfs/core"
10 - id "github.com/ipfs/go-ipfs/p2p/protocol/identify"
10 config "github.com/ipfs/go-ipfs/repo/config"
11 + id "gx/ipfs/QmY3NAw959vbE1oJooP9HchcRdBsbxhgQsEZTRhKgvoSuC/go-libp2p/p2p/protocol/identify"
12 )
13
14 // Gateway should be instantiated using NewGateway
@@ -61,7 +61,7 @@ func VersionOption() ServeOption {
61 mux.HandleFunc("/version", func(w http.ResponseWriter, r *http.Request) {
62 fmt.Fprintf(w, "Commit: %s\n", config.CurrentCommit)
63 fmt.Fprintf(w, "Client Version: %s\n", id.ClientVersion)
64 - fmt.Fprintf(w, "Protocol Version: %s\n", id.IpfsVersion)
64 + fmt.Fprintf(w, "Protocol Version: %s\n", id.LibP2PVersion)
65 })
66 return mux, nil
67 }
core/corehttp/gateway_handler.go
+1 -1
@@ -11,7 +11,7 @@ import (
11 "time"
12
13 humanize "github.com/ipfs/go-ipfs/Godeps/_workspace/src/github.com/dustin/go-humanize"
14 - "github.com/ipfs/go-ipfs/Godeps/_workspace/src/golang.org/x/net/context"
14 + "gx/ipfs/QmZy2y8t9zQH2a1b8q2ZSLKp17ATuJoCNxxyMFG5qFExpt/go-net/context"
15
16 key "github.com/ipfs/go-ipfs/blocks/key"
17 core "github.com/ipfs/go-ipfs/core"
core/corehttp/gateway_test.go
+4 -4
@@ -9,16 +9,16 @@ import (
9 "testing"
10 "time"
11
12 - context "github.com/ipfs/go-ipfs/Godeps/_workspace/src/golang.org/x/net/context"
12 core "github.com/ipfs/go-ipfs/core"
13 coreunix "github.com/ipfs/go-ipfs/core/coreunix"
14 namesys "github.com/ipfs/go-ipfs/namesys"
16 - ci "github.com/ipfs/go-ipfs/p2p/crypto"
17 - id "github.com/ipfs/go-ipfs/p2p/protocol/identify"
15 path "github.com/ipfs/go-ipfs/path"
16 repo "github.com/ipfs/go-ipfs/repo"
17 config "github.com/ipfs/go-ipfs/repo/config"
18 testutil "github.com/ipfs/go-ipfs/util/testutil"
19 + ci "gx/ipfs/QmY3NAw959vbE1oJooP9HchcRdBsbxhgQsEZTRhKgvoSuC/go-libp2p/p2p/crypto"
20 + id "gx/ipfs/QmY3NAw959vbE1oJooP9HchcRdBsbxhgQsEZTRhKgvoSuC/go-libp2p/p2p/protocol/identify"
21 + context "gx/ipfs/QmZy2y8t9zQH2a1b8q2ZSLKp17ATuJoCNxxyMFG5qFExpt/go-net/context"
22 )
23
24 type mockNamesys map[string]path.Path
@@ -431,7 +431,7 @@ func TestVersion(t *testing.T) {
431 t.Fatalf("response doesn't contain client version:\n%s", s)
432 }
433
434 - if !strings.Contains(s, "Protocol Version: "+id.IpfsVersion) {
434 + if !strings.Contains(s, "Protocol Version: "+id.LibP2PVersion) {
435 t.Fatalf("response doesn't contain protocol version:\n%s", s)
436 }
437 }
core/corehttp/ipns_hostname.go
+1 -1
@@ -6,7 +6,7 @@ import (
6 "strings"
7
8 isd "github.com/ipfs/go-ipfs/Godeps/_workspace/src/github.com/jbenet/go-is-domain"
9 - "github.com/ipfs/go-ipfs/Godeps/_workspace/src/golang.org/x/net/context"
9 + "gx/ipfs/QmZy2y8t9zQH2a1b8q2ZSLKp17ATuJoCNxxyMFG5qFExpt/go-net/context"
10 "github.com/ipfs/go-ipfs/core"
11 )
12
core/corehttp/logs.go
+1 -1
@@ -6,7 +6,7 @@ import (
6 "net/http"
7
8 core "github.com/ipfs/go-ipfs/core"
9 - logging "github.com/ipfs/go-ipfs/vendor/QmQg1J6vikuXF9oDvm4wpdeAUvvkVEKW1EYDw9HhTMnP2b/go-log"
9 + logging "gx/ipfs/QmaPaGNE2GqnfJjRRpQuQuFHuJn4FZvsrGxdik4kgxCkBi/go-log"
10 )
11
12 type writeErrNotifier struct {
core/corenet/net.go
+5 -5
@@ -3,11 +3,11 @@ package corenet
3 import (
4 "time"
5
6 - context "github.com/ipfs/go-ipfs/Godeps/_workspace/src/golang.org/x/net/context"
6 core "github.com/ipfs/go-ipfs/core"
8 - net "github.com/ipfs/go-ipfs/p2p/net"
9 - peer "github.com/ipfs/go-ipfs/p2p/peer"
10 - pro "github.com/ipfs/go-ipfs/p2p/protocol"
7 + net "gx/ipfs/QmY3NAw959vbE1oJooP9HchcRdBsbxhgQsEZTRhKgvoSuC/go-libp2p/p2p/net"
8 + peer "gx/ipfs/QmY3NAw959vbE1oJooP9HchcRdBsbxhgQsEZTRhKgvoSuC/go-libp2p/p2p/peer"
9 + pro "gx/ipfs/QmY3NAw959vbE1oJooP9HchcRdBsbxhgQsEZTRhKgvoSuC/go-libp2p/p2p/protocol"
10 + context "gx/ipfs/QmZy2y8t9zQH2a1b8q2ZSLKp17ATuJoCNxxyMFG5qFExpt/go-net/context"
11 )
12
13 type ipfsListener struct {
@@ -60,5 +60,5 @@ func Dial(nd *core.IpfsNode, p peer.ID, protocol string) (net.Stream, error) {
60 if err != nil {
61 return nil, err
62 }
63 - return nd.PeerHost.NewStream(pro.ID(protocol), p)
63 + return nd.PeerHost.NewStream(nd.Context(), pro.ID(protocol), p)
64 }
core/corerepo/gc.go
+2 -2
@@ -5,12 +5,12 @@ import (
5 "time"
6
7 humanize "github.com/ipfs/go-ipfs/Godeps/_workspace/src/github.com/dustin/go-humanize"
8 - context "github.com/ipfs/go-ipfs/Godeps/_workspace/src/golang.org/x/net/context"
8 + context "gx/ipfs/QmZy2y8t9zQH2a1b8q2ZSLKp17ATuJoCNxxyMFG5qFExpt/go-net/context"
9 key "github.com/ipfs/go-ipfs/blocks/key"
10 "github.com/ipfs/go-ipfs/core"
11 gc "github.com/ipfs/go-ipfs/pin/gc"
12 repo "github.com/ipfs/go-ipfs/repo"
13 - logging "github.com/ipfs/go-ipfs/vendor/QmQg1J6vikuXF9oDvm4wpdeAUvvkVEKW1EYDw9HhTMnP2b/go-log"
13 + logging "gx/ipfs/QmaPaGNE2GqnfJjRRpQuQuFHuJn4FZvsrGxdik4kgxCkBi/go-log"
14 )
15
16 var log = logging.Logger("corerepo")
core/corerepo/pinning.go
+1 -1
@@ -16,7 +16,7 @@ package corerepo
16 import (
17 "fmt"
18
19 - context "github.com/ipfs/go-ipfs/Godeps/_workspace/src/golang.org/x/net/context"
19 + context "gx/ipfs/QmZy2y8t9zQH2a1b8q2ZSLKp17ATuJoCNxxyMFG5qFExpt/go-net/context"
20
21 key "github.com/ipfs/go-ipfs/blocks/key"
22 "github.com/ipfs/go-ipfs/core"
core/corerouting/core.go
+3 -3
@@ -4,14 +4,14 @@ import (
4 "errors"
5
6 ds "github.com/ipfs/go-ipfs/Godeps/_workspace/src/github.com/ipfs/go-datastore"
7 - context "github.com/ipfs/go-ipfs/Godeps/_workspace/src/golang.org/x/net/context"
7 + context "gx/ipfs/QmZy2y8t9zQH2a1b8q2ZSLKp17ATuJoCNxxyMFG5qFExpt/go-net/context"
8 core "github.com/ipfs/go-ipfs/core"
9 - "github.com/ipfs/go-ipfs/p2p/host"
10 - "github.com/ipfs/go-ipfs/p2p/peer"
9 repo "github.com/ipfs/go-ipfs/repo"
10 routing "github.com/ipfs/go-ipfs/routing"
11 supernode "github.com/ipfs/go-ipfs/routing/supernode"
12 gcproxy "github.com/ipfs/go-ipfs/routing/supernode/proxy"
13 + "gx/ipfs/QmY3NAw959vbE1oJooP9HchcRdBsbxhgQsEZTRhKgvoSuC/go-libp2p/p2p/host"
14 + "gx/ipfs/QmY3NAw959vbE1oJooP9HchcRdBsbxhgQsEZTRhKgvoSuC/go-libp2p/p2p/peer"
15 )
16
17 // NB: DHT option is included in the core to avoid 1) because it's a sane
core/coreunix/add.go
+2 -2
@@ -10,7 +10,7 @@ import (
10
11 ds "github.com/ipfs/go-ipfs/Godeps/_workspace/src/github.com/ipfs/go-datastore"
12 syncds "github.com/ipfs/go-ipfs/Godeps/_workspace/src/github.com/ipfs/go-datastore/sync"
13 - context "github.com/ipfs/go-ipfs/Godeps/_workspace/src/golang.org/x/net/context"
13 + context "gx/ipfs/QmZy2y8t9zQH2a1b8q2ZSLKp17ATuJoCNxxyMFG5qFExpt/go-net/context"
14 bstore "github.com/ipfs/go-ipfs/blocks/blockstore"
15 key "github.com/ipfs/go-ipfs/blocks/key"
16 bserv "github.com/ipfs/go-ipfs/blockservice"
@@ -24,7 +24,7 @@ import (
24 core "github.com/ipfs/go-ipfs/core"
25 dag "github.com/ipfs/go-ipfs/merkledag"
26 unixfs "github.com/ipfs/go-ipfs/unixfs"
27 - logging "github.com/ipfs/go-ipfs/vendor/QmQg1J6vikuXF9oDvm4wpdeAUvvkVEKW1EYDw9HhTMnP2b/go-log"
27 + logging "gx/ipfs/QmaPaGNE2GqnfJjRRpQuQuFHuJn4FZvsrGxdik4kgxCkBi/go-log"
28 )
29
30 var log = logging.Logger("coreunix")
core/coreunix/add_test.go
+1 -1
@@ -7,7 +7,7 @@ import (
7 "testing"
8 "time"
9
10 - "github.com/ipfs/go-ipfs/Godeps/_workspace/src/golang.org/x/net/context"
10 + "gx/ipfs/QmZy2y8t9zQH2a1b8q2ZSLKp17ATuJoCNxxyMFG5qFExpt/go-net/context"
11 "github.com/ipfs/go-ipfs/blocks/key"
12 "github.com/ipfs/go-ipfs/commands/files"
13 "github.com/ipfs/go-ipfs/core"
core/coreunix/cat.go
+1 -1
@@ -1,7 +1,7 @@
1 package coreunix
2
3 import (
4 - context "github.com/ipfs/go-ipfs/Godeps/_workspace/src/golang.org/x/net/context"
4 + context "gx/ipfs/QmZy2y8t9zQH2a1b8q2ZSLKp17ATuJoCNxxyMFG5qFExpt/go-net/context"
5 core "github.com/ipfs/go-ipfs/core"
6 path "github.com/ipfs/go-ipfs/path"
7 uio "github.com/ipfs/go-ipfs/unixfs/io"
core/coreunix/metadata_test.go
+1 -1
@@ -7,7 +7,7 @@ import (
7
8 ds "github.com/ipfs/go-ipfs/Godeps/_workspace/src/github.com/ipfs/go-datastore"
9 dssync "github.com/ipfs/go-ipfs/Godeps/_workspace/src/github.com/ipfs/go-datastore/sync"
10 - context "github.com/ipfs/go-ipfs/Godeps/_workspace/src/golang.org/x/net/context"
10 + context "gx/ipfs/QmZy2y8t9zQH2a1b8q2ZSLKp17ATuJoCNxxyMFG5qFExpt/go-net/context"
11
12 bstore "github.com/ipfs/go-ipfs/blocks/blockstore"
13 key "github.com/ipfs/go-ipfs/blocks/key"
core/mock/mock.go
+5 -5
@@ -5,18 +5,18 @@ import (
5
6 "github.com/ipfs/go-ipfs/Godeps/_workspace/src/github.com/ipfs/go-datastore"
7 syncds "github.com/ipfs/go-ipfs/Godeps/_workspace/src/github.com/ipfs/go-datastore/sync"
8 - context "github.com/ipfs/go-ipfs/Godeps/_workspace/src/golang.org/x/net/context"
8 + context "gx/ipfs/QmZy2y8t9zQH2a1b8q2ZSLKp17ATuJoCNxxyMFG5qFExpt/go-net/context"
9
10 commands "github.com/ipfs/go-ipfs/commands"
11 core "github.com/ipfs/go-ipfs/core"
12 - metrics "github.com/ipfs/go-ipfs/metrics"
13 - host "github.com/ipfs/go-ipfs/p2p/host"
14 - mocknet "github.com/ipfs/go-ipfs/p2p/net/mock"
15 - peer "github.com/ipfs/go-ipfs/p2p/peer"
12 "github.com/ipfs/go-ipfs/repo"
13 config "github.com/ipfs/go-ipfs/repo/config"
14 ds2 "github.com/ipfs/go-ipfs/util/datastore2"
15 testutil "github.com/ipfs/go-ipfs/util/testutil"
16 + host "gx/ipfs/QmY3NAw959vbE1oJooP9HchcRdBsbxhgQsEZTRhKgvoSuC/go-libp2p/p2p/host"
17 + metrics "gx/ipfs/QmY3NAw959vbE1oJooP9HchcRdBsbxhgQsEZTRhKgvoSuC/go-libp2p/p2p/metrics"
18 + mocknet "gx/ipfs/QmY3NAw959vbE1oJooP9HchcRdBsbxhgQsEZTRhKgvoSuC/go-libp2p/p2p/net/mock"
19 + peer "gx/ipfs/QmY3NAw959vbE1oJooP9HchcRdBsbxhgQsEZTRhKgvoSuC/go-libp2p/p2p/peer"
20 )
21
22 // NewMockNode constructs an IpfsNode for use in tests.
core/pathresolver.go
+1 -1
@@ -4,7 +4,7 @@ import (
4 "errors"
5 "strings"
6
7 - context "github.com/ipfs/go-ipfs/Godeps/_workspace/src/golang.org/x/net/context"
7 + context "gx/ipfs/QmZy2y8t9zQH2a1b8q2ZSLKp17ATuJoCNxxyMFG5qFExpt/go-net/context"
8
9 key "github.com/ipfs/go-ipfs/blocks/key"
10 merkledag "github.com/ipfs/go-ipfs/merkledag"
diagnostics/diag.go
+7 -7
@@ -14,13 +14,13 @@ import (
14 ggio "github.com/ipfs/go-ipfs/Godeps/_workspace/src/github.com/gogo/protobuf/io"
15 proto "github.com/ipfs/go-ipfs/Godeps/_workspace/src/github.com/gogo/protobuf/proto"
16 ctxio "github.com/ipfs/go-ipfs/Godeps/_workspace/src/github.com/jbenet/go-context/io"
17 - context "github.com/ipfs/go-ipfs/Godeps/_workspace/src/golang.org/x/net/context"
17 + context "gx/ipfs/QmZy2y8t9zQH2a1b8q2ZSLKp17ATuJoCNxxyMFG5qFExpt/go-net/context"
18 pb "github.com/ipfs/go-ipfs/diagnostics/pb"
19 - host "github.com/ipfs/go-ipfs/p2p/host"
20 - inet "github.com/ipfs/go-ipfs/p2p/net"
21 - peer "github.com/ipfs/go-ipfs/p2p/peer"
22 - protocol "github.com/ipfs/go-ipfs/p2p/protocol"
23 - logging "github.com/ipfs/go-ipfs/vendor/QmQg1J6vikuXF9oDvm4wpdeAUvvkVEKW1EYDw9HhTMnP2b/go-log"
19 + logging "gx/ipfs/QmaPaGNE2GqnfJjRRpQuQuFHuJn4FZvsrGxdik4kgxCkBi/go-log"
20 + host "gx/ipfs/QmY3NAw959vbE1oJooP9HchcRdBsbxhgQsEZTRhKgvoSuC/go-libp2p/p2p/host"
21 + inet "gx/ipfs/QmY3NAw959vbE1oJooP9HchcRdBsbxhgQsEZTRhKgvoSuC/go-libp2p/p2p/net"
22 + peer "gx/ipfs/QmY3NAw959vbE1oJooP9HchcRdBsbxhgQsEZTRhKgvoSuC/go-libp2p/p2p/peer"
23 + protocol "gx/ipfs/QmY3NAw959vbE1oJooP9HchcRdBsbxhgQsEZTRhKgvoSuC/go-libp2p/p2p/protocol"
24 )
25
26 var log = logging.Logger("diagnostics")
@@ -203,7 +203,7 @@ func (d *Diagnostics) getDiagnosticFromPeers(ctx context.Context, peers map[peer
203 }
204
205 func (d *Diagnostics) getDiagnosticFromPeer(ctx context.Context, p peer.ID, pmes *pb.Message) (<-chan *DiagInfo, error) {
206 - s, err := d.host.NewStream(ProtocolDiag, p)
206 + s, err := d.host.NewStream(ctx, ProtocolDiag, p)
207 if err != nil {
208 return nil, err
209 }
diagnostics/vis.go
+1 -1
@@ -5,8 +5,8 @@ import (
5 "fmt"
6 "io"
7
8 - peer "github.com/ipfs/go-ipfs/p2p/peer"
8 rtable "github.com/ipfs/go-ipfs/routing/kbucket"
9 + peer "gx/ipfs/QmY3NAw959vbE1oJooP9HchcRdBsbxhgQsEZTRhKgvoSuC/go-libp2p/p2p/peer"
10 )
11
12 type node struct {
exchange/bitswap/bitswap.go
+3 -3
@@ -10,7 +10,7 @@ import (
10
11 process "github.com/ipfs/go-ipfs/Godeps/_workspace/src/github.com/jbenet/goprocess"
12 procctx "github.com/ipfs/go-ipfs/Godeps/_workspace/src/github.com/jbenet/goprocess/context"
13 - context "github.com/ipfs/go-ipfs/Godeps/_workspace/src/golang.org/x/net/context"
13 + context "gx/ipfs/QmZy2y8t9zQH2a1b8q2ZSLKp17ATuJoCNxxyMFG5qFExpt/go-net/context"
14 blocks "github.com/ipfs/go-ipfs/blocks"
15 blockstore "github.com/ipfs/go-ipfs/blocks/blockstore"
16 key "github.com/ipfs/go-ipfs/blocks/key"
@@ -20,9 +20,9 @@ import (
20 bsnet "github.com/ipfs/go-ipfs/exchange/bitswap/network"
21 notifications "github.com/ipfs/go-ipfs/exchange/bitswap/notifications"
22 wantlist "github.com/ipfs/go-ipfs/exchange/bitswap/wantlist"
23 - peer "github.com/ipfs/go-ipfs/p2p/peer"
23 "github.com/ipfs/go-ipfs/thirdparty/delay"
25 - logging "github.com/ipfs/go-ipfs/vendor/QmQg1J6vikuXF9oDvm4wpdeAUvvkVEKW1EYDw9HhTMnP2b/go-log"
24 + logging "gx/ipfs/QmaPaGNE2GqnfJjRRpQuQuFHuJn4FZvsrGxdik4kgxCkBi/go-log"
25 + peer "gx/ipfs/QmY3NAw959vbE1oJooP9HchcRdBsbxhgQsEZTRhKgvoSuC/go-libp2p/p2p/peer"
26 )
27
28 var log = logging.Logger("bitswap")
exchange/bitswap/bitswap_test.go
+2 -2
@@ -7,16 +7,16 @@ import (
7 "time"
8
9 detectrace "github.com/ipfs/go-ipfs/Godeps/_workspace/src/github.com/jbenet/go-detect-race"
10 - context "github.com/ipfs/go-ipfs/Godeps/_workspace/src/golang.org/x/net/context"
10 + context "gx/ipfs/QmZy2y8t9zQH2a1b8q2ZSLKp17ATuJoCNxxyMFG5qFExpt/go-net/context"
11 travis "github.com/ipfs/go-ipfs/util/testutil/ci/travis"
12
13 blocks "github.com/ipfs/go-ipfs/blocks"
14 blocksutil "github.com/ipfs/go-ipfs/blocks/blocksutil"
15 key "github.com/ipfs/go-ipfs/blocks/key"
16 tn "github.com/ipfs/go-ipfs/exchange/bitswap/testnet"
17 - p2ptestutil "github.com/ipfs/go-ipfs/p2p/test/util"
17 mockrouting "github.com/ipfs/go-ipfs/routing/mock"
18 delay "github.com/ipfs/go-ipfs/thirdparty/delay"
19 + p2ptestutil "gx/ipfs/QmY3NAw959vbE1oJooP9HchcRdBsbxhgQsEZTRhKgvoSuC/go-libp2p/p2p/test/util"
20 )
21
22 // FIXME the tests are really sensitive to the network delay. fix them to work
exchange/bitswap/decision/bench_test.go
+1 -1
@@ -6,8 +6,8 @@ import (
6
7 key "github.com/ipfs/go-ipfs/blocks/key"
8 "github.com/ipfs/go-ipfs/exchange/bitswap/wantlist"
9 - "github.com/ipfs/go-ipfs/p2p/peer"
9 "github.com/ipfs/go-ipfs/util/testutil"
10 + "gx/ipfs/QmY3NAw959vbE1oJooP9HchcRdBsbxhgQsEZTRhKgvoSuC/go-libp2p/p2p/peer"
11 )
12
13 // FWIW: At the time of this commit, including a timestamp in task increases
exchange/bitswap/decision/engine.go
+3 -3
@@ -4,13 +4,13 @@ package decision
4 import (
5 "sync"
6
7 - context "github.com/ipfs/go-ipfs/Godeps/_workspace/src/golang.org/x/net/context"
7 + context "gx/ipfs/QmZy2y8t9zQH2a1b8q2ZSLKp17ATuJoCNxxyMFG5qFExpt/go-net/context"
8 blocks "github.com/ipfs/go-ipfs/blocks"
9 bstore "github.com/ipfs/go-ipfs/blocks/blockstore"
10 bsmsg "github.com/ipfs/go-ipfs/exchange/bitswap/message"
11 wl "github.com/ipfs/go-ipfs/exchange/bitswap/wantlist"
12 - peer "github.com/ipfs/go-ipfs/p2p/peer"
13 - logging "github.com/ipfs/go-ipfs/vendor/QmQg1J6vikuXF9oDvm4wpdeAUvvkVEKW1EYDw9HhTMnP2b/go-log"
12 + logging "gx/ipfs/QmaPaGNE2GqnfJjRRpQuQuFHuJn4FZvsrGxdik4kgxCkBi/go-log"
13 + peer "gx/ipfs/QmY3NAw959vbE1oJooP9HchcRdBsbxhgQsEZTRhKgvoSuC/go-libp2p/p2p/peer"
14 )
15
16 // TODO consider taking responsibility for other types of requests. For
exchange/bitswap/decision/engine_test.go
+2 -2
@@ -10,12 +10,12 @@ import (
10
11 ds "github.com/ipfs/go-ipfs/Godeps/_workspace/src/github.com/ipfs/go-datastore"
12 dssync "github.com/ipfs/go-ipfs/Godeps/_workspace/src/github.com/ipfs/go-datastore/sync"
13 - context "github.com/ipfs/go-ipfs/Godeps/_workspace/src/golang.org/x/net/context"
13 + context "gx/ipfs/QmZy2y8t9zQH2a1b8q2ZSLKp17ATuJoCNxxyMFG5qFExpt/go-net/context"
14 blocks "github.com/ipfs/go-ipfs/blocks"
15 blockstore "github.com/ipfs/go-ipfs/blocks/blockstore"
16 message "github.com/ipfs/go-ipfs/exchange/bitswap/message"
17 - peer "github.com/ipfs/go-ipfs/p2p/peer"
17 testutil "github.com/ipfs/go-ipfs/util/testutil"
18 + peer "gx/ipfs/QmY3NAw959vbE1oJooP9HchcRdBsbxhgQsEZTRhKgvoSuC/go-libp2p/p2p/peer"
19 )
20
21 type peerAndEngine struct {
exchange/bitswap/decision/ledger.go
+1 -1
@@ -5,7 +5,7 @@ import (
5
6 key "github.com/ipfs/go-ipfs/blocks/key"
7 wl "github.com/ipfs/go-ipfs/exchange/bitswap/wantlist"
8 - peer "github.com/ipfs/go-ipfs/p2p/peer"
8 + peer "gx/ipfs/QmY3NAw959vbE1oJooP9HchcRdBsbxhgQsEZTRhKgvoSuC/go-libp2p/p2p/peer"
9 )
10
11 // keySet is just a convenient alias for maps of keys, where we only care
exchange/bitswap/decision/peer_request_queue.go
+1 -1
@@ -6,8 +6,8 @@ import (
6
7 key "github.com/ipfs/go-ipfs/blocks/key"
8 wantlist "github.com/ipfs/go-ipfs/exchange/bitswap/wantlist"
9 - peer "github.com/ipfs/go-ipfs/p2p/peer"
9 pq "github.com/ipfs/go-ipfs/thirdparty/pq"
10 + peer "gx/ipfs/QmY3NAw959vbE1oJooP9HchcRdBsbxhgQsEZTRhKgvoSuC/go-libp2p/p2p/peer"
11 )
12
13 type peerRequestQueue interface {
exchange/bitswap/message/message.go
+1 -1
@@ -7,7 +7,7 @@ import (
7 key "github.com/ipfs/go-ipfs/blocks/key"
8 pb "github.com/ipfs/go-ipfs/exchange/bitswap/message/pb"
9 wantlist "github.com/ipfs/go-ipfs/exchange/bitswap/wantlist"
10 - inet "github.com/ipfs/go-ipfs/p2p/net"
10 + inet "gx/ipfs/QmY3NAw959vbE1oJooP9HchcRdBsbxhgQsEZTRhKgvoSuC/go-libp2p/p2p/net"
11
12 ggio "github.com/ipfs/go-ipfs/Godeps/_workspace/src/github.com/gogo/protobuf/io"
13 proto "github.com/ipfs/go-ipfs/Godeps/_workspace/src/github.com/gogo/protobuf/proto"
exchange/bitswap/network/interface.go
+3 -3
@@ -1,11 +1,11 @@
1 package network
2
3 import (
4 - context "github.com/ipfs/go-ipfs/Godeps/_workspace/src/golang.org/x/net/context"
4 + context "gx/ipfs/QmZy2y8t9zQH2a1b8q2ZSLKp17ATuJoCNxxyMFG5qFExpt/go-net/context"
5 key "github.com/ipfs/go-ipfs/blocks/key"
6 bsmsg "github.com/ipfs/go-ipfs/exchange/bitswap/message"
7 - peer "github.com/ipfs/go-ipfs/p2p/peer"
8 - protocol "github.com/ipfs/go-ipfs/p2p/protocol"
7 + peer "gx/ipfs/QmY3NAw959vbE1oJooP9HchcRdBsbxhgQsEZTRhKgvoSuC/go-libp2p/p2p/peer"
8 + protocol "gx/ipfs/QmY3NAw959vbE1oJooP9HchcRdBsbxhgQsEZTRhKgvoSuC/go-libp2p/p2p/protocol"
9 )
10
11 var ProtocolBitswap protocol.ID = "/ipfs/bitswap"
exchange/bitswap/network/ipfs_impl.go
+7 -7
@@ -1,15 +1,15 @@
1 package network
2
3 import (
4 - ma "github.com/ipfs/go-ipfs/Godeps/_workspace/src/github.com/jbenet/go-multiaddr"
5 - context "github.com/ipfs/go-ipfs/Godeps/_workspace/src/golang.org/x/net/context"
4 + context "gx/ipfs/QmZy2y8t9zQH2a1b8q2ZSLKp17ATuJoCNxxyMFG5qFExpt/go-net/context"
5 key "github.com/ipfs/go-ipfs/blocks/key"
6 bsmsg "github.com/ipfs/go-ipfs/exchange/bitswap/message"
8 - host "github.com/ipfs/go-ipfs/p2p/host"
9 - inet "github.com/ipfs/go-ipfs/p2p/net"
10 - peer "github.com/ipfs/go-ipfs/p2p/peer"
7 routing "github.com/ipfs/go-ipfs/routing"
12 - logging "github.com/ipfs/go-ipfs/vendor/QmQg1J6vikuXF9oDvm4wpdeAUvvkVEKW1EYDw9HhTMnP2b/go-log"
8 + logging "gx/ipfs/QmaPaGNE2GqnfJjRRpQuQuFHuJn4FZvsrGxdik4kgxCkBi/go-log"
9 + ma "gx/ipfs/QmR3JkmZBKYXgNMNsNZawm914455Qof3PEopwuVSeXG7aV/go-multiaddr"
10 + host "gx/ipfs/QmY3NAw959vbE1oJooP9HchcRdBsbxhgQsEZTRhKgvoSuC/go-libp2p/p2p/host"
11 + inet "gx/ipfs/QmY3NAw959vbE1oJooP9HchcRdBsbxhgQsEZTRhKgvoSuC/go-libp2p/p2p/net"
12 + peer "gx/ipfs/QmY3NAw959vbE1oJooP9HchcRdBsbxhgQsEZTRhKgvoSuC/go-libp2p/p2p/peer"
13 )
14
15 var log = logging.Logger("bitswap_network")
@@ -46,7 +46,7 @@ func (bsnet *impl) newStreamToPeer(ctx context.Context, p peer.ID) (inet.Stream,
46 return nil, err
47 }
48
49 - return bsnet.host.NewStream(ProtocolBitswap, p)
49 + return bsnet.host.NewStream(ctx, ProtocolBitswap, p)
50 }
51
52 func (bsnet *impl) SendMessage(
exchange/bitswap/notifications/notifications.go
+1 -1
@@ -2,7 +2,7 @@ package notifications
2
3 import (
4 pubsub "github.com/ipfs/go-ipfs/Godeps/_workspace/src/github.com/briantigerchow/pubsub"
5 - context "github.com/ipfs/go-ipfs/Godeps/_workspace/src/golang.org/x/net/context"
5 + context "gx/ipfs/QmZy2y8t9zQH2a1b8q2ZSLKp17ATuJoCNxxyMFG5qFExpt/go-net/context"
6 blocks "github.com/ipfs/go-ipfs/blocks"
7 key "github.com/ipfs/go-ipfs/blocks/key"
8 )
exchange/bitswap/notifications/notifications_test.go
+1 -1
@@ -5,7 +5,7 @@ import (
5 "testing"
6 "time"
7
8 - context "github.com/ipfs/go-ipfs/Godeps/_workspace/src/golang.org/x/net/context"
8 + context "gx/ipfs/QmZy2y8t9zQH2a1b8q2ZSLKp17ATuJoCNxxyMFG5qFExpt/go-net/context"
9 blocks "github.com/ipfs/go-ipfs/blocks"
10 blocksutil "github.com/ipfs/go-ipfs/blocks/blocksutil"
11 key "github.com/ipfs/go-ipfs/blocks/key"
exchange/bitswap/testnet/interface.go
+1 -1
@@ -2,8 +2,8 @@ package bitswap
2
3 import (
4 bsnet "github.com/ipfs/go-ipfs/exchange/bitswap/network"
5 - peer "github.com/ipfs/go-ipfs/p2p/peer"
5 "github.com/ipfs/go-ipfs/util/testutil"
6 + peer "gx/ipfs/QmY3NAw959vbE1oJooP9HchcRdBsbxhgQsEZTRhKgvoSuC/go-libp2p/p2p/peer"
7 )
8
9 type Network interface {
exchange/bitswap/testnet/network_test.go
+2 -2
@@ -4,14 +4,14 @@ import (
4 "sync"
5 "testing"
6
7 - context "github.com/ipfs/go-ipfs/Godeps/_workspace/src/golang.org/x/net/context"
7 + context "gx/ipfs/QmZy2y8t9zQH2a1b8q2ZSLKp17ATuJoCNxxyMFG5qFExpt/go-net/context"
8 blocks "github.com/ipfs/go-ipfs/blocks"
9 bsmsg "github.com/ipfs/go-ipfs/exchange/bitswap/message"
10 bsnet "github.com/ipfs/go-ipfs/exchange/bitswap/network"
11 - peer "github.com/ipfs/go-ipfs/p2p/peer"
11 mockrouting "github.com/ipfs/go-ipfs/routing/mock"
12 delay "github.com/ipfs/go-ipfs/thirdparty/delay"
13 testutil "github.com/ipfs/go-ipfs/util/testutil"
14 + peer "gx/ipfs/QmY3NAw959vbE1oJooP9HchcRdBsbxhgQsEZTRhKgvoSuC/go-libp2p/p2p/peer"
15 )
16
17 func TestSendMessageAsyncButWaitForResponse(t *testing.T) {
exchange/bitswap/testnet/peernet.go
+3 -3
@@ -2,12 +2,12 @@ package bitswap
2
3 import (
4 ds "github.com/ipfs/go-ipfs/Godeps/_workspace/src/github.com/ipfs/go-datastore"
5 - context "github.com/ipfs/go-ipfs/Godeps/_workspace/src/golang.org/x/net/context"
5 + context "gx/ipfs/QmZy2y8t9zQH2a1b8q2ZSLKp17ATuJoCNxxyMFG5qFExpt/go-net/context"
6 bsnet "github.com/ipfs/go-ipfs/exchange/bitswap/network"
7 - mockpeernet "github.com/ipfs/go-ipfs/p2p/net/mock"
8 - peer "github.com/ipfs/go-ipfs/p2p/peer"
7 mockrouting "github.com/ipfs/go-ipfs/routing/mock"
8 testutil "github.com/ipfs/go-ipfs/util/testutil"
9 + mockpeernet "gx/ipfs/QmY3NAw959vbE1oJooP9HchcRdBsbxhgQsEZTRhKgvoSuC/go-libp2p/p2p/net/mock"
10 + peer "gx/ipfs/QmY3NAw959vbE1oJooP9HchcRdBsbxhgQsEZTRhKgvoSuC/go-libp2p/p2p/peer"
11 )
12
13 type peernet struct {
exchange/bitswap/testnet/virtual.go
+2 -2
@@ -3,15 +3,15 @@ package bitswap
3 import (
4 "errors"
5
6 - context "github.com/ipfs/go-ipfs/Godeps/_workspace/src/golang.org/x/net/context"
6 + context "gx/ipfs/QmZy2y8t9zQH2a1b8q2ZSLKp17ATuJoCNxxyMFG5qFExpt/go-net/context"
7 key "github.com/ipfs/go-ipfs/blocks/key"
8 bsmsg "github.com/ipfs/go-ipfs/exchange/bitswap/message"
9 bsnet "github.com/ipfs/go-ipfs/exchange/bitswap/network"
10 - peer "github.com/ipfs/go-ipfs/p2p/peer"
10 routing "github.com/ipfs/go-ipfs/routing"
11 mockrouting "github.com/ipfs/go-ipfs/routing/mock"
12 delay "github.com/ipfs/go-ipfs/thirdparty/delay"
13 testutil "github.com/ipfs/go-ipfs/util/testutil"
14 + peer "gx/ipfs/QmY3NAw959vbE1oJooP9HchcRdBsbxhgQsEZTRhKgvoSuC/go-libp2p/p2p/peer"
15 )
16
17 func VirtualNetwork(rs mockrouting.Server, d delay.D) Network {
exchange/bitswap/testutils.go
+3 -3
@@ -5,14 +5,14 @@ import (
5
6 ds "github.com/ipfs/go-ipfs/Godeps/_workspace/src/github.com/ipfs/go-datastore"
7 ds_sync "github.com/ipfs/go-ipfs/Godeps/_workspace/src/github.com/ipfs/go-datastore/sync"
8 - context "github.com/ipfs/go-ipfs/Godeps/_workspace/src/golang.org/x/net/context"
8 + context "gx/ipfs/QmZy2y8t9zQH2a1b8q2ZSLKp17ATuJoCNxxyMFG5qFExpt/go-net/context"
9 blockstore "github.com/ipfs/go-ipfs/blocks/blockstore"
10 tn "github.com/ipfs/go-ipfs/exchange/bitswap/testnet"
11 - peer "github.com/ipfs/go-ipfs/p2p/peer"
12 - p2ptestutil "github.com/ipfs/go-ipfs/p2p/test/util"
11 delay "github.com/ipfs/go-ipfs/thirdparty/delay"
12 datastore2 "github.com/ipfs/go-ipfs/util/datastore2"
13 testutil "github.com/ipfs/go-ipfs/util/testutil"
14 + peer "gx/ipfs/QmY3NAw959vbE1oJooP9HchcRdBsbxhgQsEZTRhKgvoSuC/go-libp2p/p2p/peer"
15 + p2ptestutil "gx/ipfs/QmY3NAw959vbE1oJooP9HchcRdBsbxhgQsEZTRhKgvoSuC/go-libp2p/p2p/test/util"
16 )
17
18 // WARNING: this uses RandTestBogusIdentity DO NOT USE for NON TESTS!
exchange/bitswap/wantmanager.go
+2 -2
@@ -4,13 +4,13 @@ import (
4 "sync"
5 "time"
6
7 - context "github.com/ipfs/go-ipfs/Godeps/_workspace/src/golang.org/x/net/context"
7 + context "gx/ipfs/QmZy2y8t9zQH2a1b8q2ZSLKp17ATuJoCNxxyMFG5qFExpt/go-net/context"
8 key "github.com/ipfs/go-ipfs/blocks/key"
9 engine "github.com/ipfs/go-ipfs/exchange/bitswap/decision"
10 bsmsg "github.com/ipfs/go-ipfs/exchange/bitswap/message"
11 bsnet "github.com/ipfs/go-ipfs/exchange/bitswap/network"
12 wantlist "github.com/ipfs/go-ipfs/exchange/bitswap/wantlist"
13 - peer "github.com/ipfs/go-ipfs/p2p/peer"
13 + peer "gx/ipfs/QmY3NAw959vbE1oJooP9HchcRdBsbxhgQsEZTRhKgvoSuC/go-libp2p/p2p/peer"
14 )
15
16 type WantManager struct {
exchange/bitswap/workers.go
+2 -2
@@ -5,10 +5,10 @@ import (
5
6 process "github.com/ipfs/go-ipfs/Godeps/_workspace/src/github.com/jbenet/goprocess"
7 procctx "github.com/ipfs/go-ipfs/Godeps/_workspace/src/github.com/jbenet/goprocess/context"
8 - context "github.com/ipfs/go-ipfs/Godeps/_workspace/src/golang.org/x/net/context"
8 + context "gx/ipfs/QmZy2y8t9zQH2a1b8q2ZSLKp17ATuJoCNxxyMFG5qFExpt/go-net/context"
9
10 key "github.com/ipfs/go-ipfs/blocks/key"
11 - logging "github.com/ipfs/go-ipfs/vendor/QmQg1J6vikuXF9oDvm4wpdeAUvvkVEKW1EYDw9HhTMnP2b/go-log"
11 + logging "gx/ipfs/QmaPaGNE2GqnfJjRRpQuQuFHuJn4FZvsrGxdik4kgxCkBi/go-log"
12 )
13
14 var TaskWorkerCount = 8
exchange/interface.go
+1 -1
@@ -4,7 +4,7 @@ package exchange
4 import (
5 "io"
6
7 - context "github.com/ipfs/go-ipfs/Godeps/_workspace/src/golang.org/x/net/context"
7 + context "gx/ipfs/QmZy2y8t9zQH2a1b8q2ZSLKp17ATuJoCNxxyMFG5qFExpt/go-net/context"
8 blocks "github.com/ipfs/go-ipfs/blocks"
9 key "github.com/ipfs/go-ipfs/blocks/key"
10 )
exchange/offline/offline.go
+1 -1
@@ -3,7 +3,7 @@
3 package offline
4
5 import (
6 - context "github.com/ipfs/go-ipfs/Godeps/_workspace/src/golang.org/x/net/context"
6 + context "gx/ipfs/QmZy2y8t9zQH2a1b8q2ZSLKp17ATuJoCNxxyMFG5qFExpt/go-net/context"
7 blocks "github.com/ipfs/go-ipfs/blocks"
8 "github.com/ipfs/go-ipfs/blocks/blockstore"
9 key "github.com/ipfs/go-ipfs/blocks/key"
exchange/offline/offline_test.go
+1 -1
@@ -5,7 +5,7 @@ import (
5
6 ds "github.com/ipfs/go-ipfs/Godeps/_workspace/src/github.com/ipfs/go-datastore"
7 ds_sync "github.com/ipfs/go-ipfs/Godeps/_workspace/src/github.com/ipfs/go-datastore/sync"
8 - context "github.com/ipfs/go-ipfs/Godeps/_workspace/src/golang.org/x/net/context"
8 + context "gx/ipfs/QmZy2y8t9zQH2a1b8q2ZSLKp17ATuJoCNxxyMFG5qFExpt/go-net/context"
9 blocks "github.com/ipfs/go-ipfs/blocks"
10 "github.com/ipfs/go-ipfs/blocks/blockstore"
11 "github.com/ipfs/go-ipfs/blocks/blocksutil"
exchange/reprovide/reprovide.go
+2 -2
@@ -5,10 +5,10 @@ import (
5 "time"
6
7 backoff "github.com/ipfs/go-ipfs/Godeps/_workspace/src/github.com/cenkalti/backoff"
8 - context "github.com/ipfs/go-ipfs/Godeps/_workspace/src/golang.org/x/net/context"
8 + context "gx/ipfs/QmZy2y8t9zQH2a1b8q2ZSLKp17ATuJoCNxxyMFG5qFExpt/go-net/context"
9 blocks "github.com/ipfs/go-ipfs/blocks/blockstore"
10 routing "github.com/ipfs/go-ipfs/routing"
11 - logging "github.com/ipfs/go-ipfs/vendor/QmQg1J6vikuXF9oDvm4wpdeAUvvkVEKW1EYDw9HhTMnP2b/go-log"
11 + logging "gx/ipfs/QmaPaGNE2GqnfJjRRpQuQuFHuJn4FZvsrGxdik4kgxCkBi/go-log"
12 )
13
14 var log = logging.Logger("reprovider")
exchange/reprovide/reprovide_test.go
+1 -1
@@ -5,7 +5,7 @@ import (
5
6 ds "github.com/ipfs/go-ipfs/Godeps/_workspace/src/github.com/ipfs/go-datastore"
7 dssync "github.com/ipfs/go-ipfs/Godeps/_workspace/src/github.com/ipfs/go-datastore/sync"
8 - context "github.com/ipfs/go-ipfs/Godeps/_workspace/src/golang.org/x/net/context"
8 + context "gx/ipfs/QmZy2y8t9zQH2a1b8q2ZSLKp17ATuJoCNxxyMFG5qFExpt/go-net/context"
9 blocks "github.com/ipfs/go-ipfs/blocks"
10 blockstore "github.com/ipfs/go-ipfs/blocks/blockstore"
11 mock "github.com/ipfs/go-ipfs/routing/mock"
fuse/ipns/common.go
+2 -2
@@ -1,14 +1,14 @@
1 package ipns
2
3 import (
4 - context "github.com/ipfs/go-ipfs/Godeps/_workspace/src/golang.org/x/net/context"
4 + context "gx/ipfs/QmZy2y8t9zQH2a1b8q2ZSLKp17ATuJoCNxxyMFG5qFExpt/go-net/context"
5
6 "github.com/ipfs/go-ipfs/core"
7 mdag "github.com/ipfs/go-ipfs/merkledag"
8 nsys "github.com/ipfs/go-ipfs/namesys"
9 - ci "github.com/ipfs/go-ipfs/p2p/crypto"
9 path "github.com/ipfs/go-ipfs/path"
10 ft "github.com/ipfs/go-ipfs/unixfs"
11 + ci "gx/ipfs/QmY3NAw959vbE1oJooP9HchcRdBsbxhgQsEZTRhKgvoSuC/go-libp2p/p2p/crypto"
12 )
13
14 // InitializeKeyspace sets the ipns record for the given key to
fuse/ipns/ipns_test.go
+1 -1
@@ -14,7 +14,7 @@ import (
14 fstest "github.com/ipfs/go-ipfs/Godeps/_workspace/src/bazil.org/fuse/fs/fstestutil"
15 racedet "github.com/ipfs/go-ipfs/Godeps/_workspace/src/github.com/jbenet/go-detect-race"
16
17 - context "github.com/ipfs/go-ipfs/Godeps/_workspace/src/golang.org/x/net/context"
17 + context "gx/ipfs/QmZy2y8t9zQH2a1b8q2ZSLKp17ATuJoCNxxyMFG5qFExpt/go-net/context"
18 core "github.com/ipfs/go-ipfs/core"
19 //mfs "github.com/ipfs/go-ipfs/mfs"
20 namesys "github.com/ipfs/go-ipfs/namesys"
fuse/ipns/ipns_unix.go
+3 -3
@@ -11,16 +11,16 @@ import (
11
12 fuse "github.com/ipfs/go-ipfs/Godeps/_workspace/src/bazil.org/fuse"
13 fs "github.com/ipfs/go-ipfs/Godeps/_workspace/src/bazil.org/fuse/fs"
14 - "github.com/ipfs/go-ipfs/Godeps/_workspace/src/golang.org/x/net/context"
15 - logging "github.com/ipfs/go-ipfs/vendor/QmQg1J6vikuXF9oDvm4wpdeAUvvkVEKW1EYDw9HhTMnP2b/go-log"
14 + "gx/ipfs/QmZy2y8t9zQH2a1b8q2ZSLKp17ATuJoCNxxyMFG5qFExpt/go-net/context"
15 + logging "gx/ipfs/QmaPaGNE2GqnfJjRRpQuQuFHuJn4FZvsrGxdik4kgxCkBi/go-log"
16
17 key "github.com/ipfs/go-ipfs/blocks/key"
18 core "github.com/ipfs/go-ipfs/core"
19 dag "github.com/ipfs/go-ipfs/merkledag"
20 mfs "github.com/ipfs/go-ipfs/mfs"
21 - ci "github.com/ipfs/go-ipfs/p2p/crypto"
21 path "github.com/ipfs/go-ipfs/path"
22 ft "github.com/ipfs/go-ipfs/unixfs"
23 + ci "gx/ipfs/QmY3NAw959vbE1oJooP9HchcRdBsbxhgQsEZTRhKgvoSuC/go-libp2p/p2p/crypto"
24 )
25
26 var log = logging.Logger("fuse/ipns")
fuse/ipns/link_unix.go
+1 -1
@@ -7,7 +7,7 @@ import (
7
8 "github.com/ipfs/go-ipfs/Godeps/_workspace/src/bazil.org/fuse"
9 "github.com/ipfs/go-ipfs/Godeps/_workspace/src/bazil.org/fuse/fs"
10 - "github.com/ipfs/go-ipfs/Godeps/_workspace/src/golang.org/x/net/context"
10 + "gx/ipfs/QmZy2y8t9zQH2a1b8q2ZSLKp17ATuJoCNxxyMFG5qFExpt/go-net/context"
11 )
12
13 type Link struct {
fuse/mount/mount.go
+1 -1
@@ -10,7 +10,7 @@ import (
10
11 goprocess "github.com/ipfs/go-ipfs/Godeps/_workspace/src/github.com/jbenet/goprocess"
12
13 - logging "github.com/ipfs/go-ipfs/vendor/QmQg1J6vikuXF9oDvm4wpdeAUvvkVEKW1EYDw9HhTMnP2b/go-log"
13 + logging "gx/ipfs/QmaPaGNE2GqnfJjRRpQuQuFHuJn4FZvsrGxdik4kgxCkBi/go-log"
14 )
15
16 var log = logging.Logger("mount")
fuse/readonly/readonly_unix.go
+2 -2
@@ -12,14 +12,14 @@ import (
12 fuse "github.com/ipfs/go-ipfs/Godeps/_workspace/src/bazil.org/fuse"
13 fs "github.com/ipfs/go-ipfs/Godeps/_workspace/src/bazil.org/fuse/fs"
14 proto "github.com/ipfs/go-ipfs/Godeps/_workspace/src/github.com/gogo/protobuf/proto"
15 - "github.com/ipfs/go-ipfs/Godeps/_workspace/src/golang.org/x/net/context"
15 + "gx/ipfs/QmZy2y8t9zQH2a1b8q2ZSLKp17ATuJoCNxxyMFG5qFExpt/go-net/context"
16 core "github.com/ipfs/go-ipfs/core"
17 mdag "github.com/ipfs/go-ipfs/merkledag"
18 path "github.com/ipfs/go-ipfs/path"
19 uio "github.com/ipfs/go-ipfs/unixfs/io"
20 ftpb "github.com/ipfs/go-ipfs/unixfs/pb"
21 lgbl "github.com/ipfs/go-ipfs/util/eventlog/loggables"
22 - logging "github.com/ipfs/go-ipfs/vendor/QmQg1J6vikuXF9oDvm4wpdeAUvvkVEKW1EYDw9HhTMnP2b/go-log"
22 + logging "gx/ipfs/QmaPaGNE2GqnfJjRRpQuQuFHuJn4FZvsrGxdik4kgxCkBi/go-log"
23 )
24
25 var log = logging.Logger("fuse/ipfs")
importer/balanced/balanced_test.go
+1 -1
@@ -9,7 +9,7 @@ import (
9 "os"
10 "testing"
11
12 - "github.com/ipfs/go-ipfs/Godeps/_workspace/src/golang.org/x/net/context"
12 + "gx/ipfs/QmZy2y8t9zQH2a1b8q2ZSLKp17ATuJoCNxxyMFG5qFExpt/go-net/context"
13 chunk "github.com/ipfs/go-ipfs/importer/chunk"
14 h "github.com/ipfs/go-ipfs/importer/helpers"
15 dag "github.com/ipfs/go-ipfs/merkledag"
importer/chunk/splitting.go
+1 -1
@@ -4,7 +4,7 @@ package chunk
4 import (
5 "io"
6
7 - logging "github.com/ipfs/go-ipfs/vendor/QmQg1J6vikuXF9oDvm4wpdeAUvvkVEKW1EYDw9HhTMnP2b/go-log"
7 + logging "gx/ipfs/QmaPaGNE2GqnfJjRRpQuQuFHuJn4FZvsrGxdik4kgxCkBi/go-log"
8 )
9
10 var log = logging.Logger("chunk")
importer/helpers/helpers.go
+1 -1
@@ -3,7 +3,7 @@ package helpers
3 import (
4 "fmt"
5
6 - "github.com/ipfs/go-ipfs/Godeps/_workspace/src/golang.org/x/net/context"
6 + "gx/ipfs/QmZy2y8t9zQH2a1b8q2ZSLKp17ATuJoCNxxyMFG5qFExpt/go-net/context"
7 chunk "github.com/ipfs/go-ipfs/importer/chunk"
8 dag "github.com/ipfs/go-ipfs/merkledag"
9 ft "github.com/ipfs/go-ipfs/unixfs"
importer/importer.go
+1 -1
@@ -12,7 +12,7 @@ import (
12 h "github.com/ipfs/go-ipfs/importer/helpers"
13 trickle "github.com/ipfs/go-ipfs/importer/trickle"
14 dag "github.com/ipfs/go-ipfs/merkledag"
15 - logging "github.com/ipfs/go-ipfs/vendor/QmQg1J6vikuXF9oDvm4wpdeAUvvkVEKW1EYDw9HhTMnP2b/go-log"
15 + logging "gx/ipfs/QmaPaGNE2GqnfJjRRpQuQuFHuJn4FZvsrGxdik4kgxCkBi/go-log"
16 )
17
18 var log = logging.Logger("importer")
importer/importer_test.go
+1 -1
@@ -6,7 +6,7 @@ import (
6 "io/ioutil"
7 "testing"
8
9 - context "github.com/ipfs/go-ipfs/Godeps/_workspace/src/golang.org/x/net/context"
9 + context "gx/ipfs/QmZy2y8t9zQH2a1b8q2ZSLKp17ATuJoCNxxyMFG5qFExpt/go-net/context"
10 chunk "github.com/ipfs/go-ipfs/importer/chunk"
11 dag "github.com/ipfs/go-ipfs/merkledag"
12 mdtest "github.com/ipfs/go-ipfs/merkledag/test"
importer/trickle/trickle_test.go
+1 -1
@@ -9,7 +9,7 @@ import (
9 "os"
10 "testing"
11
12 - "github.com/ipfs/go-ipfs/Godeps/_workspace/src/golang.org/x/net/context"
12 + "gx/ipfs/QmZy2y8t9zQH2a1b8q2ZSLKp17ATuJoCNxxyMFG5qFExpt/go-net/context"
13 chunk "github.com/ipfs/go-ipfs/importer/chunk"
14 h "github.com/ipfs/go-ipfs/importer/helpers"
15 merkledag "github.com/ipfs/go-ipfs/merkledag"
importer/trickle/trickledag.go
+1 -1
@@ -3,7 +3,7 @@ package trickle
3 import (
4 "errors"
5
6 - context "github.com/ipfs/go-ipfs/Godeps/_workspace/src/golang.org/x/net/context"
6 + context "gx/ipfs/QmZy2y8t9zQH2a1b8q2ZSLKp17ATuJoCNxxyMFG5qFExpt/go-net/context"
7
8 h "github.com/ipfs/go-ipfs/importer/helpers"
9 dag "github.com/ipfs/go-ipfs/merkledag"
merkledag/merkledag.go
+2 -2
@@ -4,11 +4,11 @@ package merkledag
4 import (
5 "fmt"
6
7 - "github.com/ipfs/go-ipfs/Godeps/_workspace/src/golang.org/x/net/context"
7 + "gx/ipfs/QmZy2y8t9zQH2a1b8q2ZSLKp17ATuJoCNxxyMFG5qFExpt/go-net/context"
8 blocks "github.com/ipfs/go-ipfs/blocks"
9 key "github.com/ipfs/go-ipfs/blocks/key"
10 bserv "github.com/ipfs/go-ipfs/blockservice"
11 - logging "github.com/ipfs/go-ipfs/vendor/QmQg1J6vikuXF9oDvm4wpdeAUvvkVEKW1EYDw9HhTMnP2b/go-log"
11 + logging "gx/ipfs/QmaPaGNE2GqnfJjRRpQuQuFHuJn4FZvsrGxdik4kgxCkBi/go-log"
12 )
13
14 var log = logging.Logger("merkledag")
merkledag/merkledag_test.go
+1 -1
@@ -12,7 +12,7 @@ import (
12
13 ds "github.com/ipfs/go-ipfs/Godeps/_workspace/src/github.com/ipfs/go-datastore"
14 dssync "github.com/ipfs/go-ipfs/Godeps/_workspace/src/github.com/ipfs/go-datastore/sync"
15 - "github.com/ipfs/go-ipfs/Godeps/_workspace/src/golang.org/x/net/context"
15 + "gx/ipfs/QmZy2y8t9zQH2a1b8q2ZSLKp17ATuJoCNxxyMFG5qFExpt/go-net/context"
16 bstore "github.com/ipfs/go-ipfs/blocks/blockstore"
17 key "github.com/ipfs/go-ipfs/blocks/key"
18 bserv "github.com/ipfs/go-ipfs/blockservice"
merkledag/node.go
+1 -1
@@ -3,7 +3,7 @@ package merkledag
3 import (
4 "fmt"
5
6 - "github.com/ipfs/go-ipfs/Godeps/_workspace/src/golang.org/x/net/context"
6 + "gx/ipfs/QmZy2y8t9zQH2a1b8q2ZSLKp17ATuJoCNxxyMFG5qFExpt/go-net/context"
7
8 mh "github.com/ipfs/go-ipfs/Godeps/_workspace/src/github.com/jbenet/go-multihash"
9 key "github.com/ipfs/go-ipfs/blocks/key"
merkledag/traverse/traverse.go
+1 -1
@@ -4,7 +4,7 @@ package traverse
4 import (
5 "errors"
6
7 - "github.com/ipfs/go-ipfs/Godeps/_workspace/src/golang.org/x/net/context"
7 + "gx/ipfs/QmZy2y8t9zQH2a1b8q2ZSLKp17ATuJoCNxxyMFG5qFExpt/go-net/context"
8
9 mdag "github.com/ipfs/go-ipfs/merkledag"
10 )
merkledag/utils/diff.go
+1 -1
@@ -5,7 +5,7 @@ import (
5 "fmt"
6 "path"
7
8 - context "github.com/ipfs/go-ipfs/Godeps/_workspace/src/golang.org/x/net/context"
8 + context "gx/ipfs/QmZy2y8t9zQH2a1b8q2ZSLKp17ATuJoCNxxyMFG5qFExpt/go-net/context"
9 key "github.com/ipfs/go-ipfs/blocks/key"
10 dag "github.com/ipfs/go-ipfs/merkledag"
11 )
merkledag/utils/utils.go
+1 -1
@@ -5,7 +5,7 @@ import (
5
6 ds "github.com/ipfs/go-ipfs/Godeps/_workspace/src/github.com/ipfs/go-datastore"
7 syncds "github.com/ipfs/go-ipfs/Godeps/_workspace/src/github.com/ipfs/go-datastore/sync"
8 - context "github.com/ipfs/go-ipfs/Godeps/_workspace/src/golang.org/x/net/context"
8 + context "gx/ipfs/QmZy2y8t9zQH2a1b8q2ZSLKp17ATuJoCNxxyMFG5qFExpt/go-net/context"
9
10 bstore "github.com/ipfs/go-ipfs/blocks/blockstore"
11 bserv "github.com/ipfs/go-ipfs/blockservice"
merkledag/utils/utils_test.go
+1 -1
@@ -8,7 +8,7 @@ import (
8 mdtest "github.com/ipfs/go-ipfs/merkledag/test"
9 path "github.com/ipfs/go-ipfs/path"
10
11 - context "github.com/ipfs/go-ipfs/Godeps/_workspace/src/golang.org/x/net/context"
11 + context "gx/ipfs/QmZy2y8t9zQH2a1b8q2ZSLKp17ATuJoCNxxyMFG5qFExpt/go-net/context"
12 )
13
14 func TestAddLink(t *testing.T) {
metrics/bw_stats.go deleted
-89
@@ -1,89 +0,0 @@
1 -package metrics
2 -
3 -import (
4 - gm "github.com/ipfs/go-ipfs/Godeps/_workspace/src/github.com/whyrusleeping/go-metrics"
5 - "sync"
6 -
7 - peer "github.com/ipfs/go-ipfs/p2p/peer"
8 - protocol "github.com/ipfs/go-ipfs/p2p/protocol"
9 -)
10 -
11 -type Stats struct {
12 - TotalIn int64
13 - TotalOut int64
14 - RateIn float64
15 - RateOut float64
16 -}
17 -
18 -type BandwidthCounter struct {
19 - lock sync.Mutex
20 - totalIn gm.Meter
21 - totalOut gm.Meter
22 - reg gm.Registry
23 -}
24 -
25 -func NewBandwidthCounter() *BandwidthCounter {
26 - reg := gm.NewRegistry()
27 - return &BandwidthCounter{
28 - totalIn: gm.GetOrRegisterMeter("totalIn", reg),
29 - totalOut: gm.GetOrRegisterMeter("totalOut", reg),
30 - reg: reg,
31 - }
32 -}
33 -
34 -func (bwc *BandwidthCounter) LogSentMessage(size int64) {
35 - bwc.totalOut.Mark(size)
36 -}
37 -
38 -func (bwc *BandwidthCounter) LogRecvMessage(size int64) {
39 - bwc.totalIn.Mark(size)
40 -}
41 -
42 -func (bwc *BandwidthCounter) LogSentMessageStream(size int64, proto protocol.ID, p peer.ID) {
43 - meter := gm.GetOrRegisterMeter("/peer/out/"+string(p), bwc.reg)
44 - meter.Mark(size)
45 -
46 - pmeter := gm.GetOrRegisterMeter("/proto/out/"+string(proto), bwc.reg)
47 - pmeter.Mark(size)
48 -}
49 -
50 -func (bwc *BandwidthCounter) LogRecvMessageStream(size int64, proto protocol.ID, p peer.ID) {
51 - meter := gm.GetOrRegisterMeter("/peer/in/"+string(p), bwc.reg)
52 - meter.Mark(size)
53 -
54 - pmeter := gm.GetOrRegisterMeter("/proto/in/"+string(proto), bwc.reg)
55 - pmeter.Mark(size)
56 -}
57 -
58 -func (bwc *BandwidthCounter) GetBandwidthForPeer(p peer.ID) (out Stats) {
59 - inMeter := gm.GetOrRegisterMeter("/peer/in/"+string(p), bwc.reg).Snapshot()
60 - outMeter := gm.GetOrRegisterMeter("/peer/out/"+string(p), bwc.reg).Snapshot()
61 -
62 - return Stats{
63 - TotalIn: inMeter.Count(),
64 - TotalOut: outMeter.Count(),
65 - RateIn: inMeter.RateFine(),
66 - RateOut: outMeter.RateFine(),
67 - }
68 -}
69 -
70 -func (bwc *BandwidthCounter) GetBandwidthForProtocol(proto protocol.ID) (out Stats) {
71 - inMeter := gm.GetOrRegisterMeter(string("/proto/in/"+proto), bwc.reg).Snapshot()
72 - outMeter := gm.GetOrRegisterMeter(string("/proto/out/"+proto), bwc.reg).Snapshot()
73 -
74 - return Stats{
75 - TotalIn: inMeter.Count(),
76 - TotalOut: outMeter.Count(),
77 - RateIn: inMeter.RateFine(),
78 - RateOut: outMeter.RateFine(),
79 - }
80 -}
81 -
82 -func (bwc *BandwidthCounter) GetBandwidthTotals() (out Stats) {
83 - return Stats{
84 - TotalIn: bwc.totalIn.Count(),
85 - TotalOut: bwc.totalOut.Count(),
86 - RateIn: bwc.totalIn.RateFine(),
87 - RateOut: bwc.totalOut.RateFine(),
88 - }
89 -}
metrics/conn/conn.go deleted
-39
@@ -1,39 +0,0 @@
1 -package meterconn
2 -
3 -import (
4 - metrics "github.com/ipfs/go-ipfs/metrics"
5 - transport "github.com/ipfs/go-ipfs/p2p/net/transport"
6 -)
7 -
8 -type MeteredConn struct {
9 - mesRecv metrics.MeterCallback
10 - mesSent metrics.MeterCallback
11 -
12 - transport.Conn
13 -}
14 -
15 -func WrapConn(bwc metrics.Reporter, c transport.Conn) transport.Conn {
16 - return newMeteredConn(c, bwc.LogRecvMessage, bwc.LogSentMessage)
17 -}
18 -
19 -func newMeteredConn(base transport.Conn, rcb metrics.MeterCallback, scb metrics.MeterCallback) transport.Conn {
20 - return &MeteredConn{
21 - Conn: base,
22 - mesRecv: rcb,
23 - mesSent: scb,
24 - }
25 -}
26 -
27 -func (mc *MeteredConn) Read(b []byte) (int, error) {
28 - n, err := mc.Conn.Read(b)
29 -
30 - mc.mesRecv(int64(n))
31 - return n, err
32 -}
33 -
34 -func (mc *MeteredConn) Write(b []byte) (int, error) {
35 - n, err := mc.Conn.Write(b)
36 -
37 - mc.mesSent(int64(n))
38 - return n, err
39 -}
metrics/interface.go deleted
-19
@@ -1,19 +0,0 @@
1 -package metrics
2 -
3 -import (
4 - peer "github.com/ipfs/go-ipfs/p2p/peer"
5 - protocol "github.com/ipfs/go-ipfs/p2p/protocol"
6 -)
7 -
8 -type StreamMeterCallback func(int64, protocol.ID, peer.ID)
9 -type MeterCallback func(int64)
10 -
11 -type Reporter interface {
12 - LogSentMessage(int64)
13 - LogRecvMessage(int64)
14 - LogSentMessageStream(int64, protocol.ID, peer.ID)
15 - LogRecvMessageStream(int64, protocol.ID, peer.ID)
16 - GetBandwidthForPeer(peer.ID) Stats
17 - GetBandwidthForProtocol(protocol.ID) Stats
18 - GetBandwidthTotals() Stats
19 -}
metrics/stream/metered.go deleted
-52
@@ -1,52 +0,0 @@
1 -package meterstream
2 -
3 -import (
4 - metrics "github.com/ipfs/go-ipfs/metrics"
5 - inet "github.com/ipfs/go-ipfs/p2p/net"
6 - peer "github.com/ipfs/go-ipfs/p2p/peer"
7 - protocol "github.com/ipfs/go-ipfs/p2p/protocol"
8 -)
9 -
10 -type meteredStream struct {
11 - // keys for accessing metrics data
12 - protoKey protocol.ID
13 - peerKey peer.ID
14 -
15 - inet.Stream
16 -
17 - // callbacks for reporting bandwidth usage
18 - mesSent metrics.StreamMeterCallback
19 - mesRecv metrics.StreamMeterCallback
20 -}
21 -
22 -func newMeteredStream(base inet.Stream, pid protocol.ID, p peer.ID, recvCB, sentCB metrics.StreamMeterCallback) inet.Stream {
23 - return &meteredStream{
24 - Stream: base,
25 - mesSent: sentCB,
26 - mesRecv: recvCB,
27 - protoKey: pid,
28 - peerKey: p,
29 - }
30 -}
31 -
32 -func WrapStream(base inet.Stream, pid protocol.ID, bwc metrics.Reporter) inet.Stream {
33 - return newMeteredStream(base, pid, base.Conn().RemotePeer(), bwc.LogRecvMessageStream, bwc.LogSentMessageStream)
34 -}
35 -
36 -func (s *meteredStream) Read(b []byte) (int, error) {
37 - n, err := s.Stream.Read(b)
38 -
39 - // Log bytes read
40 - s.mesRecv(int64(n), s.protoKey, s.peerKey)
41 -
42 - return n, err
43 -}
44 -
45 -func (s *meteredStream) Write(b []byte) (int, error) {
46 - n, err := s.Stream.Write(b)
47 -
48 - // Log bytes written
49 - s.mesSent(int64(n), s.protoKey, s.peerKey)
50 -
51 - return n, err
52 -}
metrics/stream/metered_test.go deleted
-74
@@ -1,74 +0,0 @@
1 -package meterstream
2 -
3 -import (
4 - "io"
5 - "io/ioutil"
6 - "testing"
7 -
8 - inet "github.com/ipfs/go-ipfs/p2p/net"
9 - peer "github.com/ipfs/go-ipfs/p2p/peer"
10 - protocol "github.com/ipfs/go-ipfs/p2p/protocol"
11 - u "github.com/ipfs/go-ipfs/util"
12 -)
13 -
14 -type FakeStream struct {
15 - ReadBuf io.Reader
16 - inet.Stream
17 -}
18 -
19 -func (fs *FakeStream) Read(b []byte) (int, error) {
20 - return fs.ReadBuf.Read(b)
21 -}
22 -
23 -func (fs *FakeStream) Write(b []byte) (int, error) {
24 - return len(b), nil
25 -}
26 -
27 -func TestCallbacksWork(t *testing.T) {
28 - fake := new(FakeStream)
29 -
30 - var sent int64
31 - var recv int64
32 -
33 - sentCB := func(n int64, proto protocol.ID, p peer.ID) {
34 - sent += n
35 - }
36 -
37 - recvCB := func(n int64, proto protocol.ID, p peer.ID) {
38 - recv += n
39 - }
40 -
41 - ms := newMeteredStream(fake, protocol.ID("TEST"), peer.ID("PEER"), recvCB, sentCB)
42 -
43 - toWrite := int64(100000)
44 - toRead := int64(100000)
45 -
46 - fake.ReadBuf = io.LimitReader(u.NewTimeSeededRand(), toRead)
47 - writeData := io.LimitReader(u.NewTimeSeededRand(), toWrite)
48 -
49 - n, err := io.Copy(ms, writeData)
50 - if err != nil {
51 - t.Fatal(err)
52 - }
53 -
54 - if n != toWrite {
55 - t.Fatal("incorrect write amount")
56 - }
57 -
58 - if toWrite != sent {
59 - t.Fatal("incorrectly reported writes", toWrite, sent)
60 - }
61 -
62 - n, err = io.Copy(ioutil.Discard, ms)
63 - if err != nil {
64 - t.Fatal(err)
65 - }
66 -
67 - if n != toRead {
68 - t.Fatal("incorrect read amount")
69 - }
70 -
71 - if toRead != recv {
72 - t.Fatal("incorrectly reported reads")
73 - }
74 -}
mfs/dir.go
+1 -1
@@ -8,7 +8,7 @@ import (
8 "sync"
9 "time"
10
11 - context "github.com/ipfs/go-ipfs/Godeps/_workspace/src/golang.org/x/net/context"
11 + context "gx/ipfs/QmZy2y8t9zQH2a1b8q2ZSLKp17ATuJoCNxxyMFG5qFExpt/go-net/context"
12
13 dag "github.com/ipfs/go-ipfs/merkledag"
14 ft "github.com/ipfs/go-ipfs/unixfs"
mfs/file.go
+1 -1
@@ -7,7 +7,7 @@ import (
7 dag "github.com/ipfs/go-ipfs/merkledag"
8 mod "github.com/ipfs/go-ipfs/unixfs/mod"
9
10 - context "github.com/ipfs/go-ipfs/Godeps/_workspace/src/golang.org/x/net/context"
10 + context "gx/ipfs/QmZy2y8t9zQH2a1b8q2ZSLKp17ATuJoCNxxyMFG5qFExpt/go-net/context"
11 )
12
13 type File struct {
mfs/mfs_test.go
+1 -1
@@ -14,7 +14,7 @@ import (
14 randbo "github.com/ipfs/go-ipfs/Godeps/_workspace/src/github.com/dustin/randbo"
15 ds "github.com/ipfs/go-ipfs/Godeps/_workspace/src/github.com/ipfs/go-datastore"
16 dssync "github.com/ipfs/go-ipfs/Godeps/_workspace/src/github.com/ipfs/go-datastore/sync"
17 - "github.com/ipfs/go-ipfs/Godeps/_workspace/src/golang.org/x/net/context"
17 + "gx/ipfs/QmZy2y8t9zQH2a1b8q2ZSLKp17ATuJoCNxxyMFG5qFExpt/go-net/context"
18 "github.com/ipfs/go-ipfs/path"
19
20 bstore "github.com/ipfs/go-ipfs/blocks/blockstore"
mfs/repub_test.go
+1 -1
@@ -7,7 +7,7 @@ import (
7 key "github.com/ipfs/go-ipfs/blocks/key"
8 ci "github.com/ipfs/go-ipfs/util/testutil/ci"
9
10 - "github.com/ipfs/go-ipfs/Godeps/_workspace/src/golang.org/x/net/context"
10 + "gx/ipfs/QmZy2y8t9zQH2a1b8q2ZSLKp17ATuJoCNxxyMFG5qFExpt/go-net/context"
11 )
12
13 func TestRepublisher(t *testing.T) {
mfs/system.go
+2 -2
@@ -18,8 +18,8 @@ import (
18 dag "github.com/ipfs/go-ipfs/merkledag"
19 ft "github.com/ipfs/go-ipfs/unixfs"
20
21 - context "github.com/ipfs/go-ipfs/Godeps/_workspace/src/golang.org/x/net/context"
22 - logging "github.com/ipfs/go-ipfs/vendor/QmQg1J6vikuXF9oDvm4wpdeAUvvkVEKW1EYDw9HhTMnP2b/go-log"
21 + context "gx/ipfs/QmZy2y8t9zQH2a1b8q2ZSLKp17ATuJoCNxxyMFG5qFExpt/go-net/context"
22 + logging "gx/ipfs/QmaPaGNE2GqnfJjRRpQuQuFHuJn4FZvsrGxdik4kgxCkBi/go-log"
23 )
24
25 var ErrNotExist = errors.New("no such rootfs")
namesys/base.go
+1 -1
@@ -3,7 +3,7 @@ package namesys
3 import (
4 "strings"
5
6 - context "github.com/ipfs/go-ipfs/Godeps/_workspace/src/golang.org/x/net/context"
6 + context "gx/ipfs/QmZy2y8t9zQH2a1b8q2ZSLKp17ATuJoCNxxyMFG5qFExpt/go-net/context"
7
8 path "github.com/ipfs/go-ipfs/path"
9 )
namesys/dns.go
+1 -1
@@ -6,7 +6,7 @@ import (
6 "strings"
7
8 isd "github.com/ipfs/go-ipfs/Godeps/_workspace/src/github.com/jbenet/go-is-domain"
9 - context "github.com/ipfs/go-ipfs/Godeps/_workspace/src/golang.org/x/net/context"
9 + context "gx/ipfs/QmZy2y8t9zQH2a1b8q2ZSLKp17ATuJoCNxxyMFG5qFExpt/go-net/context"
10
11 path "github.com/ipfs/go-ipfs/path"
12 )
namesys/interface.go
+2 -2
@@ -33,9 +33,9 @@ import (
33 "errors"
34 "time"
35
36 - context "github.com/ipfs/go-ipfs/Godeps/_workspace/src/golang.org/x/net/context"
37 - ci "github.com/ipfs/go-ipfs/p2p/crypto"
36 + context "gx/ipfs/QmZy2y8t9zQH2a1b8q2ZSLKp17ATuJoCNxxyMFG5qFExpt/go-net/context"
37 path "github.com/ipfs/go-ipfs/path"
38 + ci "gx/ipfs/QmY3NAw959vbE1oJooP9HchcRdBsbxhgQsEZTRhKgvoSuC/go-libp2p/p2p/crypto"
39 )
40
41 const (
namesys/ipns_select_test.go
+1 -1
@@ -9,9 +9,9 @@ import (
9 proto "github.com/ipfs/go-ipfs/Godeps/_workspace/src/github.com/gogo/protobuf/proto"
10
11 pb "github.com/ipfs/go-ipfs/namesys/pb"
12 - ci "github.com/ipfs/go-ipfs/p2p/crypto"
12 path "github.com/ipfs/go-ipfs/path"
13 u "github.com/ipfs/go-ipfs/util"
14 + ci "gx/ipfs/QmY3NAw959vbE1oJooP9HchcRdBsbxhgQsEZTRhKgvoSuC/go-libp2p/p2p/crypto"
15 )
16
17 func shuffle(a []*pb.IpnsEntry) {
namesys/namesys.go
+2 -2
@@ -5,10 +5,10 @@ import (
5 "time"
6
7 ds "github.com/ipfs/go-ipfs/Godeps/_workspace/src/github.com/ipfs/go-datastore"
8 - context "github.com/ipfs/go-ipfs/Godeps/_workspace/src/golang.org/x/net/context"
9 - ci "github.com/ipfs/go-ipfs/p2p/crypto"
8 + context "gx/ipfs/QmZy2y8t9zQH2a1b8q2ZSLKp17ATuJoCNxxyMFG5qFExpt/go-net/context"
9 path "github.com/ipfs/go-ipfs/path"
10 routing "github.com/ipfs/go-ipfs/routing"
11 + ci "gx/ipfs/QmY3NAw959vbE1oJooP9HchcRdBsbxhgQsEZTRhKgvoSuC/go-libp2p/p2p/crypto"
12 )
13
14 // mpns (a multi-protocol NameSystem) implements generic IPFS naming.
namesys/namesys_test.go
+1 -1
@@ -4,7 +4,7 @@ import (
4 "fmt"
5 "testing"
6
7 - context "github.com/ipfs/go-ipfs/Godeps/_workspace/src/golang.org/x/net/context"
7 + context "gx/ipfs/QmZy2y8t9zQH2a1b8q2ZSLKp17ATuJoCNxxyMFG5qFExpt/go-net/context"
8
9 path "github.com/ipfs/go-ipfs/path"
10 )
namesys/proquint.go
+1 -1
@@ -4,7 +4,7 @@ import (
4 "errors"
5
6 proquint "github.com/ipfs/go-ipfs/Godeps/_workspace/src/github.com/bren2010/proquint"
7 - context "github.com/ipfs/go-ipfs/Godeps/_workspace/src/golang.org/x/net/context"
7 + context "gx/ipfs/QmZy2y8t9zQH2a1b8q2ZSLKp17ATuJoCNxxyMFG5qFExpt/go-net/context"
8 path "github.com/ipfs/go-ipfs/path"
9 )
10
namesys/publisher.go
+3 -3
@@ -8,13 +8,11 @@ import (
8
9 proto "github.com/ipfs/go-ipfs/Godeps/_workspace/src/github.com/gogo/protobuf/proto"
10 ds "github.com/ipfs/go-ipfs/Godeps/_workspace/src/github.com/ipfs/go-datastore"
11 - context "github.com/ipfs/go-ipfs/Godeps/_workspace/src/golang.org/x/net/context"
11 + context "gx/ipfs/QmZy2y8t9zQH2a1b8q2ZSLKp17ATuJoCNxxyMFG5qFExpt/go-net/context"
12
13 key "github.com/ipfs/go-ipfs/blocks/key"
14 dag "github.com/ipfs/go-ipfs/merkledag"
15 pb "github.com/ipfs/go-ipfs/namesys/pb"
16 - ci "github.com/ipfs/go-ipfs/p2p/crypto"
17 - peer "github.com/ipfs/go-ipfs/p2p/peer"
16 path "github.com/ipfs/go-ipfs/path"
17 pin "github.com/ipfs/go-ipfs/pin"
18 routing "github.com/ipfs/go-ipfs/routing"
@@ -22,6 +20,8 @@ import (
20 record "github.com/ipfs/go-ipfs/routing/record"
21 ft "github.com/ipfs/go-ipfs/unixfs"
22 u "github.com/ipfs/go-ipfs/util"
23 + ci "gx/ipfs/QmY3NAw959vbE1oJooP9HchcRdBsbxhgQsEZTRhKgvoSuC/go-libp2p/p2p/crypto"
24 + peer "gx/ipfs/QmY3NAw959vbE1oJooP9HchcRdBsbxhgQsEZTRhKgvoSuC/go-libp2p/p2p/peer"
25 )
26
27 // ErrExpiredRecord should be returned when an ipns record is
namesys/republisher/repub.go
+3 -3
@@ -8,17 +8,17 @@ import (
8 key "github.com/ipfs/go-ipfs/blocks/key"
9 namesys "github.com/ipfs/go-ipfs/namesys"
10 pb "github.com/ipfs/go-ipfs/namesys/pb"
11 - peer "github.com/ipfs/go-ipfs/p2p/peer"
11 path "github.com/ipfs/go-ipfs/path"
12 "github.com/ipfs/go-ipfs/routing"
13 dhtpb "github.com/ipfs/go-ipfs/routing/dht/pb"
14 + peer "gx/ipfs/QmY3NAw959vbE1oJooP9HchcRdBsbxhgQsEZTRhKgvoSuC/go-libp2p/p2p/peer"
15
16 proto "github.com/ipfs/go-ipfs/Godeps/_workspace/src/github.com/gogo/protobuf/proto"
17 ds "github.com/ipfs/go-ipfs/Godeps/_workspace/src/github.com/ipfs/go-datastore"
18 goprocess "github.com/ipfs/go-ipfs/Godeps/_workspace/src/github.com/jbenet/goprocess"
19 gpctx "github.com/ipfs/go-ipfs/Godeps/_workspace/src/github.com/jbenet/goprocess/context"
20 - context "github.com/ipfs/go-ipfs/Godeps/_workspace/src/golang.org/x/net/context"
21 - logging "github.com/ipfs/go-ipfs/vendor/QmQg1J6vikuXF9oDvm4wpdeAUvvkVEKW1EYDw9HhTMnP2b/go-log"
20 + context "gx/ipfs/QmZy2y8t9zQH2a1b8q2ZSLKp17ATuJoCNxxyMFG5qFExpt/go-net/context"
21 + logging "gx/ipfs/QmaPaGNE2GqnfJjRRpQuQuFHuJn4FZvsrGxdik4kgxCkBi/go-log"
22 )
23
24 var errNoEntry = errors.New("no previous entry")
namesys/republisher/repub_test.go
+3 -3
@@ -6,15 +6,15 @@ import (
6 "time"
7
8 goprocess "github.com/ipfs/go-ipfs/Godeps/_workspace/src/github.com/jbenet/goprocess"
9 - context "github.com/ipfs/go-ipfs/Godeps/_workspace/src/golang.org/x/net/context"
9 + context "gx/ipfs/QmZy2y8t9zQH2a1b8q2ZSLKp17ATuJoCNxxyMFG5qFExpt/go-net/context"
10
11 "github.com/ipfs/go-ipfs/core"
12 mock "github.com/ipfs/go-ipfs/core/mock"
13 namesys "github.com/ipfs/go-ipfs/namesys"
14 . "github.com/ipfs/go-ipfs/namesys/republisher"
15 - mocknet "github.com/ipfs/go-ipfs/p2p/net/mock"
16 - peer "github.com/ipfs/go-ipfs/p2p/peer"
15 path "github.com/ipfs/go-ipfs/path"
16 + mocknet "gx/ipfs/QmY3NAw959vbE1oJooP9HchcRdBsbxhgQsEZTRhKgvoSuC/go-libp2p/p2p/net/mock"
17 + peer "gx/ipfs/QmY3NAw959vbE1oJooP9HchcRdBsbxhgQsEZTRhKgvoSuC/go-libp2p/p2p/peer"
18 )
19
20 func TestRepublish(t *testing.T) {
namesys/resolve_test.go
+2 -2
@@ -6,13 +6,13 @@ import (
6 "time"
7
8 ds "github.com/ipfs/go-ipfs/Godeps/_workspace/src/github.com/ipfs/go-datastore"
9 - context "github.com/ipfs/go-ipfs/Godeps/_workspace/src/golang.org/x/net/context"
9 + context "gx/ipfs/QmZy2y8t9zQH2a1b8q2ZSLKp17ATuJoCNxxyMFG5qFExpt/go-net/context"
10 key "github.com/ipfs/go-ipfs/blocks/key"
11 - peer "github.com/ipfs/go-ipfs/p2p/peer"
11 path "github.com/ipfs/go-ipfs/path"
12 mockrouting "github.com/ipfs/go-ipfs/routing/mock"
13 u "github.com/ipfs/go-ipfs/util"
14 testutil "github.com/ipfs/go-ipfs/util/testutil"
15 + peer "gx/ipfs/QmY3NAw959vbE1oJooP9HchcRdBsbxhgQsEZTRhKgvoSuC/go-libp2p/p2p/peer"
16 )
17
18 func TestRoutingResolve(t *testing.T) {
namesys/routing.go
+3 -3
@@ -7,15 +7,15 @@ import (
7 proto "github.com/ipfs/go-ipfs/Godeps/_workspace/src/github.com/gogo/protobuf/proto"
8 lru "github.com/ipfs/go-ipfs/Godeps/_workspace/src/github.com/hashicorp/golang-lru"
9 mh "github.com/ipfs/go-ipfs/Godeps/_workspace/src/github.com/jbenet/go-multihash"
10 - "github.com/ipfs/go-ipfs/Godeps/_workspace/src/golang.org/x/net/context"
10 + "gx/ipfs/QmZy2y8t9zQH2a1b8q2ZSLKp17ATuJoCNxxyMFG5qFExpt/go-net/context"
11
12 key "github.com/ipfs/go-ipfs/blocks/key"
13 pb "github.com/ipfs/go-ipfs/namesys/pb"
14 - ci "github.com/ipfs/go-ipfs/p2p/crypto"
14 path "github.com/ipfs/go-ipfs/path"
15 routing "github.com/ipfs/go-ipfs/routing"
16 u "github.com/ipfs/go-ipfs/util"
18 - logging "github.com/ipfs/go-ipfs/vendor/QmQg1J6vikuXF9oDvm4wpdeAUvvkVEKW1EYDw9HhTMnP2b/go-log"
17 + logging "gx/ipfs/QmaPaGNE2GqnfJjRRpQuQuFHuJn4FZvsrGxdik4kgxCkBi/go-log"
18 + ci "gx/ipfs/QmY3NAw959vbE1oJooP9HchcRdBsbxhgQsEZTRhKgvoSuC/go-libp2p/p2p/crypto"
19 )
20
21 var log = logging.Logger("namesys")
notifications/query.go
+2 -2
@@ -3,8 +3,8 @@ package notifications
3 import (
4 "encoding/json"
5
6 - context "github.com/ipfs/go-ipfs/Godeps/_workspace/src/golang.org/x/net/context"
7 - peer "github.com/ipfs/go-ipfs/p2p/peer"
6 + context "gx/ipfs/QmZy2y8t9zQH2a1b8q2ZSLKp17ATuJoCNxxyMFG5qFExpt/go-net/context"
7 + peer "gx/ipfs/QmY3NAw959vbE1oJooP9HchcRdBsbxhgQsEZTRhKgvoSuC/go-libp2p/p2p/peer"
8 )
9
10 const RoutingQueryKey = "RoutingQueryEvent"
p2p/crypto/bench_test.go deleted
-54
@@ -1,54 +0,0 @@
1 -package crypto
2 -
3 -import "testing"
4 -
5 -func BenchmarkSign1B(b *testing.B) { RunBenchmarkSign(b, 1) }
6 -func BenchmarkSign10B(b *testing.B) { RunBenchmarkSign(b, 10) }
7 -func BenchmarkSign100B(b *testing.B) { RunBenchmarkSign(b, 100) }
8 -func BenchmarkSign1000B(b *testing.B) { RunBenchmarkSign(b, 1000) }
9 -func BenchmarkSign10000B(b *testing.B) { RunBenchmarkSign(b, 10000) }
10 -func BenchmarkSign100000B(b *testing.B) { RunBenchmarkSign(b, 100000) }
11 -
12 -func BenchmarkVerify1B(b *testing.B) { RunBenchmarkVerify(b, 1) }
13 -func BenchmarkVerify10B(b *testing.B) { RunBenchmarkVerify(b, 10) }
14 -func BenchmarkVerify100B(b *testing.B) { RunBenchmarkVerify(b, 100) }
15 -func BenchmarkVerify1000B(b *testing.B) { RunBenchmarkVerify(b, 1000) }
16 -func BenchmarkVerify10000B(b *testing.B) { RunBenchmarkVerify(b, 10000) }
17 -func BenchmarkVerify100000B(b *testing.B) { RunBenchmarkVerify(b, 100000) }
18 -
19 -func RunBenchmarkSign(b *testing.B, numBytes int) {
20 - secret, _, err := GenerateKeyPair(RSA, 1024)
21 - if err != nil {
22 - b.Fatal(err)
23 - }
24 - someData := make([]byte, numBytes)
25 - b.ResetTimer()
26 - for i := 0; i < b.N; i++ {
27 - _, err := secret.Sign(someData)
28 - if err != nil {
29 - b.Fatal(err)
30 - }
31 - }
32 -}
33 -
34 -func RunBenchmarkVerify(b *testing.B, numBytes int) {
35 - secret, public, err := GenerateKeyPair(RSA, 1024)
36 - if err != nil {
37 - b.Fatal(err)
38 - }
39 - someData := make([]byte, numBytes)
40 - signature, err := secret.Sign(someData)
41 - if err != nil {
42 - b.Fatal(err)
43 - }
44 - b.ResetTimer()
45 - for i := 0; i < b.N; i++ {
46 - valid, err := public.Verify(someData, signature)
47 - if err != nil {
48 - b.Fatal(err)
49 - }
50 - if !valid {
51 - b.Fatal("signature should be valid")
52 - }
53 - }
54 -}
p2p/crypto/key.go deleted
-316
@@ -1,316 +0,0 @@
1 -// package crypto implements various cryptographic utilities used by ipfs.
2 -// This includes a Public and Private key interface and an RSA key implementation
3 -// that satisfies it.
4 -package crypto
5 -
6 -import (
7 - "bytes"
8 - "encoding/base64"
9 - "errors"
10 - "fmt"
11 - "io"
12 -
13 - "crypto/elliptic"
14 - "crypto/hmac"
15 - "crypto/rand"
16 - "crypto/rsa"
17 - "crypto/sha1"
18 - "crypto/sha256"
19 - "crypto/sha512"
20 - "hash"
21 -
22 - proto "github.com/ipfs/go-ipfs/Godeps/_workspace/src/github.com/gogo/protobuf/proto"
23 -
24 - pb "github.com/ipfs/go-ipfs/p2p/crypto/pb"
25 - u "github.com/ipfs/go-ipfs/util"
26 - logging "github.com/ipfs/go-ipfs/vendor/QmQg1J6vikuXF9oDvm4wpdeAUvvkVEKW1EYDw9HhTMnP2b/go-log"
27 -)
28 -
29 -var log = logging.Logger("crypto")
30 -
31 -var ErrBadKeyType = errors.New("invalid or unsupported key type")
32 -
33 -const (
34 - RSA = iota
35 -)
36 -
37 -// Key represents a crypto key that can be compared to another key
38 -type Key interface {
39 - // Bytes returns a serialized, storeable representation of this key
40 - Bytes() ([]byte, error)
41 -
42 - // Hash returns the hash of this key
43 - Hash() ([]byte, error)
44 -
45 - // Equals checks whether two PubKeys are the same
46 - Equals(Key) bool
47 -}
48 -
49 -// PrivKey represents a private key that can be used to generate a public key,
50 -// sign data, and decrypt data that was encrypted with a public key
51 -type PrivKey interface {
52 - Key
53 -
54 - // Cryptographically sign the given bytes
55 - Sign([]byte) ([]byte, error)
56 -
57 - // Return a public key paired with this private key
58 - GetPublic() PubKey
59 -
60 - // Generate a secret string of bytes
61 - GenSecret() []byte
62 -
63 - Decrypt(b []byte) ([]byte, error)
64 -}
65 -
66 -type PubKey interface {
67 - Key
68 -
69 - // Verify that 'sig' is the signed hash of 'data'
70 - Verify(data []byte, sig []byte) (bool, error)
71 -
72 - // Encrypt data in a way that can be decrypted by a paired private key
73 - Encrypt(data []byte) ([]byte, error)
74 -}
75 -
76 -// Given a public key, generates the shared key.
77 -type GenSharedKey func([]byte) ([]byte, error)
78 -
79 -func GenerateKeyPair(typ, bits int) (PrivKey, PubKey, error) {
80 - return GenerateKeyPairWithReader(typ, bits, rand.Reader)
81 -}
82 -
83 -// Generates a keypair of the given type and bitsize
84 -func GenerateKeyPairWithReader(typ, bits int, src io.Reader) (PrivKey, PubKey, error) {
85 - switch typ {
86 - case RSA:
87 - priv, err := rsa.GenerateKey(src, bits)
88 - if err != nil {
89 - return nil, nil, err
90 - }
91 - pk := &priv.PublicKey
92 - return &RsaPrivateKey{sk: priv}, &RsaPublicKey{pk}, nil
93 - default:
94 - return nil, nil, ErrBadKeyType
95 - }
96 -}
97 -
98 -// Generates an ephemeral public key and returns a function that will compute
99 -// the shared secret key. Used in the identify module.
100 -//
101 -// Focuses only on ECDH now, but can be made more general in the future.
102 -func GenerateEKeyPair(curveName string) ([]byte, GenSharedKey, error) {
103 - var curve elliptic.Curve
104 -
105 - switch curveName {
106 - case "P-256":
107 - curve = elliptic.P256()
108 - case "P-384":
109 - curve = elliptic.P384()
110 - case "P-521":
111 - curve = elliptic.P521()
112 - }
113 -
114 - priv, x, y, err := elliptic.GenerateKey(curve, rand.Reader)
115 - if err != nil {
116 - return nil, nil, err
117 - }
118 -
119 - pubKey := elliptic.Marshal(curve, x, y)
120 - // log.Debug("GenerateEKeyPair %d", len(pubKey))
121 -
122 - done := func(theirPub []byte) ([]byte, error) {
123 - // Verify and unpack node's public key.
124 - x, y := elliptic.Unmarshal(curve, theirPub)
125 - if x == nil {
126 - return nil, fmt.Errorf("Malformed public key: %d %v", len(theirPub), theirPub)
127 - }
128 -
129 - if !curve.IsOnCurve(x, y) {
130 - return nil, errors.New("Invalid public key.")
131 - }
132 -
133 - // Generate shared secret.
134 - secret, _ := curve.ScalarMult(x, y, priv)
135 -
136 - return secret.Bytes(), nil
137 - }
138 -
139 - return pubKey, done, nil
140 -}
141 -
142 -type StretchedKeys struct {
143 - IV []byte
144 - MacKey []byte
145 - CipherKey []byte
146 -}
147 -
148 -// Generates a set of keys for each party by stretching the shared key.
149 -// (myIV, theirIV, myCipherKey, theirCipherKey, myMACKey, theirMACKey)
150 -func KeyStretcher(cipherType string, hashType string, secret []byte) (StretchedKeys, StretchedKeys) {
151 - var cipherKeySize int
152 - var ivSize int
153 - switch cipherType {
154 - case "AES-128":
155 - ivSize = 16
156 - cipherKeySize = 16
157 - case "AES-256":
158 - ivSize = 16
159 - cipherKeySize = 32
160 - case "Blowfish":
161 - ivSize = 8
162 - // Note: 24 arbitrarily selected, needs more thought
163 - cipherKeySize = 32
164 - }
165 -
166 - hmacKeySize := 20
167 -
168 - seed := []byte("key expansion")
169 -
170 - result := make([]byte, 2*(ivSize+cipherKeySize+hmacKeySize))
171 -
172 - var h func() hash.Hash
173 -
174 - switch hashType {
175 - case "SHA1":
176 - h = sha1.New
177 - case "SHA256":
178 - h = sha256.New
179 - case "SHA512":
180 - h = sha512.New
181 - default:
182 - panic("Unrecognized hash function, programmer error?")
183 - }
184 -
185 - m := hmac.New(h, secret)
186 - m.Write(seed)
187 -
188 - a := m.Sum(nil)
189 -
190 - j := 0
191 - for j < len(result) {
192 - m.Reset()
193 - m.Write(a)
194 - m.Write(seed)
195 - b := m.Sum(nil)
196 -
197 - todo := len(b)
198 -
199 - if j+todo > len(result) {
200 - todo = len(result) - j
201 - }
202 -
203 - copy(result[j:j+todo], b)
204 -
205 - j += todo
206 -
207 - m.Reset()
208 - m.Write(a)
209 - a = m.Sum(nil)
210 - }
211 -
212 - half := len(result) / 2
213 - r1 := result[:half]
214 - r2 := result[half:]
215 -
216 - var k1 StretchedKeys
217 - var k2 StretchedKeys
218 -
219 - k1.IV = r1[:ivSize]
220 - k1.CipherKey = r1[ivSize : ivSize+cipherKeySize]
221 - k1.MacKey = r1[ivSize+cipherKeySize:]
222 -
223 - k2.IV = r2[:ivSize]
224 - k2.CipherKey = r2[ivSize : ivSize+cipherKeySize]
225 - k2.MacKey = r2[ivSize+cipherKeySize:]
226 -
227 - return k1, k2
228 -}
229 -
230 -// UnmarshalPublicKey converts a protobuf serialized public key into its
231 -// representative object
232 -func UnmarshalPublicKey(data []byte) (PubKey, error) {
233 - pmes := new(pb.PublicKey)
234 - err := proto.Unmarshal(data, pmes)
235 - if err != nil {
236 - return nil, err
237 - }
238 -
239 - switch pmes.GetType() {
240 - case pb.KeyType_RSA:
241 - return UnmarshalRsaPublicKey(pmes.GetData())
242 - default:
243 - return nil, ErrBadKeyType
244 - }
245 -}
246 -
247 -// MarshalPublicKey converts a public key object into a protobuf serialized
248 -// public key
249 -func MarshalPublicKey(k PubKey) ([]byte, error) {
250 - b, err := MarshalRsaPublicKey(k.(*RsaPublicKey))
251 - if err != nil {
252 - return nil, err
253 - }
254 - pmes := new(pb.PublicKey)
255 - typ := pb.KeyType_RSA // for now only type.
256 - pmes.Type = &typ
257 - pmes.Data = b
258 - return proto.Marshal(pmes)
259 -}
260 -
261 -// UnmarshalPrivateKey converts a protobuf serialized private key into its
262 -// representative object
263 -func UnmarshalPrivateKey(data []byte) (PrivKey, error) {
264 - pmes := new(pb.PrivateKey)
265 - err := proto.Unmarshal(data, pmes)
266 - if err != nil {
267 - return nil, err
268 - }
269 -
270 - switch pmes.GetType() {
271 - case pb.KeyType_RSA:
272 - return UnmarshalRsaPrivateKey(pmes.GetData())
273 - default:
274 - return nil, ErrBadKeyType
275 - }
276 -}
277 -
278 -// MarshalPrivateKey converts a key object into its protobuf serialized form.
279 -func MarshalPrivateKey(k PrivKey) ([]byte, error) {
280 - b := MarshalRsaPrivateKey(k.(*RsaPrivateKey))
281 - pmes := new(pb.PrivateKey)
282 - typ := pb.KeyType_RSA // for now only type.
283 - pmes.Type = &typ
284 - pmes.Data = b
285 - return proto.Marshal(pmes)
286 -}
287 -
288 -// ConfigDecodeKey decodes from b64 (for config file), and unmarshals.
289 -func ConfigDecodeKey(b string) ([]byte, error) {
290 - return base64.StdEncoding.DecodeString(b)
291 -}
292 -
293 -// ConfigEncodeKey encodes to b64 (for config file), and marshals.
294 -func ConfigEncodeKey(b []byte) string {
295 - return base64.StdEncoding.EncodeToString(b)
296 -}
297 -
298 -// KeyEqual checks whether two
299 -func KeyEqual(k1, k2 Key) bool {
300 - if k1 == k2 {
301 - return true
302 - }
303 -
304 - b1, err1 := k1.Bytes()
305 - b2, err2 := k2.Bytes()
306 - return bytes.Equal(b1, b2) && err1 == err2
307 -}
308 -
309 -// KeyHash hashes a key.
310 -func KeyHash(k Key) ([]byte, error) {
311 - kb, err := k.Bytes()
312 - if err != nil {
313 - return nil, err
314 - }
315 - return u.Hash(kb), nil
316 -}
p2p/crypto/key_test.go deleted
-122
@@ -1,122 +0,0 @@
1 -package crypto_test
2 -
3 -import (
4 - . "github.com/ipfs/go-ipfs/p2p/crypto"
5 -
6 - "bytes"
7 - tu "github.com/ipfs/go-ipfs/util/testutil"
8 - "testing"
9 -)
10 -
11 -func TestRsaKeys(t *testing.T) {
12 - sk, pk, err := tu.RandTestKeyPair(512)
13 - if err != nil {
14 - t.Fatal(err)
15 - }
16 - testKeySignature(t, sk)
17 - testKeyEncoding(t, sk)
18 - testKeyEquals(t, sk)
19 - testKeyEquals(t, pk)
20 -}
21 -
22 -func testKeySignature(t *testing.T, sk PrivKey) {
23 - pk := sk.GetPublic()
24 -
25 - text := sk.GenSecret()
26 - sig, err := sk.Sign(text)
27 - if err != nil {
28 - t.Fatal(err)
29 - }
30 -
31 - valid, err := pk.Verify(text, sig)
32 - if err != nil {
33 - t.Fatal(err)
34 - }
35 -
36 - if !valid {
37 - t.Fatal("Invalid signature.")
38 - }
39 -}
40 -
41 -func testKeyEncoding(t *testing.T, sk PrivKey) {
42 - skbm, err := MarshalPrivateKey(sk)
43 - if err != nil {
44 - t.Fatal(err)
45 - }
46 -
47 - sk2, err := UnmarshalPrivateKey(skbm)
48 - if err != nil {
49 - t.Fatal(err)
50 - }
51 -
52 - skbm2, err := MarshalPrivateKey(sk2)
53 - if err != nil {
54 - t.Fatal(err)
55 - }
56 -
57 - if !bytes.Equal(skbm, skbm2) {
58 - t.Error("skb -> marshal -> unmarshal -> skb failed.\n", skbm, "\n", skbm2)
59 - }
60 -
61 - pk := sk.GetPublic()
62 - pkbm, err := MarshalPublicKey(pk)
63 - if err != nil {
64 - t.Fatal(err)
65 - }
66 -
67 - _, err = UnmarshalPublicKey(pkbm)
68 - if err != nil {
69 - t.Fatal(err)
70 - }
71 -
72 - pkbm2, err := MarshalPublicKey(pk)
73 - if err != nil {
74 - t.Fatal(err)
75 - }
76 -
77 - if !bytes.Equal(pkbm, pkbm2) {
78 - t.Error("skb -> marshal -> unmarshal -> skb failed.\n", pkbm, "\n", pkbm2)
79 - }
80 -}
81 -
82 -func testKeyEquals(t *testing.T, k Key) {
83 - kb, err := k.Bytes()
84 - if err != nil {
85 - t.Fatal(err)
86 - }
87 -
88 - if !KeyEqual(k, k) {
89 - t.Fatal("Key not equal to itself.")
90 - }
91 -
92 - if !KeyEqual(k, testkey(kb)) {
93 - t.Fatal("Key not equal to key with same bytes.")
94 - }
95 -
96 - sk, pk, err := tu.RandTestKeyPair(512)
97 - if err != nil {
98 - t.Fatal(err)
99 - }
100 -
101 - if KeyEqual(k, sk) {
102 - t.Fatal("Keys should not equal.")
103 - }
104 -
105 - if KeyEqual(k, pk) {
106 - t.Fatal("Keys should not equal.")
107 - }
108 -}
109 -
110 -type testkey []byte
111 -
112 -func (pk testkey) Bytes() ([]byte, error) {
113 - return pk, nil
114 -}
115 -
116 -func (pk testkey) Equals(k Key) bool {
117 - return KeyEqual(pk, k)
118 -}
119 -
120 -func (pk testkey) Hash() ([]byte, error) {
121 - return KeyHash(pk)
122 -}
p2p/crypto/pb/Makefile deleted
-10
@@ -1,10 +0,0 @@
1 -PB = $(wildcard *.proto)
2 -GO = $(PB:.proto=.pb.go)
3 -
4 -all: $(GO)
5 -
6 -%.pb.go: %.proto
7 - protoc --go_out=. --proto_path=../../../../../../:/usr/local/opt/protobuf/include:. $<
8 -
9 -clean:
10 - rm *.pb.go
p2p/crypto/pb/crypto.pb.go deleted
-104
@@ -1,104 +0,0 @@
1 -// Code generated by protoc-gen-go.
2 -// source: crypto.proto
3 -// DO NOT EDIT!
4 -
5 -/*
6 -Package crypto_pb is a generated protocol buffer package.
7 -
8 -It is generated from these files:
9 - crypto.proto
10 -
11 -It has these top-level messages:
12 - PublicKey
13 - PrivateKey
14 -*/
15 -package crypto_pb
16 -
17 -import proto "github.com/ipfs/go-ipfs/Godeps/_workspace/src/github.com/golang/protobuf/proto"
18 -import math "math"
19 -
20 -// Reference imports to suppress errors if they are not otherwise used.
21 -var _ = proto.Marshal
22 -var _ = math.Inf
23 -
24 -type KeyType int32
25 -
26 -const (
27 - KeyType_RSA KeyType = 0
28 -)
29 -
30 -var KeyType_name = map[int32]string{
31 - 0: "RSA",
32 -}
33 -var KeyType_value = map[string]int32{
34 - "RSA": 0,
35 -}
36 -
37 -func (x KeyType) Enum() *KeyType {
38 - p := new(KeyType)
39 - *p = x
40 - return p
41 -}
42 -func (x KeyType) String() string {
43 - return proto.EnumName(KeyType_name, int32(x))
44 -}
45 -func (x *KeyType) UnmarshalJSON(data []byte) error {
46 - value, err := proto.UnmarshalJSONEnum(KeyType_value, data, "KeyType")
47 - if err != nil {
48 - return err
49 - }
50 - *x = KeyType(value)
51 - return nil
52 -}
53 -
54 -type PublicKey struct {
55 - Type *KeyType `protobuf:"varint,1,req,enum=crypto.pb.KeyType" json:"Type,omitempty"`
56 - Data []byte `protobuf:"bytes,2,req" json:"Data,omitempty"`
57 - XXX_unrecognized []byte `json:"-"`
58 -}
59 -
60 -func (m *PublicKey) Reset() { *m = PublicKey{} }
61 -func (m *PublicKey) String() string { return proto.CompactTextString(m) }
62 -func (*PublicKey) ProtoMessage() {}
63 -
64 -func (m *PublicKey) GetType() KeyType {
65 - if m != nil && m.Type != nil {
66 - return *m.Type
67 - }
68 - return KeyType_RSA
69 -}
70 -
71 -func (m *PublicKey) GetData() []byte {
72 - if m != nil {
73 - return m.Data
74 - }
75 - return nil
76 -}
77 -
78 -type PrivateKey struct {
79 - Type *KeyType `protobuf:"varint,1,req,enum=crypto.pb.KeyType" json:"Type,omitempty"`
80 - Data []byte `protobuf:"bytes,2,req" json:"Data,omitempty"`
81 - XXX_unrecognized []byte `json:"-"`
82 -}
83 -
84 -func (m *PrivateKey) Reset() { *m = PrivateKey{} }
85 -func (m *PrivateKey) String() string { return proto.CompactTextString(m) }
86 -func (*PrivateKey) ProtoMessage() {}
87 -
88 -func (m *PrivateKey) GetType() KeyType {
89 - if m != nil && m.Type != nil {
90 - return *m.Type
91 - }
92 - return KeyType_RSA
93 -}
94 -
95 -func (m *PrivateKey) GetData() []byte {
96 - if m != nil {
97 - return m.Data
98 - }
99 - return nil
100 -}
101 -
102 -func init() {
103 - proto.RegisterEnum("crypto.pb.KeyType", KeyType_name, KeyType_value)
104 -}
p2p/crypto/pb/crypto.proto deleted
-15
@@ -1,15 +0,0 @@
1 -package crypto.pb;
2 -
3 -enum KeyType {
4 - RSA = 0;
5 -}
6 -
7 -message PublicKey {
8 - required KeyType Type = 1;
9 - required bytes Data = 2;
10 -}
11 -
12 -message PrivateKey {
13 - required KeyType Type = 1;
14 - required bytes Data = 2;
15 -}
p2p/crypto/rsa.go deleted
-126
@@ -1,126 +0,0 @@
1 -package crypto
2 -
3 -import (
4 - "crypto"
5 - "crypto/rand"
6 - "crypto/rsa"
7 - "crypto/sha256"
8 - "crypto/x509"
9 - "errors"
10 -
11 - proto "github.com/ipfs/go-ipfs/Godeps/_workspace/src/github.com/gogo/protobuf/proto"
12 -
13 - pb "github.com/ipfs/go-ipfs/p2p/crypto/pb"
14 -)
15 -
16 -type RsaPrivateKey struct {
17 - sk *rsa.PrivateKey
18 - pk *rsa.PublicKey
19 -}
20 -
21 -type RsaPublicKey struct {
22 - k *rsa.PublicKey
23 -}
24 -
25 -func (pk *RsaPublicKey) Verify(data, sig []byte) (bool, error) {
26 - hashed := sha256.Sum256(data)
27 - err := rsa.VerifyPKCS1v15(pk.k, crypto.SHA256, hashed[:], sig)
28 - if err != nil {
29 - return false, err
30 - }
31 - return true, nil
32 -}
33 -
34 -func (pk *RsaPublicKey) Bytes() ([]byte, error) {
35 - b, err := x509.MarshalPKIXPublicKey(pk.k)
36 - if err != nil {
37 - return nil, err
38 - }
39 -
40 - pbmes := new(pb.PublicKey)
41 - typ := pb.KeyType_RSA
42 - pbmes.Type = &typ
43 - pbmes.Data = b
44 - return proto.Marshal(pbmes)
45 -}
46 -
47 -func (pk *RsaPublicKey) Encrypt(b []byte) ([]byte, error) {
48 - return rsa.EncryptPKCS1v15(rand.Reader, pk.k, b)
49 -}
50 -
51 -// Equals checks whether this key is equal to another
52 -func (pk *RsaPublicKey) Equals(k Key) bool {
53 - return KeyEqual(pk, k)
54 -}
55 -
56 -func (pk *RsaPublicKey) Hash() ([]byte, error) {
57 - return KeyHash(pk)
58 -}
59 -
60 -func (sk *RsaPrivateKey) GenSecret() []byte {
61 - buf := make([]byte, 16)
62 - rand.Read(buf)
63 - return buf
64 -}
65 -
66 -func (sk *RsaPrivateKey) Sign(message []byte) ([]byte, error) {
67 - hashed := sha256.Sum256(message)
68 - return rsa.SignPKCS1v15(rand.Reader, sk.sk, crypto.SHA256, hashed[:])
69 -}
70 -
71 -func (sk *RsaPrivateKey) GetPublic() PubKey {
72 - if sk.pk == nil {
73 - sk.pk = &sk.sk.PublicKey
74 - }
75 - return &RsaPublicKey{sk.pk}
76 -}
77 -
78 -func (sk *RsaPrivateKey) Decrypt(b []byte) ([]byte, error) {
79 - return rsa.DecryptPKCS1v15(rand.Reader, sk.sk, b)
80 -}
81 -
82 -func (sk *RsaPrivateKey) Bytes() ([]byte, error) {
83 - b := x509.MarshalPKCS1PrivateKey(sk.sk)
84 - pbmes := new(pb.PrivateKey)
85 - typ := pb.KeyType_RSA
86 - pbmes.Type = &typ
87 - pbmes.Data = b
88 - return proto.Marshal(pbmes)
89 -}
90 -
91 -// Equals checks whether this key is equal to another
92 -func (sk *RsaPrivateKey) Equals(k Key) bool {
93 - return KeyEqual(sk, k)
94 -}
95 -
96 -func (sk *RsaPrivateKey) Hash() ([]byte, error) {
97 - return KeyHash(sk)
98 -}
99 -
100 -func UnmarshalRsaPrivateKey(b []byte) (*RsaPrivateKey, error) {
101 - sk, err := x509.ParsePKCS1PrivateKey(b)
102 - if err != nil {
103 - return nil, err
104 - }
105 - return &RsaPrivateKey{sk: sk}, nil
106 -}
107 -
108 -func MarshalRsaPrivateKey(k *RsaPrivateKey) []byte {
109 - return x509.MarshalPKCS1PrivateKey(k.sk)
110 -}
111 -
112 -func UnmarshalRsaPublicKey(b []byte) (*RsaPublicKey, error) {
113 - pub, err := x509.ParsePKIXPublicKey(b)
114 - if err != nil {
115 - return nil, err
116 - }
117 - pk, ok := pub.(*rsa.PublicKey)
118 - if !ok {
119 - return nil, errors.New("Not actually an rsa public key.")
120 - }
121 - return &RsaPublicKey{pk}, nil
122 -}
123 -
124 -func MarshalRsaPublicKey(k *RsaPublicKey) ([]byte, error) {
125 - return x509.MarshalPKIXPublicKey(k.k)
126 -}
p2p/crypto/secio/al.go deleted
-115
@@ -1,115 +0,0 @@
1 -package secio
2 -
3 -import (
4 - "errors"
5 - "fmt"
6 - "strings"
7 -
8 - "crypto/aes"
9 - "crypto/cipher"
10 - "crypto/hmac"
11 - "crypto/sha1"
12 - "crypto/sha256"
13 - "crypto/sha512"
14 - "hash"
15 -
16 - bfish "github.com/ipfs/go-ipfs/Godeps/_workspace/src/golang.org/x/crypto/blowfish"
17 - ci "github.com/ipfs/go-ipfs/p2p/crypto"
18 -)
19 -
20 -// List of supported ECDH curves
21 -var SupportedExchanges = "P-256,P-384,P-521"
22 -
23 -// List of supported Ciphers
24 -var SupportedCiphers = "AES-256,AES-128,Blowfish"
25 -
26 -// List of supported Hashes
27 -var SupportedHashes = "SHA256,SHA512"
28 -
29 -type HMAC struct {
30 - hash.Hash
31 - size int
32 -}
33 -
34 -// encParams represent encryption parameters
35 -type encParams struct {
36 - // keys
37 - permanentPubKey ci.PubKey
38 - ephemeralPubKey []byte
39 - keys ci.StretchedKeys
40 -
41 - // selections
42 - curveT string
43 - cipherT string
44 - hashT string
45 -
46 - // cipher + mac
47 - cipher cipher.Stream
48 - mac HMAC
49 -}
50 -
51 -func (e *encParams) makeMacAndCipher() error {
52 - m, err := newMac(e.hashT, e.keys.MacKey)
53 - if err != nil {
54 - return err
55 - }
56 -
57 - bc, err := newBlockCipher(e.cipherT, e.keys.CipherKey)
58 - if err != nil {
59 - return err
60 - }
61 -
62 - e.cipher = cipher.NewCTR(bc, e.keys.IV)
63 - e.mac = m
64 - return nil
65 -}
66 -
67 -func newMac(hashType string, key []byte) (HMAC, error) {
68 - switch hashType {
69 - case "SHA1":
70 - return HMAC{hmac.New(sha1.New, key), sha1.Size}, nil
71 - case "SHA512":
72 - return HMAC{hmac.New(sha512.New, key), sha512.Size}, nil
73 - case "SHA256":
74 - return HMAC{hmac.New(sha256.New, key), sha256.Size}, nil
75 - default:
76 - return HMAC{}, fmt.Errorf("Unrecognized hash type: %s", hashType)
77 - }
78 -}
79 -
80 -func newBlockCipher(cipherT string, key []byte) (cipher.Block, error) {
81 - switch cipherT {
82 - case "AES-128", "AES-256":
83 - return aes.NewCipher(key)
84 - case "Blowfish":
85 - return bfish.NewCipher(key)
86 - default:
87 - return nil, fmt.Errorf("Unrecognized cipher type: %s", cipherT)
88 - }
89 -}
90 -
91 -// Determines which algorithm to use. Note: f(a, b) = f(b, a)
92 -func selectBest(order int, p1, p2 string) (string, error) {
93 - var f, s []string
94 - switch {
95 - case order < 0:
96 - f = strings.Split(p2, ",")
97 - s = strings.Split(p1, ",")
98 - case order > 0:
99 - f = strings.Split(p1, ",")
100 - s = strings.Split(p2, ",")
101 - default: // Exact same preferences.
102 - p := strings.Split(p1, ",")
103 - return p[0], nil
104 - }
105 -
106 - for _, fc := range f {
107 - for _, sc := range s {
108 - if fc == sc {
109 - return fc, nil
110 - }
111 - }
112 - }
113 -
114 - return "", errors.New("No algorithms in common!")
115 -}
p2p/crypto/secio/interface.go deleted
-126
@@ -1,126 +0,0 @@
1 -// package secio handles establishing secure communication between two peers.
2 -package secio
3 -
4 -import (
5 - "io"
6 -
7 - ci "github.com/ipfs/go-ipfs/p2p/crypto"
8 -
9 - msgio "github.com/ipfs/go-ipfs/Godeps/_workspace/src/github.com/jbenet/go-msgio"
10 - context "github.com/ipfs/go-ipfs/Godeps/_workspace/src/golang.org/x/net/context"
11 - peer "github.com/ipfs/go-ipfs/p2p/peer"
12 -)
13 -
14 -// SessionGenerator constructs secure communication sessions for a peer.
15 -type SessionGenerator struct {
16 - LocalID peer.ID
17 - PrivateKey ci.PrivKey
18 -}
19 -
20 -// NewSession takes an insecure io.ReadWriter, sets up a TLS-like
21 -// handshake with the other side, and returns a secure session.
22 -// The handshake isn't run until the connection is read or written to.
23 -// See the source for the protocol details and security implementation.
24 -// The provided Context is only needed for the duration of this function.
25 -func (sg *SessionGenerator) NewSession(ctx context.Context, insecure io.ReadWriteCloser) (Session, error) {
26 - return newSecureSession(ctx, sg.LocalID, sg.PrivateKey, insecure)
27 -}
28 -
29 -type Session interface {
30 - // ReadWriter returns the encrypted communication channel
31 - ReadWriter() msgio.ReadWriteCloser
32 -
33 - // LocalPeer retrieves the local peer.
34 - LocalPeer() peer.ID
35 -
36 - // LocalPrivateKey retrieves the local private key
37 - LocalPrivateKey() ci.PrivKey
38 -
39 - // RemotePeer retrieves the remote peer.
40 - RemotePeer() peer.ID
41 -
42 - // RemotePublicKey retrieves the remote's public key
43 - // which was received during the handshake.
44 - RemotePublicKey() ci.PubKey
45 -
46 - // Close closes the secure session
47 - Close() error
48 -}
49 -
50 -// SecureReadWriter returns the encrypted communication channel
51 -func (s *secureSession) ReadWriter() msgio.ReadWriteCloser {
52 - if err := s.Handshake(); err != nil {
53 - return &closedRW{err}
54 - }
55 - return s.secure
56 -}
57 -
58 -// LocalPeer retrieves the local peer.
59 -func (s *secureSession) LocalPeer() peer.ID {
60 - return s.localPeer
61 -}
62 -
63 -// LocalPrivateKey retrieves the local peer's PrivateKey
64 -func (s *secureSession) LocalPrivateKey() ci.PrivKey {
65 - return s.localKey
66 -}
67 -
68 -// RemotePeer retrieves the remote peer.
69 -func (s *secureSession) RemotePeer() peer.ID {
70 - if err := s.Handshake(); err != nil {
71 - return ""
72 - }
73 - return s.remotePeer
74 -}
75 -
76 -// RemotePeer retrieves the remote peer.
77 -func (s *secureSession) RemotePublicKey() ci.PubKey {
78 - if err := s.Handshake(); err != nil {
79 - return nil
80 - }
81 - return s.remote.permanentPubKey
82 -}
83 -
84 -// Close closes the secure session
85 -func (s *secureSession) Close() error {
86 - s.cancel()
87 - s.handshakeMu.Lock()
88 - defer s.handshakeMu.Unlock()
89 - if s.secure == nil {
90 - return s.insecure.Close() // hadn't secured yet.
91 - }
92 - return s.secure.Close()
93 -}
94 -
95 -// closedRW implements a stub msgio interface that's already
96 -// closed and errored.
97 -type closedRW struct {
98 - err error
99 -}
100 -
101 -func (c *closedRW) Read(buf []byte) (int, error) {
102 - return 0, c.err
103 -}
104 -
105 -func (c *closedRW) Write(buf []byte) (int, error) {
106 - return 0, c.err
107 -}
108 -
109 -func (c *closedRW) NextMsgLen() (int, error) {
110 - return 0, c.err
111 -}
112 -
113 -func (c *closedRW) ReadMsg() ([]byte, error) {
114 - return nil, c.err
115 -}
116 -
117 -func (c *closedRW) WriteMsg(buf []byte) error {
118 - return c.err
119 -}
120 -
121 -func (c *closedRW) Close() error {
122 - return c.err
123 -}
124 -
125 -func (c *closedRW) ReleaseMsg(m []byte) {
126 -}
p2p/crypto/secio/io_test.go deleted
-1
@@ -1 +0,0 @@
1 -package secio
p2p/crypto/secio/pb/Makefile deleted
-10
@@ -1,10 +0,0 @@
1 -PB = $(wildcard *.proto)
2 -GO = $(PB:.proto=.pb.go)
3 -
4 -all: $(GO)
5 -
6 -%.pb.go: %.proto
7 - protoc --gogo_out=. --proto_path=../../../../../../:/usr/local/opt/protobuf/include:. $<
8 -
9 -clean:
10 - rm *.pb.go
p2p/crypto/secio/pb/spipe.pb.go deleted
-97
@@ -1,97 +0,0 @@
1 -// Code generated by protoc-gen-gogo.
2 -// source: spipe.proto
3 -// DO NOT EDIT!
4 -
5 -/*
6 -Package spipe_pb is a generated protocol buffer package.
7 -
8 -It is generated from these files:
9 - spipe.proto
10 -
11 -It has these top-level messages:
12 - Propose
13 - Exchange
14 -*/
15 -package spipe_pb
16 -
17 -import proto "github.com/ipfs/go-ipfs/Godeps/_workspace/src/github.com/gogo/protobuf/proto"
18 -import math "math"
19 -
20 -// Reference imports to suppress errors if they are not otherwise used.
21 -var _ = proto.Marshal
22 -var _ = math.Inf
23 -
24 -type Propose struct {
25 - Rand []byte `protobuf:"bytes,1,opt,name=rand" json:"rand,omitempty"`
26 - Pubkey []byte `protobuf:"bytes,2,opt,name=pubkey" json:"pubkey,omitempty"`
27 - Exchanges *string `protobuf:"bytes,3,opt,name=exchanges" json:"exchanges,omitempty"`
28 - Ciphers *string `protobuf:"bytes,4,opt,name=ciphers" json:"ciphers,omitempty"`
29 - Hashes *string `protobuf:"bytes,5,opt,name=hashes" json:"hashes,omitempty"`
30 - XXX_unrecognized []byte `json:"-"`
31 -}
32 -
33 -func (m *Propose) Reset() { *m = Propose{} }
34 -func (m *Propose) String() string { return proto.CompactTextString(m) }
35 -func (*Propose) ProtoMessage() {}
36 -
37 -func (m *Propose) GetRand() []byte {
38 - if m != nil {
39 - return m.Rand
40 - }
41 - return nil
42 -}
43 -
44 -func (m *Propose) GetPubkey() []byte {
45 - if m != nil {
46 - return m.Pubkey
47 - }
48 - return nil
49 -}
50 -
51 -func (m *Propose) GetExchanges() string {
52 - if m != nil && m.Exchanges != nil {
53 - return *m.Exchanges
54 - }
55 - return ""
56 -}
57 -
58 -func (m *Propose) GetCiphers() string {
59 - if m != nil && m.Ciphers != nil {
60 - return *m.Ciphers
61 - }
62 - return ""
63 -}
64 -
65 -func (m *Propose) GetHashes() string {
66 - if m != nil && m.Hashes != nil {
67 - return *m.Hashes
68 - }
69 - return ""
70 -}
71 -
72 -type Exchange struct {
73 - Epubkey []byte `protobuf:"bytes,1,opt,name=epubkey" json:"epubkey,omitempty"`
74 - Signature []byte `protobuf:"bytes,2,opt,name=signature" json:"signature,omitempty"`
75 - XXX_unrecognized []byte `json:"-"`
76 -}
77 -
78 -func (m *Exchange) Reset() { *m = Exchange{} }
79 -func (m *Exchange) String() string { return proto.CompactTextString(m) }
80 -func (*Exchange) ProtoMessage() {}
81 -
82 -func (m *Exchange) GetEpubkey() []byte {
83 - if m != nil {
84 - return m.Epubkey
85 - }
86 - return nil
87 -}
88 -
89 -func (m *Exchange) GetSignature() []byte {
90 - if m != nil {
91 - return m.Signature
92 - }
93 - return nil
94 -}
95 -
96 -func init() {
97 -}
p2p/crypto/secio/pb/spipe.proto deleted
-14
@@ -1,14 +0,0 @@
1 -package spipe.pb;
2 -
3 -message Propose {
4 - optional bytes rand = 1;
5 - optional bytes pubkey = 2;
6 - optional string exchanges = 3;
7 - optional string ciphers = 4;
8 - optional string hashes = 5;
9 -}
10 -
11 -message Exchange {
12 - optional bytes epubkey = 1;
13 - optional bytes signature = 2;
14 -}
p2p/crypto/secio/protocol.go deleted
-341
@@ -1,341 +0,0 @@
1 -package secio
2 -
3 -import (
4 - "bytes"
5 - "crypto/rand"
6 - "errors"
7 - "fmt"
8 - "io"
9 - "sync"
10 - "time"
11 -
12 - msgio "github.com/ipfs/go-ipfs/Godeps/_workspace/src/github.com/jbenet/go-msgio"
13 - context "github.com/ipfs/go-ipfs/Godeps/_workspace/src/golang.org/x/net/context"
14 - ci "github.com/ipfs/go-ipfs/p2p/crypto"
15 - pb "github.com/ipfs/go-ipfs/p2p/crypto/secio/pb"
16 - peer "github.com/ipfs/go-ipfs/p2p/peer"
17 - u "github.com/ipfs/go-ipfs/util"
18 - logging "github.com/ipfs/go-ipfs/vendor/QmQg1J6vikuXF9oDvm4wpdeAUvvkVEKW1EYDw9HhTMnP2b/go-log"
19 -)
20 -
21 -var log = logging.Logger("secio")
22 -
23 -// ErrUnsupportedKeyType is returned when a private key cast/type switch fails.
24 -var ErrUnsupportedKeyType = errors.New("unsupported key type")
25 -
26 -// ErrClosed signals the closing of a connection.
27 -var ErrClosed = errors.New("connection closed")
28 -
29 -// ErrEcho is returned when we're attempting to handshake with the same keys and nonces.
30 -var ErrEcho = errors.New("same keys and nonces. one side talking to self.")
31 -
32 -// HandshakeTimeout governs how long the handshake will be allowed to take place for.
33 -// Making this number large means there could be many bogus connections waiting to
34 -// timeout in flight. Typical handshakes take ~3RTTs, so it should be completed within
35 -// seconds across a typical planet in the solar system.
36 -var HandshakeTimeout = time.Second * 30
37 -
38 -// nonceSize is the size of our nonces (in bytes)
39 -const nonceSize = 16
40 -
41 -// secureSession encapsulates all the parameters needed for encrypting
42 -// and decrypting traffic from an insecure channel.
43 -type secureSession struct {
44 - ctx context.Context
45 - cancel context.CancelFunc
46 -
47 - secure msgio.ReadWriteCloser
48 - insecure io.ReadWriteCloser
49 - insecureM msgio.ReadWriter
50 -
51 - localKey ci.PrivKey
52 - localPeer peer.ID
53 - remotePeer peer.ID
54 -
55 - local encParams
56 - remote encParams
57 -
58 - sharedSecret []byte
59 -
60 - handshakeMu sync.Mutex // guards handshakeDone + handshakeErr
61 - handshakeDone bool
62 - handshakeErr error
63 -}
64 -
65 -func (s *secureSession) Loggable() map[string]interface{} {
66 - m := make(map[string]interface{})
67 - m["localPeer"] = s.localPeer.Pretty()
68 - m["remotePeer"] = s.remotePeer.Pretty()
69 - m["established"] = (s.secure != nil)
70 - return m
71 -}
72 -
73 -func newSecureSession(ctx context.Context, local peer.ID, key ci.PrivKey, insecure io.ReadWriteCloser) (*secureSession, error) {
74 - s := &secureSession{localPeer: local, localKey: key}
75 - s.ctx, s.cancel = context.WithCancel(ctx)
76 -
77 - switch {
78 - case s.localPeer == "":
79 - return nil, errors.New("no local id provided")
80 - case s.localKey == nil:
81 - return nil, errors.New("no local private key provided")
82 - case !s.localPeer.MatchesPrivateKey(s.localKey):
83 - return nil, fmt.Errorf("peer.ID does not match PrivateKey")
84 - case insecure == nil:
85 - return nil, fmt.Errorf("insecure ReadWriter is nil")
86 - }
87 -
88 - s.ctx = ctx
89 - s.insecure = insecure
90 - s.insecureM = msgio.NewReadWriter(insecure)
91 - return s, nil
92 -}
93 -
94 -func (s *secureSession) Handshake() error {
95 - s.handshakeMu.Lock()
96 - defer s.handshakeMu.Unlock()
97 -
98 - if s.handshakeErr != nil {
99 - return s.handshakeErr
100 - }
101 -
102 - if !s.handshakeDone {
103 - s.handshakeErr = s.runHandshake()
104 - s.handshakeDone = true
105 - }
106 - return s.handshakeErr
107 -}
108 -
109 -// runHandshake performs initial communication over insecure channel to share
110 -// keys, IDs, and initiate communication, assigning all necessary params.
111 -// requires the duplex channel to be a msgio.ReadWriter (for framed messaging)
112 -func (s *secureSession) runHandshake() error {
113 - ctx, cancel := context.WithTimeout(s.ctx, HandshakeTimeout) // remove
114 - defer cancel()
115 -
116 - // =============================================================================
117 - // step 1. Propose -- propose cipher suite + send pubkeys + nonce
118 -
119 - // Generate and send Hello packet.
120 - // Hello = (rand, PublicKey, Supported)
121 - nonceOut := make([]byte, nonceSize)
122 - _, err := rand.Read(nonceOut)
123 - if err != nil {
124 - return err
125 - }
126 -
127 - defer log.EventBegin(ctx, "secureHandshake", s).Done()
128 -
129 - s.local.permanentPubKey = s.localKey.GetPublic()
130 - myPubKeyBytes, err := s.local.permanentPubKey.Bytes()
131 - if err != nil {
132 - return err
133 - }
134 -
135 - proposeOut := new(pb.Propose)
136 - proposeOut.Rand = nonceOut
137 - proposeOut.Pubkey = myPubKeyBytes
138 - proposeOut.Exchanges = &SupportedExchanges
139 - proposeOut.Ciphers = &SupportedCiphers
140 - proposeOut.Hashes = &SupportedHashes
141 -
142 - // log.Debugf("1.0 Propose: nonce:%s exchanges:%s ciphers:%s hashes:%s",
143 - // nonceOut, SupportedExchanges, SupportedCiphers, SupportedHashes)
144 -
145 - // Send Propose packet (respects ctx)
146 - proposeOutBytes, err := writeMsgCtx(ctx, s.insecureM, proposeOut)
147 - if err != nil {
148 - return err
149 - }
150 -
151 - // Receive + Parse their Propose packet and generate an Exchange packet.
152 - proposeIn := new(pb.Propose)
153 - proposeInBytes, err := readMsgCtx(ctx, s.insecureM, proposeIn)
154 - if err != nil {
155 - return err
156 - }
157 -
158 - // log.Debugf("1.0.1 Propose recv: nonce:%s exchanges:%s ciphers:%s hashes:%s",
159 - // proposeIn.GetRand(), proposeIn.GetExchanges(), proposeIn.GetCiphers(), proposeIn.GetHashes())
160 -
161 - // =============================================================================
162 - // step 1.1 Identify -- get identity from their key
163 -
164 - // get remote identity
165 - s.remote.permanentPubKey, err = ci.UnmarshalPublicKey(proposeIn.GetPubkey())
166 - if err != nil {
167 - return err
168 - }
169 -
170 - // get peer id
171 - s.remotePeer, err = peer.IDFromPublicKey(s.remote.permanentPubKey)
172 - if err != nil {
173 - return err
174 - }
175 -
176 - log.Debugf("1.1 Identify: %s Remote Peer Identified as %s", s.localPeer, s.remotePeer)
177 -
178 - // =============================================================================
179 - // step 1.2 Selection -- select/agree on best encryption parameters
180 -
181 - // to determine order, use cmp(H(remote_pubkey||local_rand), H(local_pubkey||remote_rand)).
182 - oh1 := u.Hash(append(proposeIn.GetPubkey(), nonceOut...))
183 - oh2 := u.Hash(append(myPubKeyBytes, proposeIn.GetRand()...))
184 - order := bytes.Compare(oh1, oh2)
185 - if order == 0 {
186 - return ErrEcho // talking to self (same socket. must be reuseport + dialing self)
187 - }
188 -
189 - s.local.curveT, err = selectBest(order, SupportedExchanges, proposeIn.GetExchanges())
190 - if err != nil {
191 - return err
192 - }
193 -
194 - s.local.cipherT, err = selectBest(order, SupportedCiphers, proposeIn.GetCiphers())
195 - if err != nil {
196 - return err
197 - }
198 -
199 - s.local.hashT, err = selectBest(order, SupportedHashes, proposeIn.GetHashes())
200 - if err != nil {
201 - return err
202 - }
203 -
204 - // we use the same params for both directions (must choose same curve)
205 - // WARNING: if they dont SelectBest the same way, this won't work...
206 - s.remote.curveT = s.local.curveT
207 - s.remote.cipherT = s.local.cipherT
208 - s.remote.hashT = s.local.hashT
209 -
210 - // log.Debugf("1.2 selection: exchange:%s cipher:%s hash:%s",
211 - // s.local.curveT, s.local.cipherT, s.local.hashT)
212 -
213 - // =============================================================================
214 - // step 2. Exchange -- exchange (signed) ephemeral keys. verify signatures.
215 -
216 - // Generate EphemeralPubKey
217 - var genSharedKey ci.GenSharedKey
218 - s.local.ephemeralPubKey, genSharedKey, err = ci.GenerateEKeyPair(s.local.curveT)
219 -
220 - // Gather corpus to sign.
221 - selectionOut := new(bytes.Buffer)
222 - selectionOut.Write(proposeOutBytes)
223 - selectionOut.Write(proposeInBytes)
224 - selectionOut.Write(s.local.ephemeralPubKey)
225 - selectionOutBytes := selectionOut.Bytes()
226 -
227 - // log.Debugf("2.0 exchange: %v", selectionOutBytes)
228 - exchangeOut := new(pb.Exchange)
229 - exchangeOut.Epubkey = s.local.ephemeralPubKey
230 - exchangeOut.Signature, err = s.localKey.Sign(selectionOutBytes)
231 - if err != nil {
232 - return err
233 - }
234 -
235 - // Send Propose packet (respects ctx)
236 - if _, err := writeMsgCtx(ctx, s.insecureM, exchangeOut); err != nil {
237 - return err
238 - }
239 -
240 - // Receive + Parse their Exchange packet.
241 - exchangeIn := new(pb.Exchange)
242 - if _, err := readMsgCtx(ctx, s.insecureM, exchangeIn); err != nil {
243 - return err
244 - }
245 -
246 - // =============================================================================
247 - // step 2.1. Verify -- verify their exchange packet is good.
248 -
249 - // get their ephemeral pub key
250 - s.remote.ephemeralPubKey = exchangeIn.GetEpubkey()
251 -
252 - selectionIn := new(bytes.Buffer)
253 - selectionIn.Write(proposeInBytes)
254 - selectionIn.Write(proposeOutBytes)
255 - selectionIn.Write(s.remote.ephemeralPubKey)
256 - selectionInBytes := selectionIn.Bytes()
257 - // log.Debugf("2.0.1 exchange recv: %v", selectionInBytes)
258 -
259 - // u.POut("Remote Peer Identified as %s\n", s.remote)
260 - sigOK, err := s.remote.permanentPubKey.Verify(selectionInBytes, exchangeIn.GetSignature())
261 - if err != nil {
262 - // log.Error("2.1 Verify: failed: %s", err)
263 - return err
264 - }
265 -
266 - if !sigOK {
267 - err := errors.New("Bad signature!")
268 - // log.Error("2.1 Verify: failed: %s", err)
269 - return err
270 - }
271 - // log.Debugf("2.1 Verify: signature verified.")
272 -
273 - // =============================================================================
274 - // step 2.2. Keys -- generate keys for mac + encryption
275 -
276 - // OK! seems like we're good to go.
277 - s.sharedSecret, err = genSharedKey(exchangeIn.GetEpubkey())
278 - if err != nil {
279 - return err
280 - }
281 -
282 - // generate two sets of keys (stretching)
283 - k1, k2 := ci.KeyStretcher(s.local.cipherT, s.local.hashT, s.sharedSecret)
284 -
285 - // use random nonces to decide order.
286 - switch {
287 - case order > 0:
288 - // just break
289 - case order < 0:
290 - k1, k2 = k2, k1 // swap
291 - default:
292 - // we should've bailed before this. but if not, bail here.
293 - return ErrEcho
294 - }
295 - s.local.keys = k1
296 - s.remote.keys = k2
297 -
298 - // log.Debug("2.2 keys:\n\tshared: %v\n\tk1: %v\n\tk2: %v",
299 - // s.sharedSecret, s.local.keys, s.remote.keys)
300 -
301 - // =============================================================================
302 - // step 2.3. MAC + Cipher -- prepare MAC + cipher
303 -
304 - if err := s.local.makeMacAndCipher(); err != nil {
305 - return err
306 - }
307 -
308 - if err := s.remote.makeMacAndCipher(); err != nil {
309 - return err
310 - }
311 -
312 - // log.Debug("2.3 mac + cipher.")
313 -
314 - // =============================================================================
315 - // step 3. Finish -- send expected message to verify encryption works (send local nonce)
316 -
317 - // setup ETM ReadWriter
318 - w := NewETMWriter(s.insecure, s.local.cipher, s.local.mac)
319 - r := NewETMReader(s.insecure, s.remote.cipher, s.remote.mac)
320 - s.secure = msgio.Combine(w, r).(msgio.ReadWriteCloser)
321 -
322 - // log.Debug("3.0 finish. sending: %v", proposeIn.GetRand())
323 - // send their Nonce.
324 - if _, err := s.secure.Write(proposeIn.GetRand()); err != nil {
325 - return fmt.Errorf("Failed to write Finish nonce: %s", err)
326 - }
327 -
328 - // read our Nonce
329 - nonceOut2 := make([]byte, len(nonceOut))
330 - if _, err := io.ReadFull(s.secure, nonceOut2); err != nil {
331 - return fmt.Errorf("Failed to read Finish nonce: %s", err)
332 - }
333 -
334 - // log.Debug("3.0 finish.\n\texpect: %v\n\tactual: %v", nonceOut, nonceOut2)
335 - if !bytes.Equal(nonceOut, nonceOut2) {
336 - return fmt.Errorf("Failed to read our encrypted nonce: %s != %s", nonceOut2, nonceOut)
337 - }
338 -
339 - // Whew! ok, that's all folks.
340 - return nil
341 -}
p2p/crypto/secio/rw.go deleted
-273
@@ -1,273 +0,0 @@
1 -package secio
2 -
3 -import (
4 - "crypto/cipher"
5 - "errors"
6 - "fmt"
7 - "io"
8 - "sync"
9 -
10 - "crypto/hmac"
11 -
12 - proto "github.com/ipfs/go-ipfs/Godeps/_workspace/src/github.com/gogo/protobuf/proto"
13 - msgio "github.com/ipfs/go-ipfs/Godeps/_workspace/src/github.com/jbenet/go-msgio"
14 - mpool "github.com/ipfs/go-ipfs/Godeps/_workspace/src/github.com/jbenet/go-msgio/mpool"
15 - context "github.com/ipfs/go-ipfs/Godeps/_workspace/src/golang.org/x/net/context"
16 -)
17 -
18 -const MaxMsgSize = 8 * 1024 * 1024
19 -
20 -var ErrMaxMessageSize = errors.New("attempted to read message larger than max size")
21 -
22 -// ErrMACInvalid signals that a MAC verification failed
23 -var ErrMACInvalid = errors.New("MAC verification failed")
24 -
25 -// bufPool is a ByteSlicePool for messages. we need buffers because (sadly)
26 -// we cannot encrypt in place-- the user needs their buffer back.
27 -var bufPool = mpool.ByteSlicePool
28 -
29 -type etmWriter struct {
30 - // params
31 - pool mpool.Pool // for the buffers with encrypted data
32 - msg msgio.WriteCloser // msgio for knowing where boundaries lie
33 - str cipher.Stream // the stream cipher to encrypt with
34 - mac HMAC // the mac to authenticate data with
35 -
36 - sync.Mutex
37 -}
38 -
39 -// NewETMWriter Encrypt-Then-MAC
40 -func NewETMWriter(w io.Writer, s cipher.Stream, mac HMAC) msgio.WriteCloser {
41 - return &etmWriter{msg: msgio.NewWriter(w), str: s, mac: mac, pool: bufPool}
42 -}
43 -
44 -// Write writes passed in buffer as a single message.
45 -func (w *etmWriter) Write(b []byte) (int, error) {
46 - if err := w.WriteMsg(b); err != nil {
47 - return 0, err
48 - }
49 - return len(b), nil
50 -}
51 -
52 -// WriteMsg writes the msg in the passed in buffer.
53 -func (w *etmWriter) WriteMsg(b []byte) error {
54 - w.Lock()
55 - defer w.Unlock()
56 -
57 - // encrypt.
58 - data := w.pool.Get(uint32(len(b))).([]byte)
59 - data = data[:len(b)] // the pool's buffer may be larger
60 - w.str.XORKeyStream(data, b)
61 -
62 - // log.Debugf("ENC plaintext (%d): %s %v", len(b), b, b)
63 - // log.Debugf("ENC ciphertext (%d): %s %v", len(data), data, data)
64 -
65 - // then, mac.
66 - if _, err := w.mac.Write(data); err != nil {
67 - return err
68 - }
69 -
70 - // Sum appends.
71 - data = w.mac.Sum(data)
72 - w.mac.Reset()
73 - // it's sad to append here. our buffers are -- hopefully -- coming from
74 - // a shared buffer pool, so the append may not actually cause allocation
75 - // one can only hope. i guess we'll see.
76 -
77 - return w.msg.WriteMsg(data)
78 -}
79 -
80 -func (w *etmWriter) Close() error {
81 - return w.msg.Close()
82 -}
83 -
84 -type etmReader struct {
85 - msgio.Reader
86 - io.Closer
87 -
88 - // buffer
89 - buf []byte
90 -
91 - // params
92 - msg msgio.ReadCloser // msgio for knowing where boundaries lie
93 - str cipher.Stream // the stream cipher to encrypt with
94 - mac HMAC // the mac to authenticate data with
95 -
96 - sync.Mutex
97 -}
98 -
99 -// NewETMReader Encrypt-Then-MAC
100 -func NewETMReader(r io.Reader, s cipher.Stream, mac HMAC) msgio.ReadCloser {
101 - return &etmReader{msg: msgio.NewReader(r), str: s, mac: mac}
102 -}
103 -
104 -func (r *etmReader) NextMsgLen() (int, error) {
105 - return r.msg.NextMsgLen()
106 -}
107 -
108 -func (r *etmReader) drainBuf(buf []byte) int {
109 - if r.buf == nil {
110 - return 0
111 - }
112 -
113 - n := copy(buf, r.buf)
114 - r.buf = r.buf[n:]
115 - return n
116 -}
117 -
118 -func (r *etmReader) Read(buf []byte) (int, error) {
119 - r.Lock()
120 - defer r.Unlock()
121 -
122 - // first, check if we have anything in the buffer
123 - copied := r.drainBuf(buf)
124 - buf = buf[copied:]
125 - if copied > 0 {
126 - return copied, nil
127 - // return here to avoid complicating the rest...
128 - // user can call io.ReadFull.
129 - }
130 -
131 - // check the buffer has enough space for the next msg
132 - fullLen, err := r.msg.NextMsgLen()
133 - if err != nil {
134 - return 0, err
135 - }
136 -
137 - if fullLen > MaxMsgSize {
138 - return 0, ErrMaxMessageSize
139 - }
140 -
141 - buf2 := buf
142 - changed := false
143 - // if not enough space, allocate a new buffer.
144 - if cap(buf) < fullLen {
145 - buf2 = make([]byte, fullLen)
146 - changed = true
147 - }
148 - buf2 = buf2[:fullLen]
149 -
150 - n, err := io.ReadFull(r.msg, buf2)
151 - if err != nil {
152 - return n, err
153 - }
154 -
155 - m, err := r.macCheckThenDecrypt(buf2)
156 - if err != nil {
157 - return 0, err
158 - }
159 - buf2 = buf2[:m]
160 - if !changed {
161 - return m, nil
162 - }
163 -
164 - n = copy(buf, buf2)
165 - if len(buf2) > len(buf) {
166 - r.buf = buf2[len(buf):] // had some left over? save it.
167 - }
168 - return n, nil
169 -}
170 -
171 -func (r *etmReader) ReadMsg() ([]byte, error) {
172 - r.Lock()
173 - defer r.Unlock()
174 -
175 - msg, err := r.msg.ReadMsg()
176 - if err != nil {
177 - return nil, err
178 - }
179 -
180 - n, err := r.macCheckThenDecrypt(msg)
181 - if err != nil {
182 - return nil, err
183 - }
184 - return msg[:n], nil
185 -}
186 -
187 -func (r *etmReader) macCheckThenDecrypt(m []byte) (int, error) {
188 - l := len(m)
189 - if l < r.mac.size {
190 - return 0, fmt.Errorf("buffer (%d) shorter than MAC size (%d)", l, r.mac.size)
191 - }
192 -
193 - mark := l - r.mac.size
194 - data := m[:mark]
195 - macd := m[mark:]
196 -
197 - r.mac.Write(data)
198 - expected := r.mac.Sum(nil)
199 - r.mac.Reset()
200 -
201 - // check mac. if failed, return error.
202 - if !hmac.Equal(macd, expected) {
203 - log.Debug("MAC Invalid:", expected, "!=", macd)
204 - return 0, ErrMACInvalid
205 - }
206 -
207 - // ok seems good. decrypt. (can decrypt in place, yay!)
208 - // log.Debugf("DEC ciphertext (%d): %s %v", len(data), data, data)
209 - r.str.XORKeyStream(data, data)
210 - // log.Debugf("DEC plaintext (%d): %s %v", len(data), data, data)
211 -
212 - return mark, nil
213 -}
214 -
215 -func (w *etmReader) Close() error {
216 - return w.msg.Close()
217 -}
218 -
219 -// ReleaseMsg signals a buffer can be reused.
220 -func (r *etmReader) ReleaseMsg(b []byte) {
221 - r.msg.ReleaseMsg(b)
222 -}
223 -
224 -// writeMsgCtx is used by the
225 -func writeMsgCtx(ctx context.Context, w msgio.Writer, msg proto.Message) ([]byte, error) {
226 - enc, err := proto.Marshal(msg)
227 - if err != nil {
228 - return nil, err
229 - }
230 -
231 - // write in a goroutine so we can exit when our context is cancelled.
232 - done := make(chan error)
233 - go func(m []byte) {
234 - err := w.WriteMsg(m)
235 - select {
236 - case done <- err:
237 - case <-ctx.Done():
238 - }
239 - }(enc)
240 -
241 - select {
242 - case <-ctx.Done():
243 - return nil, ctx.Err()
244 - case e := <-done:
245 - return enc, e
246 - }
247 -}
248 -
249 -func readMsgCtx(ctx context.Context, r msgio.Reader, p proto.Message) ([]byte, error) {
250 - var msg []byte
251 -
252 - // read in a goroutine so we can exit when our context is cancelled.
253 - done := make(chan error)
254 - go func() {
255 - var err error
256 - msg, err = r.ReadMsg()
257 - select {
258 - case done <- err:
259 - case <-ctx.Done():
260 - }
261 - }()
262 -
263 - select {
264 - case <-ctx.Done():
265 - return nil, ctx.Err()
266 - case e := <-done:
267 - if e != nil {
268 - return nil, e
269 - }
270 - }
271 -
272 - return msg, proto.Unmarshal(msg, p)
273 -}
p2p/discovery/mdns.go deleted
-189
@@ -1,189 +0,0 @@
1 -package discovery
2 -
3 -import (
4 - "errors"
5 - "io"
6 - "io/ioutil"
7 - golog "log"
8 - "net"
9 - "sync"
10 - "time"
11 -
12 - "github.com/ipfs/go-ipfs/Godeps/_workspace/src/github.com/cryptix/mdns"
13 - ma "github.com/ipfs/go-ipfs/Godeps/_workspace/src/github.com/jbenet/go-multiaddr"
14 - manet "github.com/ipfs/go-ipfs/Godeps/_workspace/src/github.com/jbenet/go-multiaddr-net"
15 -
16 - "github.com/ipfs/go-ipfs/p2p/host"
17 - "github.com/ipfs/go-ipfs/p2p/peer"
18 - logging "github.com/ipfs/go-ipfs/vendor/QmQg1J6vikuXF9oDvm4wpdeAUvvkVEKW1EYDw9HhTMnP2b/go-log"
19 -)
20 -
21 -var log = logging.Logger("mdns")
22 -
23 -const ServiceTag = "discovery.ipfs.io"
24 -
25 -type Service interface {
26 - io.Closer
27 - RegisterNotifee(Notifee)
28 - UnregisterNotifee(Notifee)
29 -}
30 -
31 -type Notifee interface {
32 - HandlePeerFound(peer.PeerInfo)
33 -}
34 -
35 -type mdnsService struct {
36 - server *mdns.Server
37 - service *mdns.MDNSService
38 - host host.Host
39 -
40 - lk sync.Mutex
41 - notifees []Notifee
42 - interval time.Duration
43 -}
44 -
45 -func getDialableListenAddrs(ph host.Host) ([]*net.TCPAddr, error) {
46 - var out []*net.TCPAddr
47 - for _, addr := range ph.Addrs() {
48 - na, err := manet.ToNetAddr(addr)
49 - if err != nil {
50 - continue
51 - }
52 - tcp, ok := na.(*net.TCPAddr)
53 - if ok {
54 - out = append(out, tcp)
55 - }
56 - }
57 - if len(out) == 0 {
58 - return nil, errors.New("failed to find good external addr from peerhost")
59 - }
60 - return out, nil
61 -}
62 -
63 -func NewMdnsService(peerhost host.Host, interval time.Duration) (Service, error) {
64 -
65 - // TODO: dont let mdns use logging...
66 - golog.SetOutput(ioutil.Discard)
67 -
68 - var ipaddrs []net.IP
69 - port := 4001
70 -
71 - addrs, err := getDialableListenAddrs(peerhost)
72 - if err != nil {
73 - log.Warning(err)
74 - } else {
75 - port = addrs[0].Port
76 - for _, a := range addrs {
77 - ipaddrs = append(ipaddrs, a.IP)
78 - }
79 - }
80 -
81 - myid := peerhost.ID().Pretty()
82 -
83 - info := []string{myid}
84 - service, err := mdns.NewMDNSService(myid, ServiceTag, "", "", port, ipaddrs, info)
85 - if err != nil {
86 - return nil, err
87 - }
88 -
89 - // Create the mDNS server, defer shutdown
90 - server, err := mdns.NewServer(&mdns.Config{Zone: service})
91 - if err != nil {
92 - return nil, err
93 - }
94 -
95 - s := &mdnsService{
96 - server: server,
97 - service: service,
98 - host: peerhost,
99 - interval: interval,
100 - }
101 -
102 - go s.pollForEntries()
103 -
104 - return s, nil
105 -}
106 -
107 -func (m *mdnsService) Close() error {
108 - return m.server.Shutdown()
109 -}
110 -
111 -func (m *mdnsService) pollForEntries() {
112 - ticker := time.NewTicker(m.interval)
113 - for {
114 - select {
115 - case <-ticker.C:
116 - entriesCh := make(chan *mdns.ServiceEntry, 16)
117 - go func() {
118 - for entry := range entriesCh {
119 - m.handleEntry(entry)
120 - }
121 - }()
122 -
123 - qp := mdns.QueryParam{}
124 - qp.Domain = "local"
125 - qp.Entries = entriesCh
126 - qp.Service = ServiceTag
127 - qp.Timeout = time.Second * 5
128 -
129 - err := mdns.Query(&qp)
130 - if err != nil {
131 - log.Error("mdns lookup error: ", err)
132 - }
133 - close(entriesCh)
134 - }
135 - }
136 -}
137 -
138 -func (m *mdnsService) handleEntry(e *mdns.ServiceEntry) {
139 - mpeer, err := peer.IDB58Decode(e.Info)
140 - if err != nil {
141 - log.Warning("Error parsing peer ID from mdns entry: ", err)
142 - return
143 - }
144 -
145 - if mpeer == m.host.ID() {
146 - return
147 - }
148 -
149 - maddr, err := manet.FromNetAddr(&net.TCPAddr{
150 - IP: e.AddrV4,
151 - Port: e.Port,
152 - })
153 - if err != nil {
154 - log.Warning("Error parsing multiaddr from mdns entry: ", err)
155 - return
156 - }
157 -
158 - pi := peer.PeerInfo{
159 - ID: mpeer,
160 - Addrs: []ma.Multiaddr{maddr},
161 - }
162 -
163 - m.lk.Lock()
164 - for _, n := range m.notifees {
165 - n.HandlePeerFound(pi)
166 - }
167 - m.lk.Unlock()
168 -}
169 -
170 -func (m *mdnsService) RegisterNotifee(n Notifee) {
171 - m.lk.Lock()
172 - m.notifees = append(m.notifees, n)
173 - m.lk.Unlock()
174 -}
175 -
176 -func (m *mdnsService) UnregisterNotifee(n Notifee) {
177 - m.lk.Lock()
178 - found := -1
179 - for i, notif := range m.notifees {
180 - if notif == n {
181 - found = i
182 - break
183 - }
184 - }
185 - if found != -1 {
186 - m.notifees = append(m.notifees[:found], m.notifees[found+1:]...)
187 - }
188 - m.lk.Unlock()
189 -}
p2p/host/basic/basic_host.go deleted
-268
@@ -1,268 +0,0 @@
1 -package basichost
2 -
3 -import (
4 - "io"
5 -
6 - ma "github.com/ipfs/go-ipfs/Godeps/_workspace/src/github.com/jbenet/go-multiaddr"
7 - goprocess "github.com/ipfs/go-ipfs/Godeps/_workspace/src/github.com/jbenet/goprocess"
8 - context "github.com/ipfs/go-ipfs/Godeps/_workspace/src/golang.org/x/net/context"
9 - metrics "github.com/ipfs/go-ipfs/metrics"
10 - mstream "github.com/ipfs/go-ipfs/metrics/stream"
11 - logging "github.com/ipfs/go-ipfs/vendor/QmQg1J6vikuXF9oDvm4wpdeAUvvkVEKW1EYDw9HhTMnP2b/go-log"
12 -
13 - inet "github.com/ipfs/go-ipfs/p2p/net"
14 - peer "github.com/ipfs/go-ipfs/p2p/peer"
15 - protocol "github.com/ipfs/go-ipfs/p2p/protocol"
16 - identify "github.com/ipfs/go-ipfs/p2p/protocol/identify"
17 - relay "github.com/ipfs/go-ipfs/p2p/protocol/relay"
18 -
19 - msmux "github.com/ipfs/go-ipfs/Godeps/_workspace/src/github.com/whyrusleeping/go-multistream"
20 -)
21 -
22 -var log = logging.Logger("p2p/host/basic")
23 -
24 -// Option is a type used to pass in options to the host.
25 -type Option int
26 -
27 -const (
28 - // NATPortMap makes the host attempt to open port-mapping in NAT devices
29 - // for all its listeners. Pass in this option in the constructor to
30 - // asynchronously a) find a gateway, b) open port mappings, c) republish
31 - // port mappings periodically. The NATed addresses are included in the
32 - // Host's Addrs() list.
33 - NATPortMap Option = iota
34 -)
35 -
36 -// BasicHost is the basic implementation of the host.Host interface. This
37 -// particular host implementation:
38 -// * uses a protocol muxer to mux per-protocol streams
39 -// * uses an identity service to send + receive node information
40 -// * uses a relay service to allow hosts to relay conns for each other
41 -// * uses a nat service to establish NAT port mappings
42 -type BasicHost struct {
43 - network inet.Network
44 - mux *msmux.MultistreamMuxer
45 - ids *identify.IDService
46 - relay *relay.RelayService
47 - natmgr *natManager
48 -
49 - proc goprocess.Process
50 -
51 - bwc metrics.Reporter
52 -}
53 -
54 -// New constructs and sets up a new *BasicHost with given Network
55 -func New(net inet.Network, opts ...interface{}) *BasicHost {
56 - h := &BasicHost{
57 - network: net,
58 - mux: msmux.NewMultistreamMuxer(),
59 - bwc: metrics.NewBandwidthCounter(),
60 - }
61 -
62 - h.proc = goprocess.WithTeardown(func() error {
63 - if h.natmgr != nil {
64 - h.natmgr.Close()
65 - }
66 -
67 - return h.Network().Close()
68 - })
69 -
70 - // setup host services
71 - h.ids = identify.NewIDService(h)
72 -
73 - muxh := h.Mux().Handle
74 - handle := func(s inet.Stream) {
75 - muxh(s)
76 - }
77 - h.relay = relay.NewRelayService(h, handle)
78 -
79 - for _, o := range opts {
80 - switch o := o.(type) {
81 - case Option:
82 - switch o {
83 - case NATPortMap:
84 - h.natmgr = newNatManager(h)
85 - }
86 - case metrics.Reporter:
87 - h.bwc = o
88 - }
89 - }
90 -
91 - net.SetConnHandler(h.newConnHandler)
92 - net.SetStreamHandler(h.newStreamHandler)
93 -
94 - return h
95 -}
96 -
97 -// newConnHandler is the remote-opened conn handler for inet.Network
98 -func (h *BasicHost) newConnHandler(c inet.Conn) {
99 - h.ids.IdentifyConn(c)
100 -}
101 -
102 -// newStreamHandler is the remote-opened stream handler for inet.Network
103 -// TODO: this feels a bit wonky
104 -func (h *BasicHost) newStreamHandler(s inet.Stream) {
105 - protoID, handle, err := h.Mux().Negotiate(s)
106 - if err != nil {
107 - if err == io.EOF {
108 - log.Debugf("protocol EOF: %s", s.Conn().RemotePeer())
109 - } else {
110 - log.Warning("protocol mux failed: %s", err)
111 - }
112 - return
113 - }
114 -
115 - logStream := mstream.WrapStream(s, protocol.ID(protoID), h.bwc)
116 -
117 - go handle(logStream)
118 -}
119 -
120 -// ID returns the (local) peer.ID associated with this Host
121 -func (h *BasicHost) ID() peer.ID {
122 - return h.Network().LocalPeer()
123 -}
124 -
125 -// Peerstore returns the Host's repository of Peer Addresses and Keys.
126 -func (h *BasicHost) Peerstore() peer.Peerstore {
127 - return h.Network().Peerstore()
128 -}
129 -
130 -// Network returns the Network interface of the Host
131 -func (h *BasicHost) Network() inet.Network {
132 - return h.network
133 -}
134 -
135 -// Mux returns the Mux multiplexing incoming streams to protocol handlers
136 -func (h *BasicHost) Mux() *msmux.MultistreamMuxer {
137 - return h.mux
138 -}
139 -
140 -// IDService returns
141 -func (h *BasicHost) IDService() *identify.IDService {
142 - return h.ids
143 -}
144 -
145 -// SetStreamHandler sets the protocol handler on the Host's Mux.
146 -// This is equivalent to:
147 -// host.Mux().SetHandler(proto, handler)
148 -// (Threadsafe)
149 -func (h *BasicHost) SetStreamHandler(pid protocol.ID, handler inet.StreamHandler) {
150 - h.Mux().AddHandler(string(pid), func(rwc io.ReadWriteCloser) error {
151 - handler(rwc.(inet.Stream))
152 - return nil
153 - })
154 -}
155 -
156 -// RemoveStreamHandler returns ..
157 -func (h *BasicHost) RemoveStreamHandler(pid protocol.ID) {
158 - h.Mux().RemoveHandler(string(pid))
159 -}
160 -
161 -// NewStream opens a new stream to given peer p, and writes a p2p/protocol
162 -// header with given protocol.ID. If there is no connection to p, attempts
163 -// to create one. If ProtocolID is "", writes no header.
164 -// (Threadsafe)
165 -func (h *BasicHost) NewStream(pid protocol.ID, p peer.ID) (inet.Stream, error) {
166 - s, err := h.Network().NewStream(p)
167 - if err != nil {
168 - return nil, err
169 - }
170 -
171 - logStream := mstream.WrapStream(s, pid, h.bwc)
172 -
173 - lzcon := msmux.NewMSSelect(logStream, string(pid))
174 - return &streamWrapper{
175 - Stream: logStream,
176 - rw: lzcon,
177 - }, nil
178 -}
179 -
180 -// Connect ensures there is a connection between this host and the peer with
181 -// given peer.ID. Connect will absorb the addresses in pi into its internal
182 -// peerstore. If there is not an active connection, Connect will issue a
183 -// h.Network.Dial, and block until a connection is open, or an error is
184 -// returned. // TODO: Relay + NAT.
185 -func (h *BasicHost) Connect(ctx context.Context, pi peer.PeerInfo) error {
186 -
187 - // absorb addresses into peerstore
188 - h.Peerstore().AddAddrs(pi.ID, pi.Addrs, peer.TempAddrTTL)
189 -
190 - cs := h.Network().ConnsToPeer(pi.ID)
191 - if len(cs) > 0 {
192 - return nil
193 - }
194 -
195 - return h.dialPeer(ctx, pi.ID)
196 -}
197 -
198 -// dialPeer opens a connection to peer, and makes sure to identify
199 -// the connection once it has been opened.
200 -func (h *BasicHost) dialPeer(ctx context.Context, p peer.ID) error {
201 - log.Debugf("host %s dialing %s", h.ID, p)
202 - c, err := h.Network().DialPeer(ctx, p)
203 - if err != nil {
204 - return err
205 - }
206 -
207 - // identify the connection before returning.
208 - done := make(chan struct{})
209 - go func() {
210 - h.ids.IdentifyConn(c)
211 - close(done)
212 - }()
213 -
214 - // respect don contexteone
215 - select {
216 - case <-done:
217 - case <-ctx.Done():
218 - return ctx.Err()
219 - }
220 -
221 - log.Debugf("host %s finished dialing %s", h.ID, p)
222 - return nil
223 -}
224 -
225 -// Addrs returns all the addresses of BasicHost at this moment in time.
226 -// It's ok to not include addresses if they're not available to be used now.
227 -func (h *BasicHost) Addrs() []ma.Multiaddr {
228 - addrs, err := h.Network().InterfaceListenAddresses()
229 - if err != nil {
230 - log.Debug("error retrieving network interface addrs")
231 - }
232 -
233 - if h.ids != nil { // add external observed addresses
234 - addrs = append(addrs, h.ids.OwnObservedAddrs()...)
235 - }
236 -
237 - if h.natmgr != nil { // natmgr is nil if we do not use nat option.
238 - nat := h.natmgr.NAT()
239 - if nat != nil { // nat is nil if not ready, or no nat is available.
240 - addrs = append(addrs, nat.ExternalAddrs()...)
241 - }
242 - }
243 -
244 - return addrs
245 -}
246 -
247 -// Close shuts down the Host's services (network, etc).
248 -func (h *BasicHost) Close() error {
249 - return h.proc.Close()
250 -}
251 -
252 -// GetBandwidthReporter exposes the Host's bandiwth metrics reporter
253 -func (h *BasicHost) GetBandwidthReporter() metrics.Reporter {
254 - return h.bwc
255 -}
256 -
257 -type streamWrapper struct {
258 - inet.Stream
259 - rw io.ReadWriter
260 -}
261 -
262 -func (s *streamWrapper) Read(b []byte) (int, error) {
263 - return s.rw.Read(b)
264 -}
265 -
266 -func (s *streamWrapper) Write(b []byte) (int, error) {
267 - return s.rw.Write(b)
268 -}
p2p/host/basic/basic_host_test.go deleted
-63
@@ -1,63 +0,0 @@
1 -package basichost_test
2 -
3 -import (
4 - "bytes"
5 - "io"
6 - "testing"
7 -
8 - inet "github.com/ipfs/go-ipfs/p2p/net"
9 - protocol "github.com/ipfs/go-ipfs/p2p/protocol"
10 - testutil "github.com/ipfs/go-ipfs/p2p/test/util"
11 -
12 - context "github.com/ipfs/go-ipfs/Godeps/_workspace/src/golang.org/x/net/context"
13 -)
14 -
15 -func TestHostSimple(t *testing.T) {
16 -
17 - ctx := context.Background()
18 - h1 := testutil.GenHostSwarm(t, ctx)
19 - h2 := testutil.GenHostSwarm(t, ctx)
20 - defer h1.Close()
21 - defer h2.Close()
22 -
23 - h2pi := h2.Peerstore().PeerInfo(h2.ID())
24 - if err := h1.Connect(ctx, h2pi); err != nil {
25 - t.Fatal(err)
26 - }
27 -
28 - piper, pipew := io.Pipe()
29 - h2.SetStreamHandler(protocol.TestingID, func(s inet.Stream) {
30 - defer s.Close()
31 - w := io.MultiWriter(s, pipew)
32 - io.Copy(w, s) // mirror everything
33 - })
34 -
35 - s, err := h1.NewStream(protocol.TestingID, h2pi.ID)
36 - if err != nil {
37 - t.Fatal(err)
38 - }
39 -
40 - // write to the stream
41 - buf1 := []byte("abcdefghijkl")
42 - if _, err := s.Write(buf1); err != nil {
43 - t.Fatal(err)
44 - }
45 -
46 - // get it from the stream (echoed)
47 - buf2 := make([]byte, len(buf1))
48 - if _, err := io.ReadFull(s, buf2); err != nil {
49 - t.Fatal(err)
50 - }
51 - if !bytes.Equal(buf1, buf2) {
52 - t.Fatal("buf1 != buf2 -- %x != %x", buf1, buf2)
53 - }
54 -
55 - // get it from the pipe (tee)
56 - buf3 := make([]byte, len(buf1))
57 - if _, err := io.ReadFull(piper, buf3); err != nil {
58 - t.Fatal(err)
59 - }
60 - if !bytes.Equal(buf1, buf3) {
61 - t.Fatal("buf1 != buf3 -- %x != %x", buf1, buf3)
62 - }
63 -}
p2p/host/basic/natmgr.go deleted
-228
@@ -1,228 +0,0 @@
1 -package basichost
2 -
3 -import (
4 - "sync"
5 -
6 - ma "github.com/ipfs/go-ipfs/Godeps/_workspace/src/github.com/jbenet/go-multiaddr"
7 - goprocess "github.com/ipfs/go-ipfs/Godeps/_workspace/src/github.com/jbenet/goprocess"
8 - context "github.com/ipfs/go-ipfs/Godeps/_workspace/src/golang.org/x/net/context"
9 -
10 - inat "github.com/ipfs/go-ipfs/p2p/nat"
11 - inet "github.com/ipfs/go-ipfs/p2p/net"
12 - lgbl "github.com/ipfs/go-ipfs/util/eventlog/loggables"
13 -)
14 -
15 -// natManager takes care of adding + removing port mappings to the nat.
16 -// Initialized with the host if it has a NATPortMap option enabled.
17 -// natManager receives signals from the network, and check on nat mappings:
18 -// * natManager listens to the network and adds or closes port mappings
19 -// as the network signals Listen() or ListenClose().
20 -// * closing the natManager closes the nat and its mappings.
21 -type natManager struct {
22 - host *BasicHost
23 - natmu sync.RWMutex // guards nat (ready could obviate this mutex, but safety first.)
24 - nat *inat.NAT
25 -
26 - ready chan struct{} // closed once the nat is ready to process port mappings
27 - proc goprocess.Process // natManager has a process + children. can be closed.
28 -}
29 -
30 -func newNatManager(host *BasicHost) *natManager {
31 - nmgr := &natManager{
32 - host: host,
33 - ready: make(chan struct{}),
34 - proc: goprocess.WithParent(host.proc),
35 - }
36 -
37 - // teardown
38 - nmgr.proc = goprocess.WithTeardown(func() error {
39 - // on closing, unregister from network notifications.
40 - host.Network().StopNotify((*nmgrNetNotifiee)(nmgr))
41 - return nil
42 - })
43 -
44 - // host is our parent. close when host closes.
45 - host.proc.AddChild(nmgr.proc)
46 -
47 - // discover the nat.
48 - nmgr.discoverNAT()
49 - return nmgr
50 -}
51 -
52 -// Close closes the natManager, closing the underlying nat
53 -// and unregistering from network events.
54 -func (nmgr *natManager) Close() error {
55 - return nmgr.proc.Close()
56 -}
57 -
58 -// Ready returns a channel which will be closed when the NAT has been found
59 -// and is ready to be used, or the search process is done.
60 -func (nmgr *natManager) Ready() <-chan struct{} {
61 - return nmgr.ready
62 -}
63 -
64 -func (nmgr *natManager) discoverNAT() {
65 -
66 - nmgr.proc.Go(func(worker goprocess.Process) {
67 - // inat.DiscoverNAT blocks until the nat is found or a timeout
68 - // is reached. we unfortunately cannot specify timeouts-- the
69 - // library we're using just blocks.
70 - //
71 - // Note: on early shutdown, there may be a case where we're trying
72 - // to close before DiscoverNAT() returns. Since we cant cancel it
73 - // (library) we can choose to (1) drop the result and return early,
74 - // or (2) wait until it times out to exit. For now we choose (2),
75 - // to avoid leaking resources in a non-obvious way. the only case
76 - // this affects is when the daemon is being started up and _immediately_
77 - // asked to close. other services are also starting up, so ok to wait.
78 - discoverdone := make(chan struct{})
79 - var nat *inat.NAT
80 - go func() {
81 - defer close(discoverdone)
82 - nat = inat.DiscoverNAT()
83 - }()
84 -
85 - // by this point -- after finding the NAT -- we may have already
86 - // be closing. if so, just exit.
87 - select {
88 - case <-worker.Closing():
89 - return
90 - case <-discoverdone:
91 - if nat == nil { // no nat, or failed to get it.
92 - return
93 - }
94 - }
95 -
96 - // wire up the nat to close when nmgr closes.
97 - // nmgr.proc is our parent, and waiting for us.
98 - nmgr.proc.AddChild(nat.Process())
99 -
100 - // set the nat.
101 - nmgr.natmu.Lock()
102 - nmgr.nat = nat
103 - nmgr.natmu.Unlock()
104 -
105 - // signal that we're ready to process nat mappings:
106 - close(nmgr.ready)
107 -
108 - // sign natManager up for network notifications
109 - // we need to sign up here to avoid missing some notifs
110 - // before the NAT has been found.
111 - nmgr.host.Network().Notify((*nmgrNetNotifiee)(nmgr))
112 -
113 - // if any interfaces were brought up while we were setting up
114 - // the nat, now is the time to setup port mappings for them.
115 - // we release ready, then grab them to avoid losing any. adding
116 - // a port mapping is idempotent, so its ok to add the same twice.
117 - addrs := nmgr.host.Network().ListenAddresses()
118 - for _, addr := range addrs {
119 - // we do it async because it's slow and we may want to close beforehand
120 - go addPortMapping(nmgr, addr)
121 - }
122 - })
123 -}
124 -
125 -// NAT returns the natManager's nat object. this may be nil, if
126 -// (a) the search process is still ongoing, or (b) the search process
127 -// found no nat. Clients must check whether the return value is nil.
128 -func (nmgr *natManager) NAT() *inat.NAT {
129 - nmgr.natmu.Lock()
130 - defer nmgr.natmu.Unlock()
131 - return nmgr.nat
132 -}
133 -
134 -func addPortMapping(nmgr *natManager, intaddr ma.Multiaddr) {
135 - nat := nmgr.NAT()
136 - if nat == nil {
137 - panic("natManager addPortMapping called without a nat.")
138 - }
139 -
140 - // first, check if the port mapping already exists.
141 - for _, mapping := range nat.Mappings() {
142 - if mapping.InternalAddr().Equal(intaddr) {
143 - return // it exists! return.
144 - }
145 - }
146 -
147 - ctx := context.TODO()
148 - lm := make(lgbl.DeferredMap)
149 - lm["internalAddr"] = func() interface{} { return intaddr.String() }
150 -
151 - defer log.EventBegin(ctx, "natMgrAddPortMappingWait", lm).Done()
152 -
153 - select {
154 - case <-nmgr.proc.Closing():
155 - lm["outcome"] = "cancelled"
156 - return // no use.
157 - case <-nmgr.ready: // wait until it's ready.
158 - }
159 -
160 - // actually start the port map (sub-event because waiting may take a while)
161 - defer log.EventBegin(ctx, "natMgrAddPortMapping", lm).Done()
162 -
163 - // get the nat
164 - m, err := nat.NewMapping(intaddr)
165 - if err != nil {
166 - lm["outcome"] = "failure"
167 - lm["error"] = err
168 - return
169 - }
170 -
171 - extaddr, err := m.ExternalAddr()
172 - if err != nil {
173 - lm["outcome"] = "failure"
174 - lm["error"] = err
175 - return
176 - }
177 -
178 - lm["outcome"] = "success"
179 - lm["externalAddr"] = func() interface{} { return extaddr.String() }
180 - log.Infof("established nat port mapping: %s <--> %s", intaddr, extaddr)
181 -}
182 -
183 -func rmPortMapping(nmgr *natManager, intaddr ma.Multiaddr) {
184 - nat := nmgr.NAT()
185 - if nat == nil {
186 - panic("natManager rmPortMapping called without a nat.")
187 - }
188 -
189 - // list the port mappings (it may be gone on it's own, so we need to
190 - // check this list, and not store it ourselves behind the scenes)
191 -
192 - // close mappings for this internal address.
193 - for _, mapping := range nat.Mappings() {
194 - if mapping.InternalAddr().Equal(intaddr) {
195 - mapping.Close()
196 - }
197 - }
198 -}
199 -
200 -// nmgrNetNotifiee implements the network notification listening part
201 -// of the natManager. this is merely listening to Listen() and ListenClose()
202 -// events.
203 -type nmgrNetNotifiee natManager
204 -
205 -func (nn *nmgrNetNotifiee) natManager() *natManager {
206 - return (*natManager)(nn)
207 -}
208 -
209 -func (nn *nmgrNetNotifiee) Listen(n inet.Network, addr ma.Multiaddr) {
210 - if nn.natManager().NAT() == nil {
211 - return // not ready or doesnt exist.
212 - }
213 -
214 - addPortMapping(nn.natManager(), addr)
215 -}
216 -
217 -func (nn *nmgrNetNotifiee) ListenClose(n inet.Network, addr ma.Multiaddr) {
218 - if nn.natManager().NAT() == nil {
219 - return // not ready or doesnt exist.
220 - }
221 -
222 - rmPortMapping(nn.natManager(), addr)
223 -}
224 -
225 -func (nn *nmgrNetNotifiee) Connected(inet.Network, inet.Conn) {}
226 -func (nn *nmgrNetNotifiee) Disconnected(inet.Network, inet.Conn) {}
227 -func (nn *nmgrNetNotifiee) OpenedStream(inet.Network, inet.Stream) {}
228 -func (nn *nmgrNetNotifiee) ClosedStream(inet.Network, inet.Stream) {}
p2p/host/host.go deleted
-65
@@ -1,65 +0,0 @@
1 -package host
2 -
3 -import (
4 - ma "github.com/ipfs/go-ipfs/Godeps/_workspace/src/github.com/jbenet/go-multiaddr"
5 - context "github.com/ipfs/go-ipfs/Godeps/_workspace/src/golang.org/x/net/context"
6 - metrics "github.com/ipfs/go-ipfs/metrics"
7 - inet "github.com/ipfs/go-ipfs/p2p/net"
8 - peer "github.com/ipfs/go-ipfs/p2p/peer"
9 - protocol "github.com/ipfs/go-ipfs/p2p/protocol"
10 - logging "github.com/ipfs/go-ipfs/vendor/QmQg1J6vikuXF9oDvm4wpdeAUvvkVEKW1EYDw9HhTMnP2b/go-log"
11 -
12 - msmux "github.com/ipfs/go-ipfs/Godeps/_workspace/src/github.com/whyrusleeping/go-multistream"
13 -)
14 -
15 -var log = logging.Logger("p2p/host")
16 -
17 -// Host is an object participating in a p2p network, which
18 -// implements protocols or provides services. It handles
19 -// requests like a Server, and issues requests like a Client.
20 -// It is called Host because it is both Server and Client (and Peer
21 -// may be confusing).
22 -type Host interface {
23 - // ID returns the (local) peer.ID associated with this Host
24 - ID() peer.ID
25 -
26 - // Peerstore returns the Host's repository of Peer Addresses and Keys.
27 - Peerstore() peer.Peerstore
28 -
29 - // Returns the listen addresses of the Host
30 - Addrs() []ma.Multiaddr
31 -
32 - // Networks returns the Network interface of the Host
33 - Network() inet.Network
34 -
35 - // Mux returns the Mux multiplexing incoming streams to protocol handlers
36 - Mux() *msmux.MultistreamMuxer
37 -
38 - // Connect ensures there is a connection between this host and the peer with
39 - // given peer.ID. Connect will absorb the addresses in pi into its internal
40 - // peerstore. If there is not an active connection, Connect will issue a
41 - // h.Network.Dial, and block until a connection is open, or an error is
42 - // returned. // TODO: Relay + NAT.
43 - Connect(ctx context.Context, pi peer.PeerInfo) error
44 -
45 - // SetStreamHandler sets the protocol handler on the Host's Mux.
46 - // This is equivalent to:
47 - // host.Mux().SetHandler(proto, handler)
48 - // (Threadsafe)
49 - SetStreamHandler(pid protocol.ID, handler inet.StreamHandler)
50 -
51 - // RemoveStreamHandler removes a handler on the mux that was set by
52 - // SetStreamHandler
53 - RemoveStreamHandler(pid protocol.ID)
54 -
55 - // NewStream opens a new stream to given peer p, and writes a p2p/protocol
56 - // header with given protocol.ID. If there is no connection to p, attempts
57 - // to create one. If ProtocolID is "", writes no header.
58 - // (Threadsafe)
59 - NewStream(pid protocol.ID, p peer.ID) (inet.Stream, error)
60 -
61 - // Close shuts down the host, its Network, and services.
62 - Close() error
63 -
64 - GetBandwidthReporter() metrics.Reporter
65 -}
p2p/host/routed/routed.go deleted
-124
@@ -1,124 +0,0 @@
1 -package routedhost
2 -
3 -import (
4 - "fmt"
5 - "time"
6 -
7 - ma "github.com/ipfs/go-ipfs/Godeps/_workspace/src/github.com/jbenet/go-multiaddr"
8 - context "github.com/ipfs/go-ipfs/Godeps/_workspace/src/golang.org/x/net/context"
9 - lgbl "github.com/ipfs/go-ipfs/util/eventlog/loggables"
10 - logging "github.com/ipfs/go-ipfs/vendor/QmQg1J6vikuXF9oDvm4wpdeAUvvkVEKW1EYDw9HhTMnP2b/go-log"
11 -
12 - metrics "github.com/ipfs/go-ipfs/metrics"
13 - host "github.com/ipfs/go-ipfs/p2p/host"
14 - inet "github.com/ipfs/go-ipfs/p2p/net"
15 - peer "github.com/ipfs/go-ipfs/p2p/peer"
16 - protocol "github.com/ipfs/go-ipfs/p2p/protocol"
17 - routing "github.com/ipfs/go-ipfs/routing"
18 -
19 - msmux "github.com/ipfs/go-ipfs/Godeps/_workspace/src/github.com/whyrusleeping/go-multistream"
20 -)
21 -
22 -var log = logging.Logger("p2p/host/routed")
23 -
24 -// AddressTTL is the expiry time for our addresses.
25 -// We expire them quickly.
26 -const AddressTTL = time.Second * 10
27 -
28 -// RoutedHost is a p2p Host that includes a routing system.
29 -// This allows the Host to find the addresses for peers when
30 -// it does not have them.
31 -type RoutedHost struct {
32 - host host.Host // embedded other host.
33 - route routing.IpfsRouting
34 -}
35 -
36 -func Wrap(h host.Host, r routing.IpfsRouting) *RoutedHost {
37 - return &RoutedHost{h, r}
38 -}
39 -
40 -// Connect ensures there is a connection between this host and the peer with
41 -// given peer.ID. See (host.Host).Connect for more information.
42 -//
43 -// RoutedHost's Connect differs in that if the host has no addresses for a
44 -// given peer, it will use its routing system to try to find some.
45 -func (rh *RoutedHost) Connect(ctx context.Context, pi peer.PeerInfo) error {
46 - // first, check if we're already connected.
47 - if len(rh.Network().ConnsToPeer(pi.ID)) > 0 {
48 - return nil
49 - }
50 -
51 - // if we were given some addresses, keep + use them.
52 - if len(pi.Addrs) > 0 {
53 - rh.Peerstore().AddAddrs(pi.ID, pi.Addrs, peer.TempAddrTTL)
54 - }
55 -
56 - // Check if we have some addresses in our recent memory.
57 - addrs := rh.Peerstore().Addrs(pi.ID)
58 - if len(addrs) < 1 {
59 -
60 - // no addrs? find some with the routing system.
61 - pi2, err := rh.route.FindPeer(ctx, pi.ID)
62 - if err != nil {
63 - return err // couldnt find any :(
64 - }
65 - if pi2.ID != pi.ID {
66 - err = fmt.Errorf("routing failure: provided addrs for different peer")
67 - logRoutingErrDifferentPeers(ctx, pi.ID, pi2.ID, err)
68 - return err
69 - }
70 - addrs = pi2.Addrs
71 - }
72 -
73 - // if we're here, we got some addrs. let's use our wrapped host to connect.
74 - pi.Addrs = addrs
75 - return rh.host.Connect(ctx, pi)
76 -}
77 -
78 -func logRoutingErrDifferentPeers(ctx context.Context, wanted, got peer.ID, err error) {
79 - lm := make(lgbl.DeferredMap)
80 - lm["error"] = err
81 - lm["wantedPeer"] = func() interface{} { return wanted.Pretty() }
82 - lm["gotPeer"] = func() interface{} { return got.Pretty() }
83 - log.Event(ctx, "routingError", lm)
84 -}
85 -
86 -func (rh *RoutedHost) ID() peer.ID {
87 - return rh.host.ID()
88 -}
89 -
90 -func (rh *RoutedHost) Peerstore() peer.Peerstore {
91 - return rh.host.Peerstore()
92 -}
93 -
94 -func (rh *RoutedHost) Addrs() []ma.Multiaddr {
95 - return rh.host.Addrs()
96 -}
97 -
98 -func (rh *RoutedHost) Network() inet.Network {
99 - return rh.host.Network()
100 -}
101 -
102 -func (rh *RoutedHost) Mux() *msmux.MultistreamMuxer {
103 - return rh.host.Mux()
104 -}
105 -
106 -func (rh *RoutedHost) SetStreamHandler(pid protocol.ID, handler inet.StreamHandler) {
107 - rh.host.SetStreamHandler(pid, handler)
108 -}
109 -
110 -func (rh *RoutedHost) RemoveStreamHandler(pid protocol.ID) {
111 - rh.host.RemoveStreamHandler(pid)
112 -}
113 -
114 -func (rh *RoutedHost) NewStream(pid protocol.ID, p peer.ID) (inet.Stream, error) {
115 - return rh.host.NewStream(pid, p)
116 -}
117 -func (rh *RoutedHost) Close() error {
118 - // no need to close IpfsRouting. we dont own it.
119 - return rh.host.Close()
120 -}
121 -
122 -func (rh *RoutedHost) GetBandwidthReporter() metrics.Reporter {
123 - return rh.host.GetBandwidthReporter()
124 -}
p2p/nat/nat.go deleted
-439
@@ -1,439 +0,0 @@
1 -package nat
2 -
3 -import (
4 - "errors"
5 - "fmt"
6 - "strconv"
7 - "strings"
8 - "sync"
9 - "time"
10 -
11 - ma "github.com/ipfs/go-ipfs/Godeps/_workspace/src/github.com/jbenet/go-multiaddr"
12 - manet "github.com/ipfs/go-ipfs/Godeps/_workspace/src/github.com/jbenet/go-multiaddr-net"
13 -
14 - nat "github.com/ipfs/go-ipfs/Godeps/_workspace/src/github.com/fd/go-nat"
15 - goprocess "github.com/ipfs/go-ipfs/Godeps/_workspace/src/github.com/jbenet/goprocess"
16 - periodic "github.com/ipfs/go-ipfs/Godeps/_workspace/src/github.com/jbenet/goprocess/periodic"
17 - notifier "github.com/ipfs/go-ipfs/thirdparty/notifier"
18 - logging "github.com/ipfs/go-ipfs/vendor/QmQg1J6vikuXF9oDvm4wpdeAUvvkVEKW1EYDw9HhTMnP2b/go-log"
19 -)
20 -
21 -var (
22 - // ErrNoMapping signals no mapping exists for an address
23 - ErrNoMapping = errors.New("mapping not established")
24 -)
25 -
26 -var log = logging.Logger("nat")
27 -
28 -// MappingDuration is a default port mapping duration.
29 -// Port mappings are renewed every (MappingDuration / 3)
30 -const MappingDuration = time.Second * 60
31 -
32 -// CacheTime is the time a mapping will cache an external address for
33 -const CacheTime = time.Second * 15
34 -
35 -// DiscoverNAT looks for a NAT device in the network and
36 -// returns an object that can manage port mappings.
37 -func DiscoverNAT() *NAT {
38 - nat, err := nat.DiscoverGateway()
39 - if err != nil {
40 - log.Debug("DiscoverGateway error:", err)
41 - return nil
42 - }
43 - addr, err := nat.GetDeviceAddress()
44 - if err != nil {
45 - log.Debug("DiscoverGateway address error:", err)
46 - } else {
47 - log.Debug("DiscoverGateway address:", addr)
48 - }
49 - return newNAT(nat)
50 -}
51 -
52 -// NAT is an object that manages address port mappings in
53 -// NATs (Network Address Translators). It is a long-running
54 -// service that will periodically renew port mappings,
55 -// and keep an up-to-date list of all the external addresses.
56 -type NAT struct {
57 - nat nat.NAT
58 - proc goprocess.Process // manages nat mappings lifecycle
59 -
60 - mappingmu sync.RWMutex // guards mappings
61 - mappings map[*mapping]struct{}
62 -
63 - Notifier
64 -}
65 -
66 -func newNAT(realNAT nat.NAT) *NAT {
67 - return &NAT{
68 - nat: realNAT,
69 - proc: goprocess.WithParent(goprocess.Background()),
70 - mappings: make(map[*mapping]struct{}),
71 - }
72 -}
73 -
74 -// Close shuts down all port mappings. NAT can no longer be used.
75 -func (nat *NAT) Close() error {
76 - return nat.proc.Close()
77 -}
78 -
79 -// Process returns the nat's life-cycle manager, for making it listen
80 -// to close signals.
81 -func (nat *NAT) Process() goprocess.Process {
82 - return nat.proc
83 -}
84 -
85 -// Notifier is an object that assists NAT in notifying listeners.
86 -// It is implemented using github.com/ipfs/go-ipfs/thirdparty/notifier
87 -type Notifier struct {
88 - n notifier.Notifier
89 -}
90 -
91 -func (n *Notifier) notifyAll(notify func(n Notifiee)) {
92 - n.n.NotifyAll(func(n notifier.Notifiee) {
93 - notify(n.(Notifiee))
94 - })
95 -}
96 -
97 -// Notify signs up notifiee to listen to NAT events.
98 -func (n *Notifier) Notify(notifiee Notifiee) {
99 - n.n.Notify(n)
100 -}
101 -
102 -// StopNotify stops signaling events to notifiee.
103 -func (n *Notifier) StopNotify(notifiee Notifiee) {
104 - n.n.StopNotify(notifiee)
105 -}
106 -
107 -// Notifiee is an interface objects must implement to listen to NAT events.
108 -type Notifiee interface {
109 -
110 - // Called every time a successful mapping happens
111 - // Warning: the port mapping may have changed. If that is the
112 - // case, both MappingSuccess and MappingChanged are called.
113 - MappingSuccess(nat *NAT, m Mapping)
114 -
115 - // Called when mapping a port succeeds, but the mapping is
116 - // with a different port than an earlier success.
117 - MappingChanged(nat *NAT, m Mapping, oldport int, newport int)
118 -
119 - // Called when a port mapping fails. NAT will continue attempting after
120 - // the next period. To stop trying, use: mapping.Close(). After this failure,
121 - // mapping.ExternalPort() will be zero, and nat.ExternalAddrs() will not
122 - // return the address for this mapping. With luck, the next attempt will
123 - // succeed, without the client needing to do anything.
124 - MappingFailed(nat *NAT, m Mapping, oldport int, err error)
125 -}
126 -
127 -// Mapping represents a port mapping in a NAT.
128 -type Mapping interface {
129 - // NAT returns the NAT object this Mapping belongs to.
130 - NAT() *NAT
131 -
132 - // Protocol returns the protocol of this port mapping. This is either
133 - // "tcp" or "udp" as no other protocols are likely to be NAT-supported.
134 - Protocol() string
135 -
136 - // InternalPort returns the internal device port. Mapping will continue to
137 - // try to map InternalPort() to an external facing port.
138 - InternalPort() int
139 -
140 - // ExternalPort returns the external facing port. If the mapping is not
141 - // established, port will be 0
142 - ExternalPort() int
143 -
144 - // InternalAddr returns the internal address.
145 - InternalAddr() ma.Multiaddr
146 -
147 - // ExternalAddr returns the external facing address. If the mapping is not
148 - // established, addr will be nil, and and ErrNoMapping will be returned.
149 - ExternalAddr() (addr ma.Multiaddr, err error)
150 -
151 - // Close closes the port mapping
152 - Close() error
153 -}
154 -
155 -// keeps republishing
156 -type mapping struct {
157 - sync.Mutex // guards all fields
158 -
159 - nat *NAT
160 - proto string
161 - intport int
162 - extport int
163 - intaddr ma.Multiaddr
164 - proc goprocess.Process
165 -
166 - cached ma.Multiaddr
167 - cacheTime time.Time
168 -}
169 -
170 -func (m *mapping) NAT() *NAT {
171 - m.Lock()
172 - defer m.Unlock()
173 - return m.nat
174 -}
175 -
176 -func (m *mapping) Protocol() string {
177 - m.Lock()
178 - defer m.Unlock()
179 - return m.proto
180 -}
181 -
182 -func (m *mapping) InternalPort() int {
183 - m.Lock()
184 - defer m.Unlock()
185 - return m.intport
186 -}
187 -
188 -func (m *mapping) ExternalPort() int {
189 - m.Lock()
190 - defer m.Unlock()
191 - return m.extport
192 -}
193 -
194 -func (m *mapping) setExternalPort(p int) {
195 - m.Lock()
196 - defer m.Unlock()
197 - m.extport = p
198 -}
199 -
200 -func (m *mapping) InternalAddr() ma.Multiaddr {
201 - m.Lock()
202 - defer m.Unlock()
203 - return m.intaddr
204 -}
205 -
206 -func (m *mapping) ExternalAddr() (ma.Multiaddr, error) {
207 - if time.Now().Sub(m.cacheTime) < CacheTime {
208 - return m.cached, nil
209 - }
210 -
211 - if m.ExternalPort() == 0 { // dont even try right now.
212 - return nil, ErrNoMapping
213 - }
214 -
215 - ip, err := m.nat.nat.GetExternalAddress()
216 - if err != nil {
217 - return nil, err
218 - }
219 -
220 - ipmaddr, err := manet.FromIP(ip)
221 - if err != nil {
222 - return nil, fmt.Errorf("error parsing ip")
223 - }
224 -
225 - // call m.ExternalPort again, as mapping may have changed under our feet. (tocttou)
226 - extport := m.ExternalPort()
227 - if extport == 0 {
228 - return nil, ErrNoMapping
229 - }
230 -
231 - tcp, err := ma.NewMultiaddr(fmt.Sprintf("/%s/%d", m.Protocol(), extport))
232 - if err != nil {
233 - return nil, err
234 - }
235 -
236 - maddr2 := ipmaddr.Encapsulate(tcp)
237 -
238 - m.cached = maddr2
239 - m.cacheTime = time.Now()
240 - return maddr2, nil
241 -}
242 -
243 -func (m *mapping) Close() error {
244 - return m.proc.Close()
245 -}
246 -
247 -// Mappings returns a slice of all NAT mappings
248 -func (nat *NAT) Mappings() []Mapping {
249 - nat.mappingmu.Lock()
250 - maps2 := make([]Mapping, 0, len(nat.mappings))
251 - for m := range nat.mappings {
252 - maps2 = append(maps2, m)
253 - }
254 - nat.mappingmu.Unlock()
255 - return maps2
256 -}
257 -
258 -func (nat *NAT) addMapping(m *mapping) {
259 - // make mapping automatically close when nat is closed.
260 - nat.proc.AddChild(m.proc)
261 -
262 - nat.mappingmu.Lock()
263 - nat.mappings[m] = struct{}{}
264 - nat.mappingmu.Unlock()
265 -}
266 -
267 -func (nat *NAT) rmMapping(m *mapping) {
268 - nat.mappingmu.Lock()
269 - delete(nat.mappings, m)
270 - nat.mappingmu.Unlock()
271 -}
272 -
273 -// NewMapping attemps to construct a mapping on protocol and internal port
274 -// It will also periodically renew the mapping until the returned Mapping
275 -// -- or its parent NAT -- is Closed.
276 -//
277 -// May not succeed, and mappings may change over time;
278 -// NAT devices may not respect our port requests, and even lie.
279 -// Clients should not store the mapped results, but rather always
280 -// poll our object for the latest mappings.
281 -func (nat *NAT) NewMapping(maddr ma.Multiaddr) (Mapping, error) {
282 - if nat == nil {
283 - return nil, fmt.Errorf("no nat available")
284 - }
285 -
286 - network, addr, err := manet.DialArgs(maddr)
287 - if err != nil {
288 - return nil, fmt.Errorf("DialArgs failed on addr:", maddr.String())
289 - }
290 -
291 - switch network {
292 - case "tcp", "tcp4", "tcp6":
293 - network = "tcp"
294 - case "udp", "udp4", "udp6":
295 - network = "udp"
296 - default:
297 - return nil, fmt.Errorf("transport not supported by NAT: %s", network)
298 - }
299 -
300 - intports := strings.Split(addr, ":")[1]
301 - intport, err := strconv.Atoi(intports)
302 - if err != nil {
303 - return nil, err
304 - }
305 -
306 - m := &mapping{
307 - nat: nat,
308 - proto: network,
309 - intport: intport,
310 - intaddr: maddr,
311 - }
312 - m.proc = goprocess.WithTeardown(func() error {
313 - nat.rmMapping(m)
314 - return nil
315 - })
316 - nat.addMapping(m)
317 -
318 - m.proc.AddChild(periodic.Every(MappingDuration/3, func(worker goprocess.Process) {
319 - nat.establishMapping(m)
320 - }))
321 -
322 - // do it once synchronously, so first mapping is done right away, and before exiting,
323 - // allowing users -- in the optimistic case -- to use results right after.
324 - nat.establishMapping(m)
325 - return m, nil
326 -}
327 -
328 -func (nat *NAT) establishMapping(m *mapping) {
329 - oldport := m.ExternalPort()
330 - log.Debugf("Attempting port map: %s/%d", m.Protocol(), m.InternalPort())
331 - newport, err := nat.nat.AddPortMapping(m.Protocol(), m.InternalPort(), "http", MappingDuration)
332 -
333 - failure := func() {
334 - m.setExternalPort(0) // clear mapping
335 - // TODO: log.Event
336 - log.Debugf("failed to establish port mapping: %s", err)
337 - nat.Notifier.notifyAll(func(n Notifiee) {
338 - n.MappingFailed(nat, m, oldport, err)
339 - })
340 -
341 - // we do not close if the mapping failed,
342 - // because it may work again next time.
343 - }
344 -
345 - if err != nil || newport == 0 {
346 - failure()
347 - return
348 - }
349 -
350 - m.setExternalPort(newport)
351 - ext, err := m.ExternalAddr()
352 - if err != nil {
353 - log.Debugf("NAT Mapping addr error: %s %s", m.InternalAddr(), err)
354 - failure()
355 - return
356 - }
357 -
358 - log.Debugf("NAT Mapping: %s --> %s", m.InternalAddr(), ext)
359 - if oldport != 0 && newport != oldport {
360 - log.Debugf("failed to renew same port mapping: ch %d -> %d", oldport, newport)
361 - nat.Notifier.notifyAll(func(n Notifiee) {
362 - n.MappingChanged(nat, m, oldport, newport)
363 - })
364 - }
365 -
366 - nat.Notifier.notifyAll(func(n Notifiee) {
367 - n.MappingSuccess(nat, m)
368 - })
369 -}
370 -
371 -// PortMapAddrs attempts to open (and continue to keep open)
372 -// port mappings for given addrs. This function blocks until
373 -// all addresses have been tried. This allows clients to
374 -// retrieve results immediately after:
375 -//
376 -// nat.PortMapAddrs(addrs)
377 -// mapped := nat.ExternalAddrs()
378 -//
379 -// Some may not succeed, and mappings may change over time;
380 -// NAT devices may not respect our port requests, and even lie.
381 -// Clients should not store the mapped results, but rather always
382 -// poll our object for the latest mappings.
383 -func (nat *NAT) PortMapAddrs(addrs []ma.Multiaddr) {
384 - // spin off addr mappings independently.
385 - var wg sync.WaitGroup
386 - for _, addr := range addrs {
387 - // do all of them concurrently
388 - wg.Add(1)
389 - go func() {
390 - defer wg.Done()
391 - nat.NewMapping(addr)
392 - }()
393 - }
394 - wg.Wait()
395 -}
396 -
397 -// MappedAddrs returns address mappings NAT believes have been
398 -// successfully established. Unsuccessful mappings are nil. This is:
399 -//
400 -// map[internalAddr]externalAddr
401 -//
402 -// This set of mappings _may not_ be correct, as NAT devices are finicky.
403 -// Consider this with _best effort_ semantics.
404 -func (nat *NAT) MappedAddrs() map[ma.Multiaddr]ma.Multiaddr {
405 -
406 - mappings := nat.Mappings()
407 - addrmap := make(map[ma.Multiaddr]ma.Multiaddr, len(mappings))
408 -
409 - for _, m := range mappings {
410 - i := m.InternalAddr()
411 - e, err := m.ExternalAddr()
412 - if err != nil {
413 - addrmap[i] = nil
414 - } else {
415 - addrmap[i] = e
416 - }
417 - }
418 - return addrmap
419 -}
420 -
421 -// ExternalAddrs returns a list of addresses that NAT believes have
422 -// been successfully established. Unsuccessful mappings are omitted,
423 -// so nat.ExternalAddrs() may return less addresses than nat.InternalAddrs().
424 -// To see which addresses are mapped, use nat.MappedAddrs().
425 -//
426 -// This set of mappings _may not_ be correct, as NAT devices are finicky.
427 -// Consider this with _best effort_ semantics.
428 -func (nat *NAT) ExternalAddrs() []ma.Multiaddr {
429 - mappings := nat.Mappings()
430 - addrs := make([]ma.Multiaddr, 0, len(mappings))
431 - for _, m := range mappings {
432 - a, err := m.ExternalAddr()
433 - if err != nil {
434 - continue // this mapping not currently successful.
435 - }
436 - addrs = append(addrs, a)
437 - }
438 - return addrs
439 -}
p2p/net/README.md deleted
-17
@@ -1,17 +0,0 @@
1 -# Network
2 -
3 -The IPFS Network package handles all of the peer-to-peer networking. It connects to other hosts, it encrypts communications, it muxes messages between the network's client services and target hosts. It has multiple subcomponents:
4 -
5 -- `Conn` - a connection to a single Peer
6 - - `MultiConn` - a set of connections to a single Peer
7 - - `SecureConn` - an encrypted (tls-like) connection
8 -- `Swarm` - holds connections to Peers, multiplexes from/to each `MultiConn`
9 -- `Muxer` - multiplexes between `Services` and `Swarm`. Handles `Requet/Reply`.
10 - - `Service` - connects between an outside client service and Network.
11 - - `Handler` - the client service part that handles requests
12 -
13 -It looks a bit like this:
14 -
15 -<center>
16 -![](https://docs.google.com/drawings/d/1FvU7GImRsb9GvAWDDo1le85jIrnFJNVB_OTPXC15WwM/pub?h=480)
17 -</center>
p2p/net/conn/conn.go deleted
-145
@@ -1,145 +0,0 @@
1 -package conn
2 -
3 -import (
4 - "fmt"
5 - "io"
6 - "net"
7 - "time"
8 -
9 - mpool "github.com/ipfs/go-ipfs/Godeps/_workspace/src/github.com/jbenet/go-msgio/mpool"
10 - ma "github.com/ipfs/go-ipfs/Godeps/_workspace/src/github.com/jbenet/go-multiaddr"
11 - manet "github.com/ipfs/go-ipfs/Godeps/_workspace/src/github.com/jbenet/go-multiaddr-net"
12 - context "github.com/ipfs/go-ipfs/Godeps/_workspace/src/golang.org/x/net/context"
13 - ic "github.com/ipfs/go-ipfs/p2p/crypto"
14 - peer "github.com/ipfs/go-ipfs/p2p/peer"
15 - u "github.com/ipfs/go-ipfs/util"
16 - lgbl "github.com/ipfs/go-ipfs/util/eventlog/loggables"
17 - logging "github.com/ipfs/go-ipfs/vendor/QmQg1J6vikuXF9oDvm4wpdeAUvvkVEKW1EYDw9HhTMnP2b/go-log"
18 -)
19 -
20 -var log = logging.Logger("conn")
21 -
22 -// ReleaseBuffer puts the given byte array back into the buffer pool,
23 -// first verifying that it is the correct size
24 -func ReleaseBuffer(b []byte) {
25 - log.Debugf("Releasing buffer! (cap,size = %d, %d)", cap(b), len(b))
26 - mpool.ByteSlicePool.Put(uint32(cap(b)), b)
27 -}
28 -
29 -// singleConn represents a single connection to another Peer (IPFS Node).
30 -type singleConn struct {
31 - local peer.ID
32 - remote peer.ID
33 - maconn manet.Conn
34 - event io.Closer
35 -}
36 -
37 -// newConn constructs a new connection
38 -func newSingleConn(ctx context.Context, local, remote peer.ID, maconn manet.Conn) (Conn, error) {
39 - ml := lgbl.Dial("conn", local, remote, maconn.LocalMultiaddr(), maconn.RemoteMultiaddr())
40 -
41 - conn := &singleConn{
42 - local: local,
43 - remote: remote,
44 - maconn: maconn,
45 - event: log.EventBegin(ctx, "connLifetime", ml),
46 - }
47 -
48 - log.Debugf("newSingleConn %p: %v to %v", conn, local, remote)
49 - return conn, nil
50 -}
51 -
52 -// close is the internal close function, called by ContextCloser.Close
53 -func (c *singleConn) Close() error {
54 - defer func() {
55 - if c.event != nil {
56 - c.event.Close()
57 - c.event = nil
58 - }
59 - }()
60 -
61 - // close underlying connection
62 - return c.maconn.Close()
63 -}
64 -
65 -// ID is an identifier unique to this connection.
66 -func (c *singleConn) ID() string {
67 - return ID(c)
68 -}
69 -
70 -func (c *singleConn) String() string {
71 - return String(c, "singleConn")
72 -}
73 -
74 -func (c *singleConn) LocalAddr() net.Addr {
75 - return c.maconn.LocalAddr()
76 -}
77 -
78 -func (c *singleConn) RemoteAddr() net.Addr {
79 - return c.maconn.RemoteAddr()
80 -}
81 -
82 -func (c *singleConn) LocalPrivateKey() ic.PrivKey {
83 - return nil
84 -}
85 -
86 -func (c *singleConn) RemotePublicKey() ic.PubKey {
87 - return nil
88 -}
89 -
90 -func (c *singleConn) SetDeadline(t time.Time) error {
91 - return c.maconn.SetDeadline(t)
92 -}
93 -func (c *singleConn) SetReadDeadline(t time.Time) error {
94 - return c.maconn.SetReadDeadline(t)
95 -}
96 -
97 -func (c *singleConn) SetWriteDeadline(t time.Time) error {
98 - return c.maconn.SetWriteDeadline(t)
99 -}
100 -
101 -// LocalMultiaddr is the Multiaddr on this side
102 -func (c *singleConn) LocalMultiaddr() ma.Multiaddr {
103 - return c.maconn.LocalMultiaddr()
104 -}
105 -
106 -// RemoteMultiaddr is the Multiaddr on the remote side
107 -func (c *singleConn) RemoteMultiaddr() ma.Multiaddr {
108 - return c.maconn.RemoteMultiaddr()
109 -}
110 -
111 -// LocalPeer is the Peer on this side
112 -func (c *singleConn) LocalPeer() peer.ID {
113 - return c.local
114 -}
115 -
116 -// RemotePeer is the Peer on the remote side
117 -func (c *singleConn) RemotePeer() peer.ID {
118 - return c.remote
119 -}
120 -
121 -// Read reads data, net.Conn style
122 -func (c *singleConn) Read(buf []byte) (int, error) {
123 - return c.maconn.Read(buf)
124 -}
125 -
126 -// Write writes data, net.Conn style
127 -func (c *singleConn) Write(buf []byte) (int, error) {
128 - return c.maconn.Write(buf)
129 -}
130 -
131 -// ID returns the ID of a given Conn.
132 -func ID(c Conn) string {
133 - l := fmt.Sprintf("%s/%s", c.LocalMultiaddr(), c.LocalPeer().Pretty())
134 - r := fmt.Sprintf("%s/%s", c.RemoteMultiaddr(), c.RemotePeer().Pretty())
135 - lh := u.Hash([]byte(l))
136 - rh := u.Hash([]byte(r))
137 - ch := u.XOR(lh, rh)
138 - return peer.ID(ch).Pretty()
139 -}
140 -
141 -// String returns the user-friendly String representation of a conn
142 -func String(c Conn, typ string) string {
143 - return fmt.Sprintf("%s (%s) <-- %s %p --> (%s) %s",
144 - c.LocalPeer(), c.LocalMultiaddr(), typ, c, c.RemoteMultiaddr(), c.RemotePeer())
145 -}
p2p/net/conn/conn_test.go deleted
-136
@@ -1,136 +0,0 @@
1 -package conn
2 -
3 -import (
4 - "bytes"
5 - "fmt"
6 - "runtime"
7 - "sync"
8 - "testing"
9 - "time"
10 -
11 - msgio "github.com/ipfs/go-ipfs/Godeps/_workspace/src/github.com/jbenet/go-msgio"
12 - context "github.com/ipfs/go-ipfs/Godeps/_workspace/src/golang.org/x/net/context"
13 - travis "github.com/ipfs/go-ipfs/util/testutil/ci/travis"
14 -)
15 -
16 -func msgioWrap(c Conn) msgio.ReadWriter {
17 - return msgio.NewReadWriter(c)
18 -}
19 -
20 -func testOneSendRecv(t *testing.T, c1, c2 Conn) {
21 - mc1 := msgioWrap(c1)
22 - mc2 := msgioWrap(c2)
23 -
24 - log.Debugf("testOneSendRecv from %s to %s", c1.LocalPeer(), c2.LocalPeer())
25 - m1 := []byte("hello")
26 - if err := mc1.WriteMsg(m1); err != nil {
27 - t.Fatal(err)
28 - }
29 - m2, err := mc2.ReadMsg()
30 - if err != nil {
31 - t.Fatal(err)
32 - }
33 - if !bytes.Equal(m1, m2) {
34 - t.Fatal("failed to send: %s %s", m1, m2)
35 - }
36 -}
37 -
38 -func testNotOneSendRecv(t *testing.T, c1, c2 Conn) {
39 - mc1 := msgioWrap(c1)
40 - mc2 := msgioWrap(c2)
41 -
42 - m1 := []byte("hello")
43 - if err := mc1.WriteMsg(m1); err == nil {
44 - t.Fatal("write should have failed", err)
45 - }
46 - _, err := mc2.ReadMsg()
47 - if err == nil {
48 - t.Fatal("read should have failed", err)
49 - }
50 -}
51 -
52 -func TestClose(t *testing.T) {
53 - // t.Skip("Skipping in favor of another test")
54 -
55 - ctx, cancel := context.WithCancel(context.Background())
56 - defer cancel()
57 - c1, c2, _, _ := setupSingleConn(t, ctx)
58 -
59 - testOneSendRecv(t, c1, c2)
60 - testOneSendRecv(t, c2, c1)
61 -
62 - c1.Close()
63 - testNotOneSendRecv(t, c1, c2)
64 -
65 - c2.Close()
66 - testNotOneSendRecv(t, c2, c1)
67 - testNotOneSendRecv(t, c1, c2)
68 -}
69 -
70 -func TestCloseLeak(t *testing.T) {
71 - // t.Skip("Skipping in favor of another test")
72 - if testing.Short() {
73 - t.SkipNow()
74 - }
75 -
76 - if travis.IsRunning() {
77 - t.Skip("this doesn't work well on travis")
78 - }
79 -
80 - var wg sync.WaitGroup
81 -
82 - runPair := func(num int) {
83 - ctx, cancel := context.WithCancel(context.Background())
84 - c1, c2, _, _ := setupSingleConn(t, ctx)
85 -
86 - mc1 := msgioWrap(c1)
87 - mc2 := msgioWrap(c2)
88 -
89 - for i := 0; i < num; i++ {
90 - b1 := []byte(fmt.Sprintf("beep%d", i))
91 - mc1.WriteMsg(b1)
92 - b2, err := mc2.ReadMsg()
93 - if err != nil {
94 - panic(err)
95 - }
96 - if !bytes.Equal(b1, b2) {
97 - panic(fmt.Errorf("bytes not equal: %s != %s", b1, b2))
98 - }
99 -
100 - b2 = []byte(fmt.Sprintf("boop%d", i))
101 - mc2.WriteMsg(b2)
102 - b1, err = mc1.ReadMsg()
103 - if err != nil {
104 - panic(err)
105 - }
106 - if !bytes.Equal(b1, b2) {
107 - panic(fmt.Errorf("bytes not equal: %s != %s", b1, b2))
108 - }
109 -
110 - <-time.After(time.Microsecond * 5)
111 - }
112 -
113 - c1.Close()
114 - c2.Close()
115 - cancel() // close the listener
116 - wg.Done()
117 - }
118 -
119 - var cons = 5
120 - var msgs = 50
121 - log.Debugf("Running %d connections * %d msgs.\n", cons, msgs)
122 - for i := 0; i < cons; i++ {
123 - wg.Add(1)
124 - go runPair(msgs)
125 - }
126 -
127 - log.Debugf("Waiting...\n")
128 - wg.Wait()
129 - // done!
130 -
131 - <-time.After(time.Millisecond * 150)
132 - if runtime.NumGoroutine() > 20 {
133 - // panic("uncomment me to debug")
134 - t.Fatal("leaking goroutines:", runtime.NumGoroutine())
135 - }
136 -}
p2p/net/conn/dial.go deleted
-198
@@ -1,198 +0,0 @@
1 -package conn
2 -
3 -import (
4 - "fmt"
5 - "math/rand"
6 - "strings"
7 -
8 - ma "github.com/ipfs/go-ipfs/Godeps/_workspace/src/github.com/jbenet/go-multiaddr"
9 - manet "github.com/ipfs/go-ipfs/Godeps/_workspace/src/github.com/jbenet/go-multiaddr-net"
10 - context "github.com/ipfs/go-ipfs/Godeps/_workspace/src/golang.org/x/net/context"
11 - lgbl "github.com/ipfs/go-ipfs/util/eventlog/loggables"
12 -
13 - ci "github.com/ipfs/go-ipfs/p2p/crypto"
14 - addrutil "github.com/ipfs/go-ipfs/p2p/net/swarm/addr"
15 - transport "github.com/ipfs/go-ipfs/p2p/net/transport"
16 - peer "github.com/ipfs/go-ipfs/p2p/peer"
17 -)
18 -
19 -type WrapFunc func(transport.Conn) transport.Conn
20 -
21 -func NewDialer(p peer.ID, pk ci.PrivKey, wrap WrapFunc) *Dialer {
22 - return &Dialer{
23 - LocalPeer: p,
24 - PrivateKey: pk,
25 - Wrapper: wrap,
26 - }
27 -}
28 -
29 -// String returns the string rep of d.
30 -func (d *Dialer) String() string {
31 - return fmt.Sprintf("<Dialer %s ...>", d.LocalPeer)
32 -}
33 -
34 -// Dial connects to a peer over a particular address
35 -// Ensures raddr is part of peer.Addresses()
36 -// Example: d.DialAddr(ctx, peer.Addresses()[0], peer)
37 -func (d *Dialer) Dial(ctx context.Context, raddr ma.Multiaddr, remote peer.ID) (Conn, error) {
38 - logdial := lgbl.Dial("conn", d.LocalPeer, remote, nil, raddr)
39 - logdial["encrypted"] = (d.PrivateKey != nil) // log wether this will be an encrypted dial or not.
40 - defer log.EventBegin(ctx, "connDial", logdial).Done()
41 -
42 - var connOut Conn
43 - var errOut error
44 - done := make(chan struct{})
45 -
46 - // do it async to ensure we respect don contexteone
47 - go func() {
48 - defer func() {
49 - select {
50 - case done <- struct{}{}:
51 - case <-ctx.Done():
52 - }
53 - }()
54 -
55 - maconn, err := d.rawConnDial(ctx, raddr, remote)
56 - if err != nil {
57 - errOut = err
58 - return
59 - }
60 -
61 - if d.Wrapper != nil {
62 - maconn = d.Wrapper(maconn)
63 - }
64 -
65 - c, err := newSingleConn(ctx, d.LocalPeer, remote, maconn)
66 - if err != nil {
67 - maconn.Close()
68 - errOut = err
69 - return
70 - }
71 -
72 - if d.PrivateKey == nil || EncryptConnections == false {
73 - log.Warning("dialer %s dialing INSECURELY %s at %s!", d, remote, raddr)
74 - connOut = c
75 - return
76 - }
77 -
78 - c2, err := newSecureConn(ctx, d.PrivateKey, c)
79 - if err != nil {
80 - errOut = err
81 - c.Close()
82 - return
83 - }
84 -
85 - connOut = c2
86 - }()
87 -
88 - select {
89 - case <-ctx.Done():
90 - logdial["error"] = ctx.Err()
91 - logdial["dial"] = "failure"
92 - return nil, ctx.Err()
93 - case <-done:
94 - // whew, finished.
95 - }
96 -
97 - if errOut != nil {
98 - logdial["error"] = errOut
99 - logdial["dial"] = "failure"
100 - return nil, errOut
101 - }
102 -
103 - logdial["dial"] = "success"
104 - return connOut, nil
105 -}
106 -
107 -func (d *Dialer) AddDialer(pd transport.Dialer) {
108 - d.Dialers = append(d.Dialers, pd)
109 -}
110 -
111 -// returns dialer that can dial the given address
112 -func (d *Dialer) subDialerForAddr(raddr ma.Multiaddr) transport.Dialer {
113 - for _, pd := range d.Dialers {
114 - if pd.Matches(raddr) {
115 - return pd
116 - }
117 - }
118 -
119 - return nil
120 -}
121 -
122 -// rawConnDial dials the underlying net.Conn + manet.Conns
123 -func (d *Dialer) rawConnDial(ctx context.Context, raddr ma.Multiaddr, remote peer.ID) (transport.Conn, error) {
124 - if strings.HasPrefix(raddr.String(), "/ip4/0.0.0.0") {
125 - log.Event(ctx, "connDialZeroAddr", lgbl.Dial("conn", d.LocalPeer, remote, nil, raddr))
126 - return nil, fmt.Errorf("Attempted to connect to zero address: %s", raddr)
127 - }
128 -
129 - sd := d.subDialerForAddr(raddr)
130 - if sd == nil {
131 - return nil, fmt.Errorf("no dialer for %s", raddr)
132 - }
133 -
134 - return sd.Dial(raddr)
135 -}
136 -
137 -func pickLocalAddr(laddrs []ma.Multiaddr, raddr ma.Multiaddr) (laddr ma.Multiaddr) {
138 - if len(laddrs) < 1 {
139 - return nil
140 - }
141 -
142 - // make sure that we ONLY use local addrs that match the remote addr.
143 - laddrs = manet.AddrMatch(raddr, laddrs)
144 - if len(laddrs) < 1 {
145 - return nil
146 - }
147 -
148 - // make sure that we ONLY use local addrs that CAN dial the remote addr.
149 - // filter out all the local addrs that aren't capable
150 - raddrIPLayer := ma.Split(raddr)[0]
151 - raddrIsLoopback := manet.IsIPLoopback(raddrIPLayer)
152 - raddrIsLinkLocal := manet.IsIP6LinkLocal(raddrIPLayer)
153 - laddrs = addrutil.FilterAddrs(laddrs, func(a ma.Multiaddr) bool {
154 - laddrIPLayer := ma.Split(a)[0]
155 - laddrIsLoopback := manet.IsIPLoopback(laddrIPLayer)
156 - laddrIsLinkLocal := manet.IsIP6LinkLocal(laddrIPLayer)
157 - if laddrIsLoopback { // our loopback addrs can only dial loopbacks.
158 - return raddrIsLoopback
159 - }
160 - if laddrIsLinkLocal {
161 - return raddrIsLinkLocal // out linklocal addrs can only dial link locals.
162 - }
163 - return true
164 - })
165 -
166 - // TODO pick with a good heuristic
167 - // we use a random one for now to prevent bad addresses from making nodes unreachable
168 - // with a random selection, multiple tries may work.
169 - return laddrs[rand.Intn(len(laddrs))]
170 -}
171 -
172 -// MultiaddrProtocolsMatch returns whether two multiaddrs match in protocol stacks.
173 -func MultiaddrProtocolsMatch(a, b ma.Multiaddr) bool {
174 - ap := a.Protocols()
175 - bp := b.Protocols()
176 -
177 - if len(ap) != len(bp) {
178 - return false
179 - }
180 -
181 - for i, api := range ap {
182 - if api.Code != bp[i].Code {
183 - return false
184 - }
185 - }
186 -
187 - return true
188 -}
189 -
190 -// MultiaddrNetMatch returns the first Multiaddr found to match network.
191 -func MultiaddrNetMatch(tgt ma.Multiaddr, srcs []ma.Multiaddr) ma.Multiaddr {
192 - for _, a := range srcs {
193 - if MultiaddrProtocolsMatch(tgt, a) {
194 - return a
195 - }
196 - }
197 - return nil
198 -}
p2p/net/conn/dial_test.go deleted
-321
@@ -1,321 +0,0 @@
1 -package conn
2 -
3 -import (
4 - "fmt"
5 - "io"
6 - "net"
7 - "strings"
8 - "testing"
9 - "time"
10 -
11 - ic "github.com/ipfs/go-ipfs/p2p/crypto"
12 - transport "github.com/ipfs/go-ipfs/p2p/net/transport"
13 - peer "github.com/ipfs/go-ipfs/p2p/peer"
14 - tu "github.com/ipfs/go-ipfs/util/testutil"
15 -
16 - ma "github.com/ipfs/go-ipfs/Godeps/_workspace/src/github.com/jbenet/go-multiaddr"
17 - context "github.com/ipfs/go-ipfs/Godeps/_workspace/src/golang.org/x/net/context"
18 -)
19 -
20 -func echoListen(ctx context.Context, listener Listener) {
21 - for {
22 - c, err := listener.Accept()
23 - if err != nil {
24 -
25 - select {
26 - case <-ctx.Done():
27 - return
28 - default:
29 - }
30 -
31 - if ne, ok := err.(net.Error); ok && ne.Temporary() {
32 - <-time.After(time.Microsecond * 10)
33 - continue
34 - }
35 -
36 - log.Debugf("echoListen: listener appears to be closing")
37 - return
38 - }
39 -
40 - go echo(c.(Conn))
41 - }
42 -}
43 -
44 -func echo(c Conn) {
45 - io.Copy(c, c)
46 -}
47 -
48 -func setupSecureConn(t *testing.T, ctx context.Context) (a, b Conn, p1, p2 tu.PeerNetParams) {
49 - return setupConn(t, ctx, true)
50 -}
51 -
52 -func setupSingleConn(t *testing.T, ctx context.Context) (a, b Conn, p1, p2 tu.PeerNetParams) {
53 - return setupConn(t, ctx, false)
54 -}
55 -
56 -func Listen(ctx context.Context, addr ma.Multiaddr, local peer.ID, sk ic.PrivKey) (Listener, error) {
57 - list, err := transport.NewTCPTransport().Listen(addr)
58 - if err != nil {
59 - return nil, err
60 - }
61 -
62 - return WrapTransportListener(ctx, list, local, sk)
63 -}
64 -
65 -func dialer(t *testing.T, a ma.Multiaddr) transport.Dialer {
66 - tpt := transport.NewTCPTransport()
67 - tptd, err := tpt.Dialer(a)
68 - if err != nil {
69 - t.Fatal(err)
70 - }
71 -
72 - return tptd
73 -}
74 -
75 -func setupConn(t *testing.T, ctx context.Context, secure bool) (a, b Conn, p1, p2 tu.PeerNetParams) {
76 -
77 - p1 = tu.RandPeerNetParamsOrFatal(t)
78 - p2 = tu.RandPeerNetParamsOrFatal(t)
79 -
80 - key1 := p1.PrivKey
81 - key2 := p2.PrivKey
82 - if !secure {
83 - key1 = nil
84 - key2 = nil
85 - }
86 - l1, err := Listen(ctx, p1.Addr, p1.ID, key1)
87 - if err != nil {
88 - t.Fatal(err)
89 - }
90 - p1.Addr = l1.Multiaddr() // Addr has been determined by kernel.
91 -
92 - d2 := &Dialer{
93 - LocalPeer: p2.ID,
94 - PrivateKey: key2,
95 - }
96 -
97 - d2.AddDialer(dialer(t, p2.Addr))
98 -
99 - var c2 Conn
100 -
101 - done := make(chan error)
102 - go func() {
103 - defer close(done)
104 -
105 - var err error
106 - c2, err = d2.Dial(ctx, p1.Addr, p1.ID)
107 - if err != nil {
108 - done <- err
109 - return
110 - }
111 -
112 - // if secure, need to read + write, as that's what triggers the handshake.
113 - if secure {
114 - if err := sayHello(c2); err != nil {
115 - done <- err
116 - }
117 - }
118 - }()
119 -
120 - c1, err := l1.Accept()
121 - if err != nil {
122 - t.Fatal("failed to accept", err)
123 - }
124 -
125 - // if secure, need to read + write, as that's what triggers the handshake.
126 - if secure {
127 - if err := sayHello(c1); err != nil {
128 - done <- err
129 - }
130 - }
131 -
132 - if err := <-done; err != nil {
133 - t.Fatal(err)
134 - }
135 -
136 - return c1.(Conn), c2, p1, p2
137 -}
138 -
139 -func sayHello(c net.Conn) error {
140 - h := []byte("hello")
141 - if _, err := c.Write(h); err != nil {
142 - return err
143 - }
144 - if _, err := c.Read(h); err != nil {
145 - return err
146 - }
147 - if string(h) != "hello" {
148 - return fmt.Errorf("did not get hello")
149 - }
150 - return nil
151 -}
152 -
153 -func testDialer(t *testing.T, secure bool) {
154 - // t.Skip("Skipping in favor of another test")
155 -
156 - p1 := tu.RandPeerNetParamsOrFatal(t)
157 - p2 := tu.RandPeerNetParamsOrFatal(t)
158 -
159 - key1 := p1.PrivKey
160 - key2 := p2.PrivKey
161 - if !secure {
162 - key1 = nil
163 - key2 = nil
164 - t.Log("testing insecurely")
165 - } else {
166 - t.Log("testing securely")
167 - }
168 -
169 - ctx, cancel := context.WithCancel(context.Background())
170 - l1, err := Listen(ctx, p1.Addr, p1.ID, key1)
171 - if err != nil {
172 - t.Fatal(err)
173 - }
174 - p1.Addr = l1.Multiaddr() // Addr has been determined by kernel.
175 -
176 - d2 := &Dialer{
177 - LocalPeer: p2.ID,
178 - PrivateKey: key2,
179 - }
180 - d2.AddDialer(dialer(t, p2.Addr))
181 -
182 - go echoListen(ctx, l1)
183 -
184 - c, err := d2.Dial(ctx, p1.Addr, p1.ID)
185 - if err != nil {
186 - t.Fatal("error dialing peer", err)
187 - }
188 -
189 - // fmt.Println("sending")
190 - mc := msgioWrap(c)
191 - mc.WriteMsg([]byte("beep"))
192 - mc.WriteMsg([]byte("boop"))
193 - out, err := mc.ReadMsg()
194 - if err != nil {
195 - t.Fatal(err)
196 - }
197 -
198 - // fmt.Println("recving", string(out))
199 - data := string(out)
200 - if data != "beep" {
201 - t.Error("unexpected conn output", data)
202 - }
203 -
204 - out, err = mc.ReadMsg()
205 - if err != nil {
206 - t.Fatal(err)
207 - }
208 -
209 - data = string(out)
210 - if string(out) != "boop" {
211 - t.Error("unexpected conn output", data)
212 - }
213 -
214 - // fmt.Println("closing")
215 - c.Close()
216 - l1.Close()
217 - cancel()
218 -}
219 -
220 -func TestDialerInsecure(t *testing.T) {
221 - // t.Skip("Skipping in favor of another test")
222 - testDialer(t, false)
223 -}
224 -
225 -func TestDialerSecure(t *testing.T) {
226 - // t.Skip("Skipping in favor of another test")
227 - testDialer(t, true)
228 -}
229 -
230 -func testDialerCloseEarly(t *testing.T, secure bool) {
231 - // t.Skip("Skipping in favor of another test")
232 -
233 - p1 := tu.RandPeerNetParamsOrFatal(t)
234 - p2 := tu.RandPeerNetParamsOrFatal(t)
235 -
236 - key1 := p1.PrivKey
237 - if !secure {
238 - key1 = nil
239 - t.Log("testing insecurely")
240 - } else {
241 - t.Log("testing securely")
242 - }
243 -
244 - ctx, cancel := context.WithCancel(context.Background())
245 - l1, err := Listen(ctx, p1.Addr, p1.ID, key1)
246 - if err != nil {
247 - t.Fatal(err)
248 - }
249 - p1.Addr = l1.Multiaddr() // Addr has been determined by kernel.
250 -
251 - // lol nesting
252 - d2 := &Dialer{
253 - LocalPeer: p2.ID,
254 - // PrivateKey: key2, -- dont give it key. we'll just close the conn.
255 - }
256 - d2.AddDialer(dialer(t, p2.Addr))
257 -
258 - errs := make(chan error, 100)
259 - done := make(chan struct{}, 1)
260 - gotclosed := make(chan struct{}, 1)
261 - go func() {
262 - defer func() { done <- struct{}{} }()
263 -
264 - c, err := l1.Accept()
265 - if err != nil {
266 - if strings.Contains(err.Error(), "closed") {
267 - gotclosed <- struct{}{}
268 - return
269 - }
270 - errs <- err
271 - }
272 -
273 - if _, err := c.Write([]byte("hello")); err != nil {
274 - gotclosed <- struct{}{}
275 - return
276 - }
277 -
278 - errs <- fmt.Errorf("wrote to conn")
279 - }()
280 -
281 - c, err := d2.Dial(ctx, p1.Addr, p1.ID)
282 - if err != nil {
283 - t.Fatal(err)
284 - }
285 - c.Close() // close it early.
286 -
287 - readerrs := func() {
288 - for {
289 - select {
290 - case e := <-errs:
291 - t.Error(e)
292 - default:
293 - return
294 - }
295 - }
296 - }
297 - readerrs()
298 -
299 - l1.Close()
300 - <-done
301 - cancel()
302 - readerrs()
303 - close(errs)
304 -
305 - select {
306 - case <-gotclosed:
307 - default:
308 - t.Error("did not get closed")
309 - }
310 -}
311 -
312 -// we dont do a handshake with singleConn, so cant "close early."
313 -// func TestDialerCloseEarlyInsecure(t *testing.T) {
314 -// // t.Skip("Skipping in favor of another test")
315 -// testDialerCloseEarly(t, false)
316 -// }
317 -
318 -func TestDialerCloseEarlySecure(t *testing.T) {
319 - // t.Skip("Skipping in favor of another test")
320 - testDialerCloseEarly(t, true)
321 -}
p2p/net/conn/interface.go deleted
-102
@@ -1,102 +0,0 @@
1 -package conn
2 -
3 -import (
4 - "io"
5 - "net"
6 - "time"
7 -
8 - key "github.com/ipfs/go-ipfs/blocks/key"
9 - ic "github.com/ipfs/go-ipfs/p2p/crypto"
10 - filter "github.com/ipfs/go-ipfs/p2p/net/filter"
11 - transport "github.com/ipfs/go-ipfs/p2p/net/transport"
12 - peer "github.com/ipfs/go-ipfs/p2p/peer"
13 -
14 - ma "github.com/ipfs/go-ipfs/Godeps/_workspace/src/github.com/jbenet/go-multiaddr"
15 -)
16 -
17 -// Map maps Keys (Peer.IDs) to Connections.
18 -type Map map[key.Key]Conn
19 -
20 -type PeerConn interface {
21 - io.Closer
22 -
23 - // LocalPeer (this side) ID, PrivateKey, and Address
24 - LocalPeer() peer.ID
25 - LocalPrivateKey() ic.PrivKey
26 - LocalMultiaddr() ma.Multiaddr
27 -
28 - // RemotePeer ID, PublicKey, and Address
29 - RemotePeer() peer.ID
30 - RemotePublicKey() ic.PubKey
31 - RemoteMultiaddr() ma.Multiaddr
32 -}
33 -
34 -// Conn is a generic message-based Peer-to-Peer connection.
35 -type Conn interface {
36 - PeerConn
37 -
38 - // ID is an identifier unique to this connection.
39 - ID() string
40 -
41 - // can't just say "net.Conn" cause we have duplicate methods.
42 - LocalAddr() net.Addr
43 - RemoteAddr() net.Addr
44 - SetDeadline(t time.Time) error
45 - SetReadDeadline(t time.Time) error
46 - SetWriteDeadline(t time.Time) error
47 -
48 - io.Reader
49 - io.Writer
50 -}
51 -
52 -// Dialer is an object that can open connections. We could have a "convenience"
53 -// Dial function as before, but it would have many arguments, as dialing is
54 -// no longer simple (need a peerstore, a local peer, a context, a network, etc)
55 -type Dialer struct {
56 - // LocalPeer is the identity of the local Peer.
57 - LocalPeer peer.ID
58 -
59 - // LocalAddrs is a set of local addresses to use.
60 - //LocalAddrs []ma.Multiaddr
61 -
62 - // Dialers are the sub-dialers usable by this dialer
63 - // selected in order based on the address being dialed
64 - Dialers []transport.Dialer
65 -
66 - // PrivateKey used to initialize a secure connection.
67 - // Warning: if PrivateKey is nil, connection will not be secured.
68 - PrivateKey ic.PrivKey
69 -
70 - // Wrapper to wrap the raw connection (optional)
71 - Wrapper WrapFunc
72 -}
73 -
74 -// Listener is an object that can accept connections. It matches net.Listener
75 -type Listener interface {
76 -
77 - // Accept waits for and returns the next connection to the listener.
78 - Accept() (net.Conn, error)
79 -
80 - // Addr is the local address
81 - Addr() net.Addr
82 -
83 - // Multiaddr is the local multiaddr address
84 - Multiaddr() ma.Multiaddr
85 -
86 - // LocalPeer is the identity of the local Peer.
87 - LocalPeer() peer.ID
88 -
89 - SetAddrFilters(*filter.Filters)
90 -
91 - // Close closes the listener.
92 - // Any blocked Accept operations will be unblocked and return errors.
93 - Close() error
94 -}
95 -
96 -// EncryptConnections is a global parameter because it should either be
97 -// enabled or _completely disabled_. I.e. a node should only be able to talk
98 -// to proper (encrypted) networks if it is encrypting all its transports.
99 -// Running a node with disabled transport encryption is useful to debug the
100 -// protocols, achieve implementation interop, or for private networks which
101 -// -- for whatever reason -- _must_ run unencrypted.
102 -var EncryptConnections = true
p2p/net/conn/listen.go deleted
-170
@@ -1,170 +0,0 @@
1 -package conn
2 -
3 -import (
4 - "fmt"
5 - "io"
6 - "net"
7 -
8 - ma "github.com/ipfs/go-ipfs/Godeps/_workspace/src/github.com/jbenet/go-multiaddr"
9 - tec "github.com/ipfs/go-ipfs/Godeps/_workspace/src/github.com/jbenet/go-temp-err-catcher"
10 - "github.com/ipfs/go-ipfs/Godeps/_workspace/src/github.com/jbenet/goprocess"
11 - goprocessctx "github.com/ipfs/go-ipfs/Godeps/_workspace/src/github.com/jbenet/goprocess/context"
12 - context "github.com/ipfs/go-ipfs/Godeps/_workspace/src/golang.org/x/net/context"
13 -
14 - ic "github.com/ipfs/go-ipfs/p2p/crypto"
15 - filter "github.com/ipfs/go-ipfs/p2p/net/filter"
16 - transport "github.com/ipfs/go-ipfs/p2p/net/transport"
17 - peer "github.com/ipfs/go-ipfs/p2p/peer"
18 -)
19 -
20 -// ConnWrapper is any function that wraps a raw multiaddr connection
21 -type ConnWrapper func(transport.Conn) transport.Conn
22 -
23 -// listener is an object that can accept connections. It implements Listener
24 -type listener struct {
25 - transport.Listener
26 -
27 - local peer.ID // LocalPeer is the identity of the local Peer
28 - privk ic.PrivKey // private key to use to initialize secure conns
29 -
30 - filters *filter.Filters
31 -
32 - wrapper ConnWrapper
33 -
34 - proc goprocess.Process
35 -}
36 -
37 -func (l *listener) teardown() error {
38 - defer log.Debugf("listener closed: %s %s", l.local, l.Multiaddr())
39 - return l.Listener.Close()
40 -}
41 -
42 -func (l *listener) Close() error {
43 - log.Debugf("listener closing: %s %s", l.local, l.Multiaddr())
44 - return l.proc.Close()
45 -}
46 -
47 -func (l *listener) String() string {
48 - return fmt.Sprintf("<Listener %s %s>", l.local, l.Multiaddr())
49 -}
50 -
51 -func (l *listener) SetAddrFilters(fs *filter.Filters) {
52 - l.filters = fs
53 -}
54 -
55 -// Accept waits for and returns the next connection to the listener.
56 -// Note that unfortunately this
57 -func (l *listener) Accept() (net.Conn, error) {
58 -
59 - // listeners dont have contexts. given changes dont make sense here anymore
60 - // note that the parent of listener will Close, which will interrupt all io.
61 - // Contexts and io don't mix.
62 - ctx := context.Background()
63 -
64 - var catcher tec.TempErrCatcher
65 -
66 - catcher.IsTemp = func(e error) bool {
67 - // ignore connection breakages up to this point. but log them
68 - if e == io.EOF {
69 - log.Debugf("listener ignoring conn with EOF: %s", e)
70 - return true
71 - }
72 -
73 - te, ok := e.(tec.Temporary)
74 - if ok {
75 - log.Debugf("listener ignoring conn with temporary err: %s", e)
76 - return te.Temporary()
77 - }
78 - return false
79 - }
80 -
81 - for {
82 - maconn, err := l.Listener.Accept()
83 - if err != nil {
84 - if catcher.IsTemporary(err) {
85 - continue
86 - }
87 - return nil, err
88 - }
89 -
90 - log.Debugf("listener %s got connection: %s <---> %s", l, maconn.LocalMultiaddr(), maconn.RemoteMultiaddr())
91 -
92 - if l.filters != nil && l.filters.AddrBlocked(maconn.RemoteMultiaddr()) {
93 - log.Debugf("blocked connection from %s", maconn.RemoteMultiaddr())
94 - maconn.Close()
95 - continue
96 - }
97 - // If we have a wrapper func, wrap this conn
98 - if l.wrapper != nil {
99 - maconn = l.wrapper(maconn)
100 - }
101 -
102 - c, err := newSingleConn(ctx, l.local, "", maconn)
103 - if err != nil {
104 - if catcher.IsTemporary(err) {
105 - continue
106 - }
107 - return nil, err
108 - }
109 -
110 - if l.privk == nil || EncryptConnections == false {
111 - log.Warning("listener %s listening INSECURELY!", l)
112 - return c, nil
113 - }
114 - sc, err := newSecureConn(ctx, l.privk, c)
115 - if err != nil {
116 - log.Infof("ignoring conn we failed to secure: %s %s", err, c)
117 - continue
118 - }
119 - return sc, nil
120 - }
121 -}
122 -
123 -func (l *listener) Addr() net.Addr {
124 - return l.Listener.Addr()
125 -}
126 -
127 -// Multiaddr is the identity of the local Peer.
128 -// If there is an error converting from net.Addr to ma.Multiaddr,
129 -// the return value will be nil.
130 -func (l *listener) Multiaddr() ma.Multiaddr {
131 - return l.Listener.Multiaddr()
132 -}
133 -
134 -// LocalPeer is the identity of the local Peer.
135 -func (l *listener) LocalPeer() peer.ID {
136 - return l.local
137 -}
138 -
139 -func (l *listener) Loggable() map[string]interface{} {
140 - return map[string]interface{}{
141 - "listener": map[string]interface{}{
142 - "peer": l.LocalPeer(),
143 - "address": l.Multiaddr(),
144 - "secure": (l.privk != nil),
145 - },
146 - }
147 -}
148 -
149 -func WrapTransportListener(ctx context.Context, ml transport.Listener, local peer.ID, sk ic.PrivKey) (Listener, error) {
150 - l := &listener{
151 - Listener: ml,
152 - local: local,
153 - privk: sk,
154 - }
155 - l.proc = goprocessctx.WithContextAndTeardown(ctx, l.teardown)
156 -
157 - log.Debugf("Conn Listener on %s", l.Multiaddr())
158 - log.Event(ctx, "swarmListen", l)
159 - return l, nil
160 -}
161 -
162 -type ListenerConnWrapper interface {
163 - SetConnWrapper(ConnWrapper)
164 -}
165 -
166 -// SetConnWrapper assigns a maconn ConnWrapper to wrap all incoming
167 -// connections with. MUST be set _before_ calling `Accept()`
168 -func (l *listener) SetConnWrapper(cw ConnWrapper) {
169 - l.wrapper = cw
170 -}
p2p/net/conn/secure_conn.go deleted
-125
@@ -1,125 +0,0 @@
1 -package conn
2 -
3 -import (
4 - "errors"
5 - "net"
6 - "time"
7 -
8 - ma "github.com/ipfs/go-ipfs/Godeps/_workspace/src/github.com/jbenet/go-multiaddr"
9 - context "github.com/ipfs/go-ipfs/Godeps/_workspace/src/golang.org/x/net/context"
10 -
11 - ic "github.com/ipfs/go-ipfs/p2p/crypto"
12 - secio "github.com/ipfs/go-ipfs/p2p/crypto/secio"
13 - peer "github.com/ipfs/go-ipfs/p2p/peer"
14 -)
15 -
16 -// secureConn wraps another Conn object with an encrypted channel.
17 -type secureConn struct {
18 - insecure Conn // the wrapped conn
19 - secure secio.Session // secure Session
20 -}
21 -
22 -// newConn constructs a new connection
23 -func newSecureConn(ctx context.Context, sk ic.PrivKey, insecure Conn) (Conn, error) {
24 -
25 - if insecure == nil {
26 - return nil, errors.New("insecure is nil")
27 - }
28 - if insecure.LocalPeer() == "" {
29 - return nil, errors.New("insecure.LocalPeer() is nil")
30 - }
31 - if sk == nil {
32 - return nil, errors.New("private key is nil")
33 - }
34 -
35 - // NewSession performs the secure handshake, which takes multiple RTT
36 - sessgen := secio.SessionGenerator{LocalID: insecure.LocalPeer(), PrivateKey: sk}
37 - secure, err := sessgen.NewSession(ctx, insecure)
38 - if err != nil {
39 - return nil, err
40 - }
41 -
42 - conn := &secureConn{
43 - insecure: insecure,
44 - secure: secure,
45 - }
46 - return conn, nil
47 -}
48 -
49 -func (c *secureConn) Close() error {
50 - return c.secure.Close()
51 -}
52 -
53 -// ID is an identifier unique to this connection.
54 -func (c *secureConn) ID() string {
55 - return ID(c)
56 -}
57 -
58 -func (c *secureConn) String() string {
59 - return String(c, "secureConn")
60 -}
61 -
62 -func (c *secureConn) LocalAddr() net.Addr {
63 - return c.insecure.LocalAddr()
64 -}
65 -
66 -func (c *secureConn) RemoteAddr() net.Addr {
67 - return c.insecure.RemoteAddr()
68 -}
69 -
70 -func (c *secureConn) SetDeadline(t time.Time) error {
71 - return c.insecure.SetDeadline(t)
72 -}
73 -
74 -func (c *secureConn) SetReadDeadline(t time.Time) error {
75 - return c.insecure.SetReadDeadline(t)
76 -}
77 -
78 -func (c *secureConn) SetWriteDeadline(t time.Time) error {
79 - return c.insecure.SetWriteDeadline(t)
80 -}
81 -
82 -// LocalMultiaddr is the Multiaddr on this side
83 -func (c *secureConn) LocalMultiaddr() ma.Multiaddr {
84 - return c.insecure.LocalMultiaddr()
85 -}
86 -
87 -// RemoteMultiaddr is the Multiaddr on the remote side
88 -func (c *secureConn) RemoteMultiaddr() ma.Multiaddr {
89 - return c.insecure.RemoteMultiaddr()
90 -}
91 -
92 -// LocalPeer is the Peer on this side
93 -func (c *secureConn) LocalPeer() peer.ID {
94 - return c.secure.LocalPeer()
95 -}
96 -
97 -// RemotePeer is the Peer on the remote side
98 -func (c *secureConn) RemotePeer() peer.ID {
99 - return c.secure.RemotePeer()
100 -}
101 -
102 -// LocalPrivateKey is the public key of the peer on this side
103 -func (c *secureConn) LocalPrivateKey() ic.PrivKey {
104 - return c.secure.LocalPrivateKey()
105 -}
106 -
107 -// RemotePubKey is the public key of the peer on the remote side
108 -func (c *secureConn) RemotePublicKey() ic.PubKey {
109 - return c.secure.RemotePublicKey()
110 -}
111 -
112 -// Read reads data, net.Conn style
113 -func (c *secureConn) Read(buf []byte) (int, error) {
114 - return c.secure.ReadWriter().Read(buf)
115 -}
116 -
117 -// Write writes data, net.Conn style
118 -func (c *secureConn) Write(buf []byte) (int, error) {
119 - return c.secure.ReadWriter().Write(buf)
120 -}
121 -
122 -// ReleaseMsg releases a buffer
123 -func (c *secureConn) ReleaseMsg(m []byte) {
124 - c.secure.ReadWriter().ReleaseMsg(m)
125 -}
p2p/net/conn/secure_conn_test.go deleted
-211
@@ -1,211 +0,0 @@
1 -package conn
2 -
3 -import (
4 - "bytes"
5 - "runtime"
6 - "sync"
7 - "testing"
8 - "time"
9 -
10 - ic "github.com/ipfs/go-ipfs/p2p/crypto"
11 - travis "github.com/ipfs/go-ipfs/util/testutil/ci/travis"
12 -
13 - context "github.com/ipfs/go-ipfs/Godeps/_workspace/src/golang.org/x/net/context"
14 -)
15 -
16 -func upgradeToSecureConn(t *testing.T, ctx context.Context, sk ic.PrivKey, c Conn) (Conn, error) {
17 - if c, ok := c.(*secureConn); ok {
18 - return c, nil
19 - }
20 -
21 - // shouldn't happen, because dial + listen already return secure conns.
22 - s, err := newSecureConn(ctx, sk, c)
23 - if err != nil {
24 - return nil, err
25 - }
26 -
27 - // need to read + write, as that's what triggers the handshake.
28 - h := []byte("hello")
29 - if _, err := s.Write(h); err != nil {
30 - return nil, err
31 - }
32 - if _, err := s.Read(h); err != nil {
33 - return nil, err
34 - }
35 - return s, nil
36 -}
37 -
38 -func secureHandshake(t *testing.T, ctx context.Context, sk ic.PrivKey, c Conn, done chan error) {
39 - _, err := upgradeToSecureConn(t, ctx, sk, c)
40 - done <- err
41 -}
42 -
43 -func TestSecureSimple(t *testing.T) {
44 - // t.Skip("Skipping in favor of another test")
45 -
46 - numMsgs := 100
47 - if testing.Short() {
48 - numMsgs = 10
49 - }
50 -
51 - ctx := context.Background()
52 - c1, c2, p1, p2 := setupSingleConn(t, ctx)
53 -
54 - done := make(chan error)
55 - go secureHandshake(t, ctx, p1.PrivKey, c1, done)
56 - go secureHandshake(t, ctx, p2.PrivKey, c2, done)
57 -
58 - for i := 0; i < 2; i++ {
59 - if err := <-done; err != nil {
60 - t.Fatal(err)
61 - }
62 - }
63 -
64 - for i := 0; i < numMsgs; i++ {
65 - testOneSendRecv(t, c1, c2)
66 - testOneSendRecv(t, c2, c1)
67 - }
68 -
69 - c1.Close()
70 - c2.Close()
71 -}
72 -
73 -func TestSecureClose(t *testing.T) {
74 - // t.Skip("Skipping in favor of another test")
75 -
76 - ctx := context.Background()
77 - c1, c2, p1, p2 := setupSingleConn(t, ctx)
78 -
79 - done := make(chan error)
80 - go secureHandshake(t, ctx, p1.PrivKey, c1, done)
81 - go secureHandshake(t, ctx, p2.PrivKey, c2, done)
82 -
83 - for i := 0; i < 2; i++ {
84 - if err := <-done; err != nil {
85 - t.Fatal(err)
86 - }
87 - }
88 -
89 - testOneSendRecv(t, c1, c2)
90 -
91 - c1.Close()
92 - testNotOneSendRecv(t, c1, c2)
93 -
94 - c2.Close()
95 - testNotOneSendRecv(t, c1, c2)
96 - testNotOneSendRecv(t, c2, c1)
97 -
98 -}
99 -
100 -func TestSecureCancelHandshake(t *testing.T) {
101 - // t.Skip("Skipping in favor of another test")
102 -
103 - ctx, cancel := context.WithCancel(context.Background())
104 - c1, c2, p1, p2 := setupSingleConn(t, ctx)
105 -
106 - done := make(chan error)
107 - go secureHandshake(t, ctx, p1.PrivKey, c1, done)
108 - <-time.After(time.Millisecond)
109 - cancel() // cancel ctx
110 - go secureHandshake(t, ctx, p2.PrivKey, c2, done)
111 -
112 - for i := 0; i < 2; i++ {
113 - if err := <-done; err == nil {
114 - t.Error("cancel should've errored out")
115 - }
116 - }
117 -}
118 -
119 -func TestSecureHandshakeFailsWithWrongKeys(t *testing.T) {
120 - // t.Skip("Skipping in favor of another test")
121 -
122 - ctx, cancel := context.WithCancel(context.Background())
123 - defer cancel()
124 - c1, c2, p1, p2 := setupSingleConn(t, ctx)
125 -
126 - done := make(chan error)
127 - go secureHandshake(t, ctx, p2.PrivKey, c1, done)
128 - go secureHandshake(t, ctx, p1.PrivKey, c2, done)
129 -
130 - for i := 0; i < 2; i++ {
131 - if err := <-done; err == nil {
132 - t.Fatal("wrong keys should've errored out.")
133 - }
134 - }
135 -}
136 -
137 -func TestSecureCloseLeak(t *testing.T) {
138 - // t.Skip("Skipping in favor of another test")
139 -
140 - if testing.Short() {
141 - t.SkipNow()
142 - }
143 - if travis.IsRunning() {
144 - t.Skip("this doesn't work well on travis")
145 - }
146 -
147 - runPair := func(c1, c2 Conn, num int) {
148 - mc1 := msgioWrap(c1)
149 - mc2 := msgioWrap(c2)
150 -
151 - log.Debugf("runPair %d", num)
152 -
153 - for i := 0; i < num; i++ {
154 - log.Debugf("runPair iteration %d", i)
155 - b1 := []byte("beep")
156 - mc1.WriteMsg(b1)
157 - b2, err := mc2.ReadMsg()
158 - if err != nil {
159 - panic(err)
160 - }
161 - if !bytes.Equal(b1, b2) {
162 - panic("bytes not equal")
163 - }
164 -
165 - b2 = []byte("beep")
166 - mc2.WriteMsg(b2)
167 - b1, err = mc1.ReadMsg()
168 - if err != nil {
169 - panic(err)
170 - }
171 - if !bytes.Equal(b1, b2) {
172 - panic("bytes not equal")
173 - }
174 -
175 - <-time.After(time.Microsecond * 5)
176 - }
177 - }
178 -
179 - var cons = 5
180 - var msgs = 50
181 - log.Debugf("Running %d connections * %d msgs.\n", cons, msgs)
182 -
183 - var wg sync.WaitGroup
184 - for i := 0; i < cons; i++ {
185 - wg.Add(1)
186 -
187 - ctx, cancel := context.WithCancel(context.Background())
188 - c1, c2, _, _ := setupSecureConn(t, ctx)
189 - go func(c1, c2 Conn) {
190 -
191 - defer func() {
192 - c1.Close()
193 - c2.Close()
194 - cancel()
195 - wg.Done()
196 - }()
197 -
198 - runPair(c1, c2, msgs)
199 - }(c1, c2)
200 - }
201 -
202 - log.Debugf("Waiting...\n")
203 - wg.Wait()
204 - // done!
205 -
206 - <-time.After(time.Millisecond * 150)
207 - if runtime.NumGoroutine() > 20 {
208 - // panic("uncomment me to debug")
209 - t.Fatal("leaking goroutines:", runtime.NumGoroutine())
210 - }
211 -}
p2p/net/filter/filter.go deleted
-62
@@ -1,62 +0,0 @@
1 -package filter
2 -
3 -import (
4 - "net"
5 - "strings"
6 - "sync"
7 -
8 - ma "github.com/ipfs/go-ipfs/Godeps/_workspace/src/github.com/jbenet/go-multiaddr"
9 - manet "github.com/ipfs/go-ipfs/Godeps/_workspace/src/github.com/jbenet/go-multiaddr-net"
10 -)
11 -
12 -type Filters struct {
13 - mu sync.RWMutex
14 - filters map[string]*net.IPNet
15 -}
16 -
17 -func NewFilters() *Filters {
18 - return &Filters{
19 - filters: make(map[string]*net.IPNet),
20 - }
21 -}
22 -
23 -func (fs *Filters) AddDialFilter(f *net.IPNet) {
24 - fs.mu.Lock()
25 - defer fs.mu.Unlock()
26 - fs.filters[f.String()] = f
27 -}
28 -
29 -func (f *Filters) AddrBlocked(a ma.Multiaddr) bool {
30 - _, addr, err := manet.DialArgs(a)
31 - if err != nil {
32 - // if we cant parse it, its probably not blocked
33 - return false
34 - }
35 -
36 - ipstr := strings.Split(addr, ":")[0]
37 - ip := net.ParseIP(ipstr)
38 - f.mu.RLock()
39 - defer f.mu.RUnlock()
40 - for _, ft := range f.filters {
41 - if ft.Contains(ip) {
42 - return true
43 - }
44 - }
45 - return false
46 -}
47 -
48 -func (f *Filters) Filters() []*net.IPNet {
49 - var out []*net.IPNet
50 - f.mu.RLock()
51 - defer f.mu.RUnlock()
52 - for _, ff := range f.filters {
53 - out = append(out, ff)
54 - }
55 - return out
56 -}
57 -
58 -func (f *Filters) Remove(ff *net.IPNet) {
59 - f.mu.Lock()
60 - defer f.mu.Unlock()
61 - delete(f.filters, ff.String())
62 -}
p2p/net/interface.go deleted
-155
@@ -1,155 +0,0 @@
1 -package net
2 -
3 -import (
4 - "io"
5 -
6 - conn "github.com/ipfs/go-ipfs/p2p/net/conn"
7 - peer "github.com/ipfs/go-ipfs/p2p/peer"
8 -
9 - ma "github.com/ipfs/go-ipfs/Godeps/_workspace/src/github.com/jbenet/go-multiaddr"
10 - "github.com/ipfs/go-ipfs/Godeps/_workspace/src/github.com/jbenet/goprocess"
11 - context "github.com/ipfs/go-ipfs/Godeps/_workspace/src/golang.org/x/net/context"
12 -)
13 -
14 -// MessageSizeMax is a soft (recommended) maximum for network messages.
15 -// One can write more, as the interface is a stream. But it is useful
16 -// to bunch it up into multiple read/writes when the whole message is
17 -// a single, large serialized object.
18 -const MessageSizeMax = 2 << 22 // 4MB
19 -
20 -// Stream represents a bidirectional channel between two agents in
21 -// the IPFS network. "agent" is as granular as desired, potentially
22 -// being a "request -> reply" pair, or whole protocols.
23 -// Streams are backed by SPDY streams underneath the hood.
24 -type Stream interface {
25 - io.Reader
26 - io.Writer
27 - io.Closer
28 -
29 - // Conn returns the connection this stream is part of.
30 - Conn() Conn
31 -}
32 -
33 -// StreamHandler is the type of function used to listen for
34 -// streams opened by the remote side.
35 -type StreamHandler func(Stream)
36 -
37 -// Conn is a connection to a remote peer. It multiplexes streams.
38 -// Usually there is no need to use a Conn directly, but it may
39 -// be useful to get information about the peer on the other side:
40 -// stream.Conn().RemotePeer()
41 -type Conn interface {
42 - conn.PeerConn
43 -
44 - // NewStream constructs a new Stream over this conn.
45 - NewStream() (Stream, error)
46 -}
47 -
48 -// ConnHandler is the type of function used to listen for
49 -// connections opened by the remote side.
50 -type ConnHandler func(Conn)
51 -
52 -// Network is the interface used to connect to the outside world.
53 -// It dials and listens for connections. it uses a Swarm to pool
54 -// connnections (see swarm pkg, and peerstream.Swarm). Connections
55 -// are encrypted with a TLS-like protocol.
56 -type Network interface {
57 - Dialer
58 - io.Closer
59 -
60 - // SetStreamHandler sets the handler for new streams opened by the
61 - // remote side. This operation is threadsafe.
62 - SetStreamHandler(StreamHandler)
63 -
64 - // SetConnHandler sets the handler for new connections opened by the
65 - // remote side. This operation is threadsafe.
66 - SetConnHandler(ConnHandler)
67 -
68 - // NewStream returns a new stream to given peer p.
69 - // If there is no connection to p, attempts to create one.
70 - NewStream(peer.ID) (Stream, error)
71 -
72 - // Listen tells the network to start listening on given multiaddrs.
73 - Listen(...ma.Multiaddr) error
74 -
75 - // ListenAddresses returns a list of addresses at which this network listens.
76 - ListenAddresses() []ma.Multiaddr
77 -
78 - // InterfaceListenAddresses returns a list of addresses at which this network
79 - // listens. It expands "any interface" addresses (/ip4/0.0.0.0, /ip6/::) to
80 - // use the known local interfaces.
81 - InterfaceListenAddresses() ([]ma.Multiaddr, error)
82 -
83 - // Process returns the network's Process
84 - Process() goprocess.Process
85 -}
86 -
87 -// Dialer represents a service that can dial out to peers
88 -// (this is usually just a Network, but other services may not need the whole
89 -// stack, and thus it becomes easier to mock)
90 -type Dialer interface {
91 -
92 - // Peerstore returns the internal peerstore
93 - // This is useful to tell the dialer about a new address for a peer.
94 - // Or use one of the public keys found out over the network.
95 - Peerstore() peer.Peerstore
96 -
97 - // LocalPeer returns the local peer associated with this network
98 - LocalPeer() peer.ID
99 -
100 - // DialPeer establishes a connection to a given peer
101 - DialPeer(context.Context, peer.ID) (Conn, error)
102 -
103 - // ClosePeer closes the connection to a given peer
104 - ClosePeer(peer.ID) error
105 -
106 - // Connectedness returns a state signaling connection capabilities
107 - Connectedness(peer.ID) Connectedness
108 -
109 - // Peers returns the peers connected
110 - Peers() []peer.ID
111 -
112 - // Conns returns the connections in this Netowrk
113 - Conns() []Conn
114 -
115 - // ConnsToPeer returns the connections in this Netowrk for given peer.
116 - ConnsToPeer(p peer.ID) []Conn
117 -
118 - // Notify/StopNotify register and unregister a notifiee for signals
119 - Notify(Notifiee)
120 - StopNotify(Notifiee)
121 -}
122 -
123 -// Connectedness signals the capacity for a connection with a given node.
124 -// It is used to signal to services and other peers whether a node is reachable.
125 -type Connectedness int
126 -
127 -const (
128 - // NotConnected means no connection to peer, and no extra information (default)
129 - NotConnected Connectedness = iota
130 -
131 - // Connected means has an open, live connection to peer
132 - Connected
133 -
134 - // CanConnect means recently connected to peer, terminated gracefully
135 - CanConnect
136 -
137 - // CannotConnect means recently attempted connecting but failed to connect.
138 - // (should signal "made effort, failed")
139 - CannotConnect
140 -)
141 -
142 -// Notifiee is an interface for an object wishing to receive
143 -// notifications from a Network.
144 -type Notifiee interface {
145 - Listen(Network, ma.Multiaddr) // called when network starts listening on an addr
146 - ListenClose(Network, ma.Multiaddr) // called when network starts listening on an addr
147 - Connected(Network, Conn) // called when a connection opened
148 - Disconnected(Network, Conn) // called when a connection closed
149 - OpenedStream(Network, Stream) // called when a stream opened
150 - ClosedStream(Network, Stream) // called when a stream closed
151 -
152 - // TODO
153 - // PeerConnected(Network, peer.ID) // called when a peer connected
154 - // PeerDisconnected(Network, peer.ID) // called when a peer disconnected
155 -}
p2p/net/mock/interface.go deleted
-103
@@ -1,103 +0,0 @@
1 -// Package mocknet provides a mock net.Network to test with.
2 -//
3 -// - a Mocknet has many inet.Networks
4 -// - a Mocknet has many Links
5 -// - a Link joins two inet.Networks
6 -// - inet.Conns and inet.Streams are created by inet.Networks
7 -package mocknet
8 -
9 -import (
10 - ic "github.com/ipfs/go-ipfs/p2p/crypto"
11 - host "github.com/ipfs/go-ipfs/p2p/host"
12 - inet "github.com/ipfs/go-ipfs/p2p/net"
13 - peer "github.com/ipfs/go-ipfs/p2p/peer"
14 - "io"
15 - "time"
16 -
17 - ma "github.com/ipfs/go-ipfs/Godeps/_workspace/src/github.com/jbenet/go-multiaddr"
18 -)
19 -
20 -type Mocknet interface {
21 -
22 - // GenPeer generates a peer and its inet.Network in the Mocknet
23 - GenPeer() (host.Host, error)
24 -
25 - // AddPeer adds an existing peer. we need both a privkey and addr.
26 - // ID is derived from PrivKey
27 - AddPeer(ic.PrivKey, ma.Multiaddr) (host.Host, error)
28 - AddPeerWithPeerstore(peer.ID, peer.Peerstore) (host.Host, error)
29 -
30 - // retrieve things (with randomized iteration order)
31 - Peers() []peer.ID
32 - Net(peer.ID) inet.Network
33 - Nets() []inet.Network
34 - Host(peer.ID) host.Host
35 - Hosts() []host.Host
36 - Links() LinkMap
37 - LinksBetweenPeers(a, b peer.ID) []Link
38 - LinksBetweenNets(a, b inet.Network) []Link
39 -
40 - // Links are the **ability to connect**.
41 - // think of Links as the physical medium.
42 - // For p1 and p2 to connect, a link must exist between them.
43 - // (this makes it possible to test dial failures, and
44 - // things like relaying traffic)
45 - LinkPeers(peer.ID, peer.ID) (Link, error)
46 - LinkNets(inet.Network, inet.Network) (Link, error)
47 - Unlink(Link) error
48 - UnlinkPeers(peer.ID, peer.ID) error
49 - UnlinkNets(inet.Network, inet.Network) error
50 -
51 - // LinkDefaults are the default options that govern links
52 - // if they do not have thier own option set.
53 - SetLinkDefaults(LinkOptions)
54 - LinkDefaults() LinkOptions
55 -
56 - // Connections are the usual. Connecting means Dialing.
57 - // **to succeed, peers must be linked beforehand**
58 - ConnectPeers(peer.ID, peer.ID) (inet.Conn, error)
59 - ConnectNets(inet.Network, inet.Network) (inet.Conn, error)
60 - DisconnectPeers(peer.ID, peer.ID) error
61 - DisconnectNets(inet.Network, inet.Network) error
62 - LinkAll() error
63 - ConnectAllButSelf() error
64 -}
65 -
66 -// LinkOptions are used to change aspects of the links.
67 -// Sorry but they dont work yet :(
68 -type LinkOptions struct {
69 - Latency time.Duration
70 - Bandwidth float64 // in bytes-per-second
71 - // we can make these values distributions down the road.
72 -}
73 -
74 -// Link represents the **possibility** of a connection between
75 -// two peers. Think of it like physical network links. Without
76 -// them, the peers can try and try but they won't be able to
77 -// connect. This allows constructing topologies where specific
78 -// nodes cannot talk to each other directly. :)
79 -type Link interface {
80 - Networks() []inet.Network
81 - Peers() []peer.ID
82 -
83 - SetOptions(LinkOptions)
84 - Options() LinkOptions
85 -
86 - // Metrics() Metrics
87 -}
88 -
89 -// LinkMap is a 3D map to give us an easy way to track links.
90 -// (wow, much map. so data structure. how compose. ahhh pointer)
91 -type LinkMap map[string]map[string]map[Link]struct{}
92 -
93 -// Printer lets you inspect things :)
94 -type Printer interface {
95 - // MocknetLinks shows the entire Mocknet's link table :)
96 - MocknetLinks(mn Mocknet)
97 - NetworkConns(ni inet.Network)
98 -}
99 -
100 -// PrinterTo returns a Printer ready to write to w.
101 -func PrinterTo(w io.Writer) Printer {
102 - return &printer{w}
103 -}
p2p/net/mock/mock.go deleted
-57
@@ -1,57 +0,0 @@
1 -package mocknet
2 -
3 -import (
4 - logging "github.com/ipfs/go-ipfs/vendor/QmQg1J6vikuXF9oDvm4wpdeAUvvkVEKW1EYDw9HhTMnP2b/go-log"
5 -
6 - context "github.com/ipfs/go-ipfs/Godeps/_workspace/src/golang.org/x/net/context"
7 -)
8 -
9 -var log = logging.Logger("mocknet")
10 -
11 -// WithNPeers constructs a Mocknet with N peers.
12 -func WithNPeers(ctx context.Context, n int) (Mocknet, error) {
13 - m := New(ctx)
14 - for i := 0; i < n; i++ {
15 - if _, err := m.GenPeer(); err != nil {
16 - return nil, err
17 - }
18 - }
19 - return m, nil
20 -}
21 -
22 -// FullMeshLinked constructs a Mocknet with full mesh of Links.
23 -// This means that all the peers **can** connect to each other
24 -// (not that they already are connected. you can use m.ConnectAll())
25 -func FullMeshLinked(ctx context.Context, n int) (Mocknet, error) {
26 - m, err := WithNPeers(ctx, n)
27 - if err != nil {
28 - return nil, err
29 - }
30 -
31 - if err := m.LinkAll(); err != nil {
32 - return nil, err
33 - }
34 -
35 - return m, nil
36 -}
37 -
38 -// FullMeshConnected constructs a Mocknet with full mesh of Connections.
39 -// This means that all the peers have dialed and are ready to talk to
40 -// each other.
41 -func FullMeshConnected(ctx context.Context, n int) (Mocknet, error) {
42 - m, err := FullMeshLinked(ctx, n)
43 - if err != nil {
44 - return nil, err
45 - }
46 -
47 - nets := m.Nets()
48 - for _, n1 := range nets {
49 - for _, n2 := range nets {
50 - if _, err := m.ConnectNets(n1, n2); err != nil {
51 - return nil, err
52 - }
53 - }
54 - }
55 -
56 - return m, nil
57 -}
p2p/net/mock/mock_conn.go deleted
-150
@@ -1,150 +0,0 @@
1 -package mocknet
2 -
3 -import (
4 - "container/list"
5 - "sync"
6 -
7 - ic "github.com/ipfs/go-ipfs/p2p/crypto"
8 - inet "github.com/ipfs/go-ipfs/p2p/net"
9 - peer "github.com/ipfs/go-ipfs/p2p/peer"
10 -
11 - ma "github.com/ipfs/go-ipfs/Godeps/_workspace/src/github.com/jbenet/go-multiaddr"
12 - process "github.com/ipfs/go-ipfs/Godeps/_workspace/src/github.com/jbenet/goprocess"
13 -)
14 -
15 -// conn represents one side's perspective of a
16 -// live connection between two peers.
17 -// it goes over a particular link.
18 -type conn struct {
19 - local peer.ID
20 - remote peer.ID
21 -
22 - localAddr ma.Multiaddr
23 - remoteAddr ma.Multiaddr
24 -
25 - localPrivKey ic.PrivKey
26 - remotePubKey ic.PubKey
27 -
28 - net *peernet
29 - link *link
30 - rconn *conn // counterpart
31 - streams list.List
32 - proc process.Process
33 -
34 - sync.RWMutex
35 -}
36 -
37 -func newConn(ln, rn *peernet, l *link) *conn {
38 - c := &conn{net: ln, link: l}
39 - c.local = ln.peer
40 - c.remote = rn.peer
41 -
42 - c.localAddr = ln.ps.Addrs(ln.peer)[0]
43 - c.remoteAddr = rn.ps.Addrs(rn.peer)[0]
44 -
45 - c.localPrivKey = ln.ps.PrivKey(ln.peer)
46 - c.remotePubKey = rn.ps.PubKey(rn.peer)
47 -
48 - c.proc = process.WithTeardown(c.teardown)
49 - return c
50 -}
51 -
52 -func (c *conn) Close() error {
53 - return c.proc.Close()
54 -}
55 -
56 -func (c *conn) teardown() error {
57 - for _, s := range c.allStreams() {
58 - s.Close()
59 - }
60 - c.net.removeConn(c)
61 - c.net.notifyAll(func(n inet.Notifiee) {
62 - n.Disconnected(c.net, c)
63 - })
64 - return nil
65 -}
66 -
67 -func (c *conn) addStream(s *stream) {
68 - c.Lock()
69 - s.conn = c
70 - c.streams.PushBack(s)
71 - c.Unlock()
72 -}
73 -
74 -func (c *conn) removeStream(s *stream) {
75 - c.Lock()
76 - defer c.Unlock()
77 - for e := c.streams.Front(); e != nil; e = e.Next() {
78 - if s == e.Value {
79 - c.streams.Remove(e)
80 - return
81 - }
82 - }
83 -}
84 -
85 -func (c *conn) allStreams() []inet.Stream {
86 - c.RLock()
87 - defer c.RUnlock()
88 -
89 - strs := make([]inet.Stream, 0, c.streams.Len())
90 - for e := c.streams.Front(); e != nil; e = e.Next() {
91 - s := e.Value.(*stream)
92 - strs = append(strs, s)
93 - }
94 - return strs
95 -}
96 -
97 -func (c *conn) remoteOpenedStream(s *stream) {
98 - c.addStream(s)
99 - c.net.handleNewStream(s)
100 - c.net.notifyAll(func(n inet.Notifiee) {
101 - n.OpenedStream(c.net, s)
102 - })
103 -}
104 -
105 -func (c *conn) openStream() *stream {
106 - sl, sr := c.link.newStreamPair()
107 - c.addStream(sl)
108 - c.net.notifyAll(func(n inet.Notifiee) {
109 - n.OpenedStream(c.net, sl)
110 - })
111 - c.rconn.remoteOpenedStream(sr)
112 - return sl
113 -}
114 -
115 -func (c *conn) NewStream() (inet.Stream, error) {
116 - log.Debugf("Conn.NewStreamWithProtocol: %s --> %s", c.local, c.remote)
117 -
118 - s := c.openStream()
119 - return s, nil
120 -}
121 -
122 -// LocalMultiaddr is the Multiaddr on this side
123 -func (c *conn) LocalMultiaddr() ma.Multiaddr {
124 - return c.localAddr
125 -}
126 -
127 -// LocalPeer is the Peer on our side of the connection
128 -func (c *conn) LocalPeer() peer.ID {
129 - return c.local
130 -}
131 -
132 -// LocalPrivateKey is the private key of the peer on our side.
133 -func (c *conn) LocalPrivateKey() ic.PrivKey {
134 - return c.localPrivKey
135 -}
136 -
137 -// RemoteMultiaddr is the Multiaddr on the remote side
138 -func (c *conn) RemoteMultiaddr() ma.Multiaddr {
139 - return c.remoteAddr
140 -}
141 -
142 -// RemotePeer is the Peer on the remote side
143 -func (c *conn) RemotePeer() peer.ID {
144 - return c.remote
145 -}
146 -
147 -// RemotePublicKey is the private key of the peer on our side.
148 -func (c *conn) RemotePublicKey() ic.PubKey {
149 - return c.remotePubKey
150 -}
p2p/net/mock/mock_link.go deleted
-93
@@ -1,93 +0,0 @@
1 -package mocknet
2 -
3 -import (
4 - // "fmt"
5 - "io"
6 - "sync"
7 - "time"
8 -
9 - inet "github.com/ipfs/go-ipfs/p2p/net"
10 - peer "github.com/ipfs/go-ipfs/p2p/peer"
11 -)
12 -
13 -// link implements mocknet.Link
14 -// and, for simplicity, inet.Conn
15 -type link struct {
16 - mock *mocknet
17 - nets []*peernet
18 - opts LinkOptions
19 - ratelimiter *ratelimiter
20 - // this could have addresses on both sides.
21 -
22 - sync.RWMutex
23 -}
24 -
25 -func newLink(mn *mocknet, opts LinkOptions) *link {
26 - l := &link{mock: mn,
27 - opts: opts,
28 - ratelimiter: NewRatelimiter(opts.Bandwidth)}
29 - return l
30 -}
31 -
32 -func (l *link) newConnPair(dialer *peernet) (*conn, *conn) {
33 - l.RLock()
34 - defer l.RUnlock()
35 -
36 - c1 := newConn(l.nets[0], l.nets[1], l)
37 - c2 := newConn(l.nets[1], l.nets[0], l)
38 - c1.rconn = c2
39 - c2.rconn = c1
40 -
41 - if dialer == c1.net {
42 - return c1, c2
43 - }
44 - return c2, c1
45 -}
46 -
47 -func (l *link) newStreamPair() (*stream, *stream) {
48 - r1, w1 := io.Pipe()
49 - r2, w2 := io.Pipe()
50 -
51 - s1 := NewStream(w2, r1)
52 - s2 := NewStream(w1, r2)
53 - return s1, s2
54 -}
55 -
56 -func (l *link) Networks() []inet.Network {
57 - l.RLock()
58 - defer l.RUnlock()
59 -
60 - cp := make([]inet.Network, len(l.nets))
61 - for i, n := range l.nets {
62 - cp[i] = n
63 - }
64 - return cp
65 -}
66 -
67 -func (l *link) Peers() []peer.ID {
68 - l.RLock()
69 - defer l.RUnlock()
70 -
71 - cp := make([]peer.ID, len(l.nets))
72 - for i, n := range l.nets {
73 - cp[i] = n.peer
74 - }
75 - return cp
76 -}
77 -
78 -func (l *link) SetOptions(o LinkOptions) {
79 - l.opts = o
80 - l.ratelimiter.UpdateBandwidth(l.opts.Bandwidth)
81 -}
82 -
83 -func (l *link) Options() LinkOptions {
84 - return l.opts
85 -}
86 -
87 -func (l *link) GetLatency() time.Duration {
88 - return l.opts.Latency
89 -}
90 -
91 -func (l *link) RateLimit(dataSize int) time.Duration {
92 - return l.ratelimiter.Limit(dataSize)
93 -}
p2p/net/mock/mock_net.go deleted
-371
@@ -1,371 +0,0 @@
1 -package mocknet
2 -
3 -import (
4 - "fmt"
5 - "sort"
6 - "sync"
7 -
8 - ic "github.com/ipfs/go-ipfs/p2p/crypto"
9 - host "github.com/ipfs/go-ipfs/p2p/host"
10 - bhost "github.com/ipfs/go-ipfs/p2p/host/basic"
11 - inet "github.com/ipfs/go-ipfs/p2p/net"
12 - peer "github.com/ipfs/go-ipfs/p2p/peer"
13 - p2putil "github.com/ipfs/go-ipfs/p2p/test/util"
14 - testutil "github.com/ipfs/go-ipfs/util/testutil"
15 -
16 - ma "github.com/ipfs/go-ipfs/Godeps/_workspace/src/github.com/jbenet/go-multiaddr"
17 - "github.com/ipfs/go-ipfs/Godeps/_workspace/src/github.com/jbenet/goprocess"
18 - goprocessctx "github.com/ipfs/go-ipfs/Godeps/_workspace/src/github.com/jbenet/goprocess/context"
19 - context "github.com/ipfs/go-ipfs/Godeps/_workspace/src/golang.org/x/net/context"
20 -)
21 -
22 -// mocknet implements mocknet.Mocknet
23 -type mocknet struct {
24 - nets map[peer.ID]*peernet
25 - hosts map[peer.ID]*bhost.BasicHost
26 -
27 - // links make it possible to connect two peers.
28 - // think of links as the physical medium.
29 - // usually only one, but there could be multiple
30 - // **links are shared between peers**
31 - links map[peer.ID]map[peer.ID]map[*link]struct{}
32 -
33 - linkDefaults LinkOptions
34 -
35 - proc goprocess.Process // for Context closing
36 - ctx context.Context
37 - sync.Mutex
38 -}
39 -
40 -func New(ctx context.Context) Mocknet {
41 - return &mocknet{
42 - nets: map[peer.ID]*peernet{},
43 - hosts: map[peer.ID]*bhost.BasicHost{},
44 - links: map[peer.ID]map[peer.ID]map[*link]struct{}{},
45 - proc: goprocessctx.WithContext(ctx),
46 - ctx: ctx,
47 - }
48 -}
49 -
50 -func (mn *mocknet) GenPeer() (host.Host, error) {
51 - sk, err := p2putil.RandTestBogusPrivateKey()
52 - if err != nil {
53 - return nil, err
54 - }
55 -
56 - a := testutil.RandLocalTCPAddress()
57 -
58 - h, err := mn.AddPeer(sk, a)
59 - if err != nil {
60 - return nil, err
61 - }
62 -
63 - return h, nil
64 -}
65 -
66 -func (mn *mocknet) AddPeer(k ic.PrivKey, a ma.Multiaddr) (host.Host, error) {
67 - p, err := peer.IDFromPublicKey(k.GetPublic())
68 - if err != nil {
69 - return nil, err
70 - }
71 -
72 - ps := peer.NewPeerstore()
73 - ps.AddAddr(p, a, peer.PermanentAddrTTL)
74 - ps.AddPrivKey(p, k)
75 - ps.AddPubKey(p, k.GetPublic())
76 -
77 - return mn.AddPeerWithPeerstore(p, ps)
78 -}
79 -
80 -func (mn *mocknet) AddPeerWithPeerstore(p peer.ID, ps peer.Peerstore) (host.Host, error) {
81 - n, err := newPeernet(mn.ctx, mn, p, ps)
82 - if err != nil {
83 - return nil, err
84 - }
85 -
86 - h := bhost.New(n)
87 -
88 - mn.proc.AddChild(n.proc)
89 -
90 - mn.Lock()
91 - mn.nets[n.peer] = n
92 - mn.hosts[n.peer] = h
93 - mn.Unlock()
94 - return h, nil
95 -}
96 -
97 -func (mn *mocknet) Peers() []peer.ID {
98 - mn.Lock()
99 - defer mn.Unlock()
100 -
101 - cp := make([]peer.ID, 0, len(mn.nets))
102 - for _, n := range mn.nets {
103 - cp = append(cp, n.peer)
104 - }
105 - sort.Sort(peer.IDSlice(cp))
106 - return cp
107 -}
108 -
109 -func (mn *mocknet) Host(pid peer.ID) host.Host {
110 - mn.Lock()
111 - host := mn.hosts[pid]
112 - mn.Unlock()
113 - return host
114 -}
115 -
116 -func (mn *mocknet) Net(pid peer.ID) inet.Network {
117 - mn.Lock()
118 - n := mn.nets[pid]
119 - mn.Unlock()
120 - return n
121 -}
122 -
123 -func (mn *mocknet) Hosts() []host.Host {
124 - mn.Lock()
125 - defer mn.Unlock()
126 -
127 - cp := make([]host.Host, 0, len(mn.hosts))
128 - for _, h := range mn.hosts {
129 - cp = append(cp, h)
130 - }
131 -
132 - sort.Sort(hostSlice(cp))
133 - return cp
134 -}
135 -
136 -func (mn *mocknet) Nets() []inet.Network {
137 - mn.Lock()
138 - defer mn.Unlock()
139 -
140 - cp := make([]inet.Network, 0, len(mn.nets))
141 - for _, n := range mn.nets {
142 - cp = append(cp, n)
143 - }
144 - sort.Sort(netSlice(cp))
145 - return cp
146 -}
147 -
148 -// Links returns a copy of the internal link state map.
149 -// (wow, much map. so data structure. how compose. ahhh pointer)
150 -func (mn *mocknet) Links() LinkMap {
151 - mn.Lock()
152 - defer mn.Unlock()
153 -
154 - links := map[string]map[string]map[Link]struct{}{}
155 - for p1, lm := range mn.links {
156 - sp1 := string(p1)
157 - links[sp1] = map[string]map[Link]struct{}{}
158 - for p2, ls := range lm {
159 - sp2 := string(p2)
160 - links[sp1][sp2] = map[Link]struct{}{}
161 - for l := range ls {
162 - links[sp1][sp2][l] = struct{}{}
163 - }
164 - }
165 - }
166 - return links
167 -}
168 -
169 -func (mn *mocknet) LinkAll() error {
170 - nets := mn.Nets()
171 - for _, n1 := range nets {
172 - for _, n2 := range nets {
173 - if _, err := mn.LinkNets(n1, n2); err != nil {
174 - return err
175 - }
176 - }
177 - }
178 - return nil
179 -}
180 -
181 -func (mn *mocknet) LinkPeers(p1, p2 peer.ID) (Link, error) {
182 - mn.Lock()
183 - n1 := mn.nets[p1]
184 - n2 := mn.nets[p2]
185 - mn.Unlock()
186 -
187 - if n1 == nil {
188 - return nil, fmt.Errorf("network for p1 not in mocknet")
189 - }
190 -
191 - if n2 == nil {
192 - return nil, fmt.Errorf("network for p2 not in mocknet")
193 - }
194 -
195 - return mn.LinkNets(n1, n2)
196 -}
197 -
198 -func (mn *mocknet) validate(n inet.Network) (*peernet, error) {
199 - // WARNING: assumes locks acquired
200 -
201 - nr, ok := n.(*peernet)
202 - if !ok {
203 - return nil, fmt.Errorf("Network not supported (use mock package nets only)")
204 - }
205 -
206 - if _, found := mn.nets[nr.peer]; !found {
207 - return nil, fmt.Errorf("Network not on mocknet. is it from another mocknet?")
208 - }
209 -
210 - return nr, nil
211 -}
212 -
213 -func (mn *mocknet) LinkNets(n1, n2 inet.Network) (Link, error) {
214 - mn.Lock()
215 - n1r, err1 := mn.validate(n1)
216 - n2r, err2 := mn.validate(n2)
217 - ld := mn.linkDefaults
218 - mn.Unlock()
219 -
220 - if err1 != nil {
221 - return nil, err1
222 - }
223 - if err2 != nil {
224 - return nil, err2
225 - }
226 -
227 - l := newLink(mn, ld)
228 - l.nets = append(l.nets, n1r, n2r)
229 - mn.addLink(l)
230 - return l, nil
231 -}
232 -
233 -func (mn *mocknet) Unlink(l2 Link) error {
234 -
235 - l, ok := l2.(*link)
236 - if !ok {
237 - return fmt.Errorf("only links from mocknet are supported")
238 - }
239 -
240 - mn.removeLink(l)
241 - return nil
242 -}
243 -
244 -func (mn *mocknet) UnlinkPeers(p1, p2 peer.ID) error {
245 - ls := mn.LinksBetweenPeers(p1, p2)
246 - if ls == nil {
247 - return fmt.Errorf("no link between p1 and p2")
248 - }
249 -
250 - for _, l := range ls {
251 - if err := mn.Unlink(l); err != nil {
252 - return err
253 - }
254 - }
255 - return nil
256 -}
257 -
258 -func (mn *mocknet) UnlinkNets(n1, n2 inet.Network) error {
259 - return mn.UnlinkPeers(n1.LocalPeer(), n2.LocalPeer())
260 -}
261 -
262 -// get from the links map. and lazily contruct.
263 -func (mn *mocknet) linksMapGet(p1, p2 peer.ID) map[*link]struct{} {
264 -
265 - l1, found := mn.links[p1]
266 - if !found {
267 - mn.links[p1] = map[peer.ID]map[*link]struct{}{}
268 - l1 = mn.links[p1] // so we make sure it's there.
269 - }
270 -
271 - l2, found := l1[p2]
272 - if !found {
273 - m := map[*link]struct{}{}
274 - l1[p2] = m
275 - l2 = l1[p2]
276 - }
277 -
278 - return l2
279 -}
280 -
281 -func (mn *mocknet) addLink(l *link) {
282 - mn.Lock()
283 - defer mn.Unlock()
284 -
285 - n1, n2 := l.nets[0], l.nets[1]
286 - mn.linksMapGet(n1.peer, n2.peer)[l] = struct{}{}
287 - mn.linksMapGet(n2.peer, n1.peer)[l] = struct{}{}
288 -}
289 -
290 -func (mn *mocknet) removeLink(l *link) {
291 - mn.Lock()
292 - defer mn.Unlock()
293 -
294 - n1, n2 := l.nets[0], l.nets[1]
295 - delete(mn.linksMapGet(n1.peer, n2.peer), l)
296 - delete(mn.linksMapGet(n2.peer, n1.peer), l)
297 -}
298 -
299 -func (mn *mocknet) ConnectAllButSelf() error {
300 - nets := mn.Nets()
301 - for _, n1 := range nets {
302 - for _, n2 := range nets {
303 - if n1 == n2 {
304 - continue
305 - }
306 -
307 - if _, err := mn.ConnectNets(n1, n2); err != nil {
308 - return err
309 - }
310 - }
311 - }
312 - return nil
313 -}
314 -
315 -func (mn *mocknet) ConnectPeers(a, b peer.ID) (inet.Conn, error) {
316 - return mn.Net(a).DialPeer(mn.ctx, b)
317 -}
318 -
319 -func (mn *mocknet) ConnectNets(a, b inet.Network) (inet.Conn, error) {
320 - return a.DialPeer(mn.ctx, b.LocalPeer())
321 -}
322 -
323 -func (mn *mocknet) DisconnectPeers(p1, p2 peer.ID) error {
324 - return mn.Net(p1).ClosePeer(p2)
325 -}
326 -
327 -func (mn *mocknet) DisconnectNets(n1, n2 inet.Network) error {
328 - return n1.ClosePeer(n2.LocalPeer())
329 -}
330 -
331 -func (mn *mocknet) LinksBetweenPeers(p1, p2 peer.ID) []Link {
332 - mn.Lock()
333 - defer mn.Unlock()
334 -
335 - ls2 := mn.linksMapGet(p1, p2)
336 - cp := make([]Link, 0, len(ls2))
337 - for l := range ls2 {
338 - cp = append(cp, l)
339 - }
340 - return cp
341 -}
342 -
343 -func (mn *mocknet) LinksBetweenNets(n1, n2 inet.Network) []Link {
344 - return mn.LinksBetweenPeers(n1.LocalPeer(), n2.LocalPeer())
345 -}
346 -
347 -func (mn *mocknet) SetLinkDefaults(o LinkOptions) {
348 - mn.Lock()
349 - mn.linkDefaults = o
350 - mn.Unlock()
351 -}
352 -
353 -func (mn *mocknet) LinkDefaults() LinkOptions {
354 - mn.Lock()
355 - defer mn.Unlock()
356 - return mn.linkDefaults
357 -}
358 -
359 -// netSlice for sorting by peer
360 -type netSlice []inet.Network
361 -
362 -func (es netSlice) Len() int { return len(es) }
363 -func (es netSlice) Swap(i, j int) { es[i], es[j] = es[j], es[i] }
364 -func (es netSlice) Less(i, j int) bool { return string(es[i].LocalPeer()) < string(es[j].LocalPeer()) }
365 -
366 -// hostSlice for sorting by peer
367 -type hostSlice []host.Host
368 -
369 -func (es hostSlice) Len() int { return len(es) }
370 -func (es hostSlice) Swap(i, j int) { es[i], es[j] = es[j], es[i] }
371 -func (es hostSlice) Less(i, j int) bool { return string(es[i].ID()) < string(es[j].ID()) }
p2p/net/mock/mock_notif_test.go deleted
-224
@@ -1,224 +0,0 @@
1 -package mocknet
2 -
3 -import (
4 - "testing"
5 - "time"
6 -
7 - ma "github.com/ipfs/go-ipfs/Godeps/_workspace/src/github.com/jbenet/go-multiaddr"
8 - context "github.com/ipfs/go-ipfs/Godeps/_workspace/src/golang.org/x/net/context"
9 - inet "github.com/ipfs/go-ipfs/p2p/net"
10 - peer "github.com/ipfs/go-ipfs/p2p/peer"
11 -)
12 -
13 -func TestNotifications(t *testing.T) {
14 -
15 - mn, err := FullMeshLinked(context.Background(), 5)
16 - if err != nil {
17 - t.Fatal(err)
18 - }
19 -
20 - timeout := 10 * time.Second
21 -
22 - // signup notifs
23 - nets := mn.Nets()
24 - notifiees := make([]*netNotifiee, len(nets))
25 - for i, pn := range nets {
26 - n := newNetNotifiee()
27 - pn.Notify(n)
28 - notifiees[i] = n
29 - }
30 -
31 - // connect all but self
32 - if err := mn.ConnectAllButSelf(); err != nil {
33 - t.Fatal(err)
34 - }
35 -
36 - // test everyone got the correct connection opened calls
37 - for i, s := range nets {
38 - n := notifiees[i]
39 - notifs := make(map[peer.ID][]inet.Conn)
40 - for j, s2 := range nets {
41 - if i == j {
42 - continue
43 - }
44 -
45 - // this feels a little sketchy, but its probably okay
46 - for len(s.ConnsToPeer(s2.LocalPeer())) != len(notifs[s2.LocalPeer()]) {
47 - select {
48 - case c := <-n.connected:
49 - nfp := notifs[c.RemotePeer()]
50 - notifs[c.RemotePeer()] = append(nfp, c)
51 - case <-time.After(timeout):
52 - t.Fatal("timeout")
53 - }
54 - }
55 - }
56 -
57 - for p, cons := range notifs {
58 - expect := s.ConnsToPeer(p)
59 - if len(expect) != len(cons) {
60 - t.Fatal("got different number of connections")
61 - }
62 -
63 - for _, c := range cons {
64 - var found bool
65 - for _, c2 := range expect {
66 - if c == c2 {
67 - found = true
68 - break
69 - }
70 - }
71 -
72 - if !found {
73 - t.Fatal("connection not found!")
74 - }
75 - }
76 - }
77 - }
78 -
79 - complement := func(c inet.Conn) (inet.Network, *netNotifiee, *conn) {
80 - for i, s := range nets {
81 - for _, c2 := range s.Conns() {
82 - if c2.(*conn).rconn == c {
83 - return s, notifiees[i], c2.(*conn)
84 - }
85 - }
86 - }
87 - t.Fatal("complementary conn not found", c)
88 - return nil, nil, nil
89 - }
90 -
91 - testOCStream := func(n *netNotifiee, s inet.Stream) {
92 - var s2 inet.Stream
93 - select {
94 - case s2 = <-n.openedStream:
95 - t.Log("got notif for opened stream")
96 - case <-time.After(timeout):
97 - t.Fatal("timeout")
98 - }
99 - if s != nil && s != s2 {
100 - t.Fatalf("got incorrect stream %p %p", s, s2)
101 - }
102 -
103 - select {
104 - case s2 = <-n.closedStream:
105 - t.Log("got notif for closed stream")
106 - case <-time.After(timeout):
107 - t.Fatal("timeout")
108 - }
109 - if s != nil && s != s2 {
110 - t.Fatalf("got incorrect stream %p %p", s, s2)
111 - }
112 - }
113 -
114 - for _, s := range nets {
115 - s.SetStreamHandler(func(s inet.Stream) {
116 - s.Close()
117 - })
118 - }
119 -
120 - // there's one stream per conn that we need to drain....
121 - // unsure where these are coming from
122 - for i := range nets {
123 - n := notifiees[i]
124 - for j := 0; j < len(nets)-1; j++ {
125 - testOCStream(n, nil)
126 - }
127 - }
128 -
129 - streams := make(chan inet.Stream)
130 - for _, s := range nets {
131 - s.SetStreamHandler(func(s inet.Stream) {
132 - streams <- s
133 - s.Close()
134 - })
135 - }
136 -
137 - // open a streams in each conn
138 - for i, s := range nets {
139 - conns := s.Conns()
140 - for _, c := range conns {
141 - _, n2, c2 := complement(c)
142 - st1, err := c.NewStream()
143 - if err != nil {
144 - t.Error(err)
145 - } else {
146 - t.Logf("%s %s <--%p--> %s %s", c.LocalPeer(), c.LocalMultiaddr(), st1, c.RemotePeer(), c.RemoteMultiaddr())
147 - // st1.Write([]byte("hello"))
148 - st1.Close()
149 - st2 := <-streams
150 - t.Logf("%s %s <--%p--> %s %s", c2.LocalPeer(), c2.LocalMultiaddr(), st2, c2.RemotePeer(), c2.RemoteMultiaddr())
151 - testOCStream(notifiees[i], st1)
152 - testOCStream(n2, st2)
153 - }
154 - }
155 - }
156 -
157 - // close conns
158 - for i, s := range nets {
159 - n := notifiees[i]
160 - for _, c := range s.Conns() {
161 - _, n2, c2 := complement(c)
162 - c.(*conn).Close()
163 - c2.Close()
164 -
165 - var c3, c4 inet.Conn
166 - select {
167 - case c3 = <-n.disconnected:
168 - case <-time.After(timeout):
169 - t.Fatal("timeout")
170 - }
171 - if c != c3 {
172 - t.Fatal("got incorrect conn", c, c3)
173 - }
174 -
175 - select {
176 - case c4 = <-n2.disconnected:
177 - case <-time.After(timeout):
178 - t.Fatal("timeout")
179 - }
180 - if c2 != c4 {
181 - t.Fatal("got incorrect conn", c, c2)
182 - }
183 - }
184 - }
185 -}
186 -
187 -type netNotifiee struct {
188 - listen chan ma.Multiaddr
189 - listenClose chan ma.Multiaddr
190 - connected chan inet.Conn
191 - disconnected chan inet.Conn
192 - openedStream chan inet.Stream
193 - closedStream chan inet.Stream
194 -}
195 -
196 -func newNetNotifiee() *netNotifiee {
197 - return &netNotifiee{
198 - listen: make(chan ma.Multiaddr),
199 - listenClose: make(chan ma.Multiaddr),
200 - connected: make(chan inet.Conn),
201 - disconnected: make(chan inet.Conn),
202 - openedStream: make(chan inet.Stream),
203 - closedStream: make(chan inet.Stream),
204 - }
205 -}
206 -
207 -func (nn *netNotifiee) Listen(n inet.Network, a ma.Multiaddr) {
208 - nn.listen <- a
209 -}
210 -func (nn *netNotifiee) ListenClose(n inet.Network, a ma.Multiaddr) {
211 - nn.listenClose <- a
212 -}
213 -func (nn *netNotifiee) Connected(n inet.Network, v inet.Conn) {
214 - nn.connected <- v
215 -}
216 -func (nn *netNotifiee) Disconnected(n inet.Network, v inet.Conn) {
217 - nn.disconnected <- v
218 -}
219 -func (nn *netNotifiee) OpenedStream(n inet.Network, v inet.Stream) {
220 - nn.openedStream <- v
221 -}
222 -func (nn *netNotifiee) ClosedStream(n inet.Network, v inet.Stream) {
223 - nn.closedStream <- v
224 -}
p2p/net/mock/mock_peernet.go deleted
-391
@@ -1,391 +0,0 @@
1 -package mocknet
2 -
3 -import (
4 - "fmt"
5 - "math/rand"
6 - "sync"
7 -
8 - inet "github.com/ipfs/go-ipfs/p2p/net"
9 - peer "github.com/ipfs/go-ipfs/p2p/peer"
10 -
11 - ma "github.com/ipfs/go-ipfs/Godeps/_workspace/src/github.com/jbenet/go-multiaddr"
12 - "github.com/ipfs/go-ipfs/Godeps/_workspace/src/github.com/jbenet/goprocess"
13 - goprocessctx "github.com/ipfs/go-ipfs/Godeps/_workspace/src/github.com/jbenet/goprocess/context"
14 - context "github.com/ipfs/go-ipfs/Godeps/_workspace/src/golang.org/x/net/context"
15 -)
16 -
17 -// peernet implements inet.Network
18 -type peernet struct {
19 - mocknet *mocknet // parent
20 -
21 - peer peer.ID
22 - ps peer.Peerstore
23 -
24 - // conns are actual live connections between peers.
25 - // many conns could run over each link.
26 - // **conns are NOT shared between peers**
27 - connsByPeer map[peer.ID]map[*conn]struct{}
28 - connsByLink map[*link]map[*conn]struct{}
29 -
30 - // implement inet.Network
31 - streamHandler inet.StreamHandler
32 - connHandler inet.ConnHandler
33 -
34 - notifmu sync.RWMutex
35 - notifs map[inet.Notifiee]struct{}
36 -
37 - proc goprocess.Process
38 - sync.RWMutex
39 -}
40 -
41 -// newPeernet constructs a new peernet
42 -func newPeernet(ctx context.Context, m *mocknet, p peer.ID, ps peer.Peerstore) (*peernet, error) {
43 -
44 - n := &peernet{
45 - mocknet: m,
46 - peer: p,
47 - ps: ps,
48 -
49 - connsByPeer: map[peer.ID]map[*conn]struct{}{},
50 - connsByLink: map[*link]map[*conn]struct{}{},
51 -
52 - notifs: make(map[inet.Notifiee]struct{}),
53 - }
54 -
55 - n.proc = goprocessctx.WithContextAndTeardown(ctx, n.teardown)
56 - return n, nil
57 -}
58 -
59 -func (pn *peernet) teardown() error {
60 -
61 - // close the connections
62 - for _, c := range pn.allConns() {
63 - c.Close()
64 - }
65 - return nil
66 -}
67 -
68 -// allConns returns all the connections between this peer and others
69 -func (pn *peernet) allConns() []*conn {
70 - pn.RLock()
71 - var cs []*conn
72 - for _, csl := range pn.connsByPeer {
73 - for c := range csl {
74 - cs = append(cs, c)
75 - }
76 - }
77 - pn.RUnlock()
78 - return cs
79 -}
80 -
81 -// Close calls the ContextCloser func
82 -func (pn *peernet) Close() error {
83 - return pn.proc.Close()
84 -}
85 -
86 -func (pn *peernet) Peerstore() peer.Peerstore {
87 - return pn.ps
88 -}
89 -
90 -func (pn *peernet) String() string {
91 - return fmt.Sprintf("<mock.peernet %s - %d conns>", pn.peer, len(pn.allConns()))
92 -}
93 -
94 -// handleNewStream is an internal function to trigger the client's handler
95 -func (pn *peernet) handleNewStream(s inet.Stream) {
96 - pn.RLock()
97 - handler := pn.streamHandler
98 - pn.RUnlock()
99 - if handler != nil {
100 - go handler(s)
101 - }
102 -}
103 -
104 -// handleNewConn is an internal function to trigger the client's handler
105 -func (pn *peernet) handleNewConn(c inet.Conn) {
106 - pn.RLock()
107 - handler := pn.connHandler
108 - pn.RUnlock()
109 - if handler != nil {
110 - go handler(c)
111 - }
112 -}
113 -
114 -// DialPeer attempts to establish a connection to a given peer.
115 -// Respects the context.
116 -func (pn *peernet) DialPeer(ctx context.Context, p peer.ID) (inet.Conn, error) {
117 - return pn.connect(p)
118 -}
119 -
120 -func (pn *peernet) connect(p peer.ID) (*conn, error) {
121 - // first, check if we already have live connections
122 - pn.RLock()
123 - cs, found := pn.connsByPeer[p]
124 - if found && len(cs) > 0 {
125 - var chosen *conn
126 - for c := range cs { // because cs is a map
127 - chosen = c // select first
128 - break
129 - }
130 - pn.RUnlock()
131 - return chosen, nil
132 - }
133 - pn.RUnlock()
134 -
135 - log.Debugf("%s (newly) dialing %s", pn.peer, p)
136 -
137 - // ok, must create a new connection. we need a link
138 - links := pn.mocknet.LinksBetweenPeers(pn.peer, p)
139 - if len(links) < 1 {
140 - return nil, fmt.Errorf("%s cannot connect to %s", pn.peer, p)
141 - }
142 -
143 - // if many links found, how do we select? for now, randomly...
144 - // this would be an interesting place to test logic that can measure
145 - // links (network interfaces) and select properly
146 - l := links[rand.Intn(len(links))]
147 -
148 - log.Debugf("%s dialing %s openingConn", pn.peer, p)
149 - // create a new connection with link
150 - c := pn.openConn(p, l.(*link))
151 - return c, nil
152 -}
153 -
154 -func (pn *peernet) openConn(r peer.ID, l *link) *conn {
155 - lc, rc := l.newConnPair(pn)
156 - log.Debugf("%s opening connection to %s", pn.LocalPeer(), lc.RemotePeer())
157 - pn.addConn(lc)
158 - pn.notifyAll(func(n inet.Notifiee) {
159 - n.Connected(pn, lc)
160 - })
161 - rc.net.remoteOpenedConn(rc)
162 - return lc
163 -}
164 -
165 -func (pn *peernet) remoteOpenedConn(c *conn) {
166 - log.Debugf("%s accepting connection from %s", pn.LocalPeer(), c.RemotePeer())
167 - pn.addConn(c)
168 - pn.handleNewConn(c)
169 - pn.notifyAll(func(n inet.Notifiee) {
170 - n.Connected(pn, c)
171 - })
172 -}
173 -
174 -// addConn constructs and adds a connection
175 -// to given remote peer over given link
176 -func (pn *peernet) addConn(c *conn) {
177 - pn.Lock()
178 - defer pn.Unlock()
179 -
180 - cs, found := pn.connsByPeer[c.RemotePeer()]
181 - if !found {
182 - cs = map[*conn]struct{}{}
183 - pn.connsByPeer[c.RemotePeer()] = cs
184 - }
185 - pn.connsByPeer[c.RemotePeer()][c] = struct{}{}
186 -
187 - cs, found = pn.connsByLink[c.link]
188 - if !found {
189 - cs = map[*conn]struct{}{}
190 - pn.connsByLink[c.link] = cs
191 - }
192 - pn.connsByLink[c.link][c] = struct{}{}
193 -}
194 -
195 -// removeConn removes a given conn
196 -func (pn *peernet) removeConn(c *conn) {
197 - pn.Lock()
198 - defer pn.Unlock()
199 -
200 - cs, found := pn.connsByLink[c.link]
201 - if !found || len(cs) < 1 {
202 - panic(fmt.Sprintf("attempting to remove a conn that doesnt exist %p", c.link))
203 - }
204 - delete(cs, c)
205 -
206 - cs, found = pn.connsByPeer[c.remote]
207 - if !found {
208 - panic(fmt.Sprintf("attempting to remove a conn that doesnt exist %p", c.remote))
209 - }
210 - delete(cs, c)
211 -}
212 -
213 -// Process returns the network's Process
214 -func (pn *peernet) Process() goprocess.Process {
215 - return pn.proc
216 -}
217 -
218 -// LocalPeer the network's LocalPeer
219 -func (pn *peernet) LocalPeer() peer.ID {
220 - return pn.peer
221 -}
222 -
223 -// Peers returns the connected peers
224 -func (pn *peernet) Peers() []peer.ID {
225 - pn.RLock()
226 - defer pn.RUnlock()
227 -
228 - peers := make([]peer.ID, 0, len(pn.connsByPeer))
229 - for _, cs := range pn.connsByPeer {
230 - for c := range cs {
231 - peers = append(peers, c.remote)
232 - break
233 - }
234 - }
235 - return peers
236 -}
237 -
238 -// Conns returns all the connections of this peer
239 -func (pn *peernet) Conns() []inet.Conn {
240 - pn.RLock()
241 - defer pn.RUnlock()
242 -
243 - out := make([]inet.Conn, 0, len(pn.connsByPeer))
244 - for _, cs := range pn.connsByPeer {
245 - for c := range cs {
246 - out = append(out, c)
247 - }
248 - }
249 - return out
250 -}
251 -
252 -func (pn *peernet) ConnsToPeer(p peer.ID) []inet.Conn {
253 - pn.RLock()
254 - defer pn.RUnlock()
255 -
256 - cs, found := pn.connsByPeer[p]
257 - if !found || len(cs) == 0 {
258 - return nil
259 - }
260 -
261 - var cs2 []inet.Conn
262 - for c := range cs {
263 - cs2 = append(cs2, c)
264 - }
265 - return cs2
266 -}
267 -
268 -// ClosePeer connections to peer
269 -func (pn *peernet) ClosePeer(p peer.ID) error {
270 - pn.RLock()
271 - cs, found := pn.connsByPeer[p]
272 - if !found {
273 - pn.RUnlock()
274 - return nil
275 - }
276 -
277 - var conns []*conn
278 - for c := range cs {
279 - conns = append(conns, c)
280 - }
281 - pn.RUnlock()
282 - for _, c := range conns {
283 - c.Close()
284 - }
285 - return nil
286 -}
287 -
288 -// BandwidthTotals returns the total amount of bandwidth transferred
289 -func (pn *peernet) BandwidthTotals() (in uint64, out uint64) {
290 - // need to implement this. probably best to do it in swarm this time.
291 - // need a "metrics" object
292 - return 0, 0
293 -}
294 -
295 -// Listen tells the network to start listening on given multiaddrs.
296 -func (pn *peernet) Listen(addrs ...ma.Multiaddr) error {
297 - pn.Peerstore().AddAddrs(pn.LocalPeer(), addrs, peer.PermanentAddrTTL)
298 - return nil
299 -}
300 -
301 -// ListenAddresses returns a list of addresses at which this network listens.
302 -func (pn *peernet) ListenAddresses() []ma.Multiaddr {
303 - return pn.Peerstore().Addrs(pn.LocalPeer())
304 -}
305 -
306 -// InterfaceListenAddresses returns a list of addresses at which this network
307 -// listens. It expands "any interface" addresses (/ip4/0.0.0.0, /ip6/::) to
308 -// use the known local interfaces.
309 -func (pn *peernet) InterfaceListenAddresses() ([]ma.Multiaddr, error) {
310 - return pn.ListenAddresses(), nil
311 -}
312 -
313 -// Connectedness returns a state signaling connection capabilities
314 -// For now only returns Connecter || NotConnected. Expand into more later.
315 -func (pn *peernet) Connectedness(p peer.ID) inet.Connectedness {
316 - pn.Lock()
317 - defer pn.Unlock()
318 -
319 - cs, found := pn.connsByPeer[p]
320 - if found && len(cs) > 0 {
321 - return inet.Connected
322 - }
323 - return inet.NotConnected
324 -}
325 -
326 -// NewStream returns a new stream to given peer p.
327 -// If there is no connection to p, attempts to create one.
328 -func (pn *peernet) NewStream(p peer.ID) (inet.Stream, error) {
329 - pn.Lock()
330 - cs, found := pn.connsByPeer[p]
331 - if !found || len(cs) < 1 {
332 - pn.Unlock()
333 - return nil, fmt.Errorf("no connection to peer")
334 - }
335 -
336 - // if many conns are found, how do we select? for now, randomly...
337 - // this would be an interesting place to test logic that can measure
338 - // links (network interfaces) and select properly
339 - n := rand.Intn(len(cs))
340 - var c *conn
341 - for c = range cs {
342 - if n == 0 {
343 - break
344 - }
345 - n--
346 - }
347 - pn.Unlock()
348 -
349 - return c.NewStream()
350 -}
351 -
352 -// SetStreamHandler sets the new stream handler on the Network.
353 -// This operation is threadsafe.
354 -func (pn *peernet) SetStreamHandler(h inet.StreamHandler) {
355 - pn.Lock()
356 - pn.streamHandler = h
357 - pn.Unlock()
358 -}
359 -
360 -// SetConnHandler sets the new conn handler on the Network.
361 -// This operation is threadsafe.
362 -func (pn *peernet) SetConnHandler(h inet.ConnHandler) {
363 - pn.Lock()
364 - pn.connHandler = h
365 - pn.Unlock()
366 -}
367 -
368 -// Notify signs up Notifiee to receive signals when events happen
369 -func (pn *peernet) Notify(f inet.Notifiee) {
370 - pn.notifmu.Lock()
371 - pn.notifs[f] = struct{}{}
372 - pn.notifmu.Unlock()
373 -}
374 -
375 -// StopNotify unregisters Notifiee fromr receiving signals
376 -func (pn *peernet) StopNotify(f inet.Notifiee) {
377 - pn.notifmu.Lock()
378 - delete(pn.notifs, f)
379 - pn.notifmu.Unlock()
380 -}
381 -
382 -// notifyAll runs the notification function on all Notifiees
383 -func (pn *peernet) notifyAll(notification func(f inet.Notifiee)) {
384 - pn.notifmu.RLock()
385 - for n := range pn.notifs {
386 - // make sure we dont block
387 - // and they dont block each other.
388 - go notification(n)
389 - }
390 - pn.notifmu.RUnlock()
391 -}
p2p/net/mock/mock_printer.go deleted
-36
@@ -1,36 +0,0 @@
1 -package mocknet
2 -
3 -import (
4 - "fmt"
5 - "io"
6 -
7 - inet "github.com/ipfs/go-ipfs/p2p/net"
8 - peer "github.com/ipfs/go-ipfs/p2p/peer"
9 -)
10 -
11 -// separate object so our interfaces are separate :)
12 -type printer struct {
13 - w io.Writer
14 -}
15 -
16 -func (p *printer) MocknetLinks(mn Mocknet) {
17 - links := mn.Links()
18 -
19 - fmt.Fprintf(p.w, "Mocknet link map:\n")
20 - for p1, lm := range links {
21 - fmt.Fprintf(p.w, "\t%s linked to:\n", peer.ID(p1))
22 - for p2, l := range lm {
23 - fmt.Fprintf(p.w, "\t\t%s (%d links)\n", peer.ID(p2), len(l))
24 - }
25 - }
26 - fmt.Fprintf(p.w, "\n")
27 -}
28 -
29 -func (p *printer) NetworkConns(ni inet.Network) {
30 -
31 - fmt.Fprintf(p.w, "%s connected to:\n", ni.LocalPeer())
32 - for _, c := range ni.Conns() {
33 - fmt.Fprintf(p.w, "\t%s (addr: %s)\n", c.RemotePeer(), c.RemoteMultiaddr())
34 - }
35 - fmt.Fprintf(p.w, "\n")
36 -}
p2p/net/mock/mock_stream.go deleted
-145
@@ -1,145 +0,0 @@
1 -package mocknet
2 -
3 -import (
4 - "bytes"
5 - "io"
6 - "time"
7 -
8 - process "github.com/ipfs/go-ipfs/Godeps/_workspace/src/github.com/jbenet/goprocess"
9 -
10 - inet "github.com/ipfs/go-ipfs/p2p/net"
11 -)
12 -
13 -// stream implements inet.Stream
14 -type stream struct {
15 - io.Reader
16 - io.Writer
17 - conn *conn
18 - toDeliver chan *transportObject
19 - proc process.Process
20 -}
21 -
22 -type transportObject struct {
23 - msg []byte
24 - arrivalTime time.Time
25 -}
26 -
27 -func NewStream(w io.Writer, r io.Reader) *stream {
28 - s := &stream{
29 - Reader: r,
30 - Writer: w,
31 - toDeliver: make(chan *transportObject),
32 - }
33 -
34 - s.proc = process.WithTeardown(s.teardown)
35 - s.proc.Go(s.transport)
36 - return s
37 -}
38 -
39 -// How to handle errors with writes?
40 -func (s *stream) Write(p []byte) (n int, err error) {
41 - l := s.conn.link
42 - delay := l.GetLatency() + l.RateLimit(len(p))
43 - t := time.Now().Add(delay)
44 - select {
45 - case <-s.proc.Closing(): // bail out if we're closing.
46 - return 0, io.ErrClosedPipe
47 - case s.toDeliver <- &transportObject{msg: p, arrivalTime: t}:
48 - }
49 - return len(p), nil
50 -}
51 -
52 -func (s *stream) Close() error {
53 - return s.proc.Close()
54 -}
55 -
56 -// teardown shuts down the stream. it is called by s.proc.Close()
57 -// after all the children of this s.proc (i.e. transport's proc)
58 -// are done.
59 -func (s *stream) teardown() error {
60 - // at this point, no streams are writing.
61 -
62 - s.conn.removeStream(s)
63 - if r, ok := (s.Reader).(io.Closer); ok {
64 - r.Close()
65 - }
66 - if w, ok := (s.Writer).(io.Closer); ok {
67 - w.Close()
68 - }
69 - s.conn.net.notifyAll(func(n inet.Notifiee) {
70 - n.ClosedStream(s.conn.net, s)
71 - })
72 - return nil
73 -}
74 -
75 -func (s *stream) Conn() inet.Conn {
76 - return s.conn
77 -}
78 -
79 -// transport will grab message arrival times, wait until that time, and
80 -// then write the message out when it is scheduled to arrive
81 -func (s *stream) transport(proc process.Process) {
82 - bufsize := 256
83 - buf := new(bytes.Buffer)
84 - ticker := time.NewTicker(time.Millisecond * 4)
85 -
86 - // writeBuf writes the contents of buf through to the s.Writer.
87 - // done only when arrival time makes sense.
88 - drainBuf := func() {
89 - if buf.Len() > 0 {
90 - _, err := s.Writer.Write(buf.Bytes())
91 - if err != nil {
92 - return
93 - }
94 - buf.Reset()
95 - }
96 - }
97 -
98 - // deliverOrWait is a helper func that processes
99 - // an incoming packet. it waits until the arrival time,
100 - // and then writes things out.
101 - deliverOrWait := func(o *transportObject) {
102 - buffered := len(o.msg) + buf.Len()
103 -
104 - now := time.Now()
105 - if now.Before(o.arrivalTime) {
106 - if buffered < bufsize {
107 - buf.Write(o.msg)
108 - return
109 - }
110 -
111 - // we do not buffer + return here, instead hanging the
112 - // call (i.e. not accepting any more transportObjects)
113 - // so that we apply back-pressure to the sender.
114 - // this sleep should wake up same time as ticker.
115 - time.Sleep(o.arrivalTime.Sub(now))
116 - }
117 -
118 - // ok, we waited our due time. now rite the buf + msg.
119 -
120 - // drainBuf first, before we write this message.
121 - drainBuf()
122 -
123 - // write this message.
124 - _, err := s.Writer.Write(o.msg)
125 - if err != nil {
126 - log.Error("mock_stream", err)
127 - }
128 - }
129 -
130 - for {
131 - select {
132 - case <-proc.Closing():
133 - return // bail out of here.
134 -
135 - case o, ok := <-s.toDeliver:
136 - if !ok {
137 - return
138 - }
139 - deliverOrWait(o)
140 -
141 - case <-ticker.C: // ok, due to write it out.
142 - drainBuf()
143 - }
144 - }
145 -}
p2p/net/mock/mock_test.go deleted
-581
@@ -1,581 +0,0 @@
1 -package mocknet
2 -
3 -import (
4 - "bytes"
5 - "io"
6 - "math"
7 - "math/rand"
8 - "sync"
9 - "testing"
10 - "time"
11 -
12 - inet "github.com/ipfs/go-ipfs/p2p/net"
13 - peer "github.com/ipfs/go-ipfs/p2p/peer"
14 - protocol "github.com/ipfs/go-ipfs/p2p/protocol"
15 - testutil "github.com/ipfs/go-ipfs/util/testutil"
16 -
17 - detectrace "github.com/ipfs/go-ipfs/Godeps/_workspace/src/github.com/jbenet/go-detect-race"
18 - context "github.com/ipfs/go-ipfs/Godeps/_workspace/src/golang.org/x/net/context"
19 -)
20 -
21 -func randPeer(t *testing.T) peer.ID {
22 - p, err := testutil.RandPeerID()
23 - if err != nil {
24 - t.Fatal(err)
25 - }
26 - return p
27 -}
28 -
29 -func TestNetworkSetup(t *testing.T) {
30 -
31 - ctx := context.Background()
32 - sk1, _, err := testutil.RandTestKeyPair(512)
33 - if err != nil {
34 - t.Fatal(t)
35 - }
36 - sk2, _, err := testutil.RandTestKeyPair(512)
37 - if err != nil {
38 - t.Fatal(t)
39 - }
40 - sk3, _, err := testutil.RandTestKeyPair(512)
41 - if err != nil {
42 - t.Fatal(t)
43 - }
44 - mn := New(ctx)
45 - // peers := []peer.ID{p1, p2, p3}
46 -
47 - // add peers to mock net
48 -
49 - a1 := testutil.RandLocalTCPAddress()
50 - a2 := testutil.RandLocalTCPAddress()
51 - a3 := testutil.RandLocalTCPAddress()
52 -
53 - h1, err := mn.AddPeer(sk1, a1)
54 - if err != nil {
55 - t.Fatal(err)
56 - }
57 - p1 := h1.ID()
58 -
59 - h2, err := mn.AddPeer(sk2, a2)
60 - if err != nil {
61 - t.Fatal(err)
62 - }
63 - p2 := h2.ID()
64 -
65 - h3, err := mn.AddPeer(sk3, a3)
66 - if err != nil {
67 - t.Fatal(err)
68 - }
69 - p3 := h3.ID()
70 -
71 - // check peers and net
72 - if mn.Host(p1) != h1 {
73 - t.Error("host for p1.ID != h1")
74 - }
75 - if mn.Host(p2) != h2 {
76 - t.Error("host for p2.ID != h2")
77 - }
78 - if mn.Host(p3) != h3 {
79 - t.Error("host for p3.ID != h3")
80 - }
81 -
82 - n1 := h1.Network()
83 - if mn.Net(p1) != n1 {
84 - t.Error("net for p1.ID != n1")
85 - }
86 - n2 := h2.Network()
87 - if mn.Net(p2) != n2 {
88 - t.Error("net for p2.ID != n1")
89 - }
90 - n3 := h3.Network()
91 - if mn.Net(p3) != n3 {
92 - t.Error("net for p3.ID != n1")
93 - }
94 -
95 - // link p1<-->p2, p1<-->p1, p2<-->p3, p3<-->p2
96 -
97 - l12, err := mn.LinkPeers(p1, p2)
98 - if err != nil {
99 - t.Fatal(err)
100 - }
101 - if !(l12.Networks()[0] == n1 && l12.Networks()[1] == n2) &&
102 - !(l12.Networks()[0] == n2 && l12.Networks()[1] == n1) {
103 - t.Error("l12 networks incorrect")
104 - }
105 -
106 - l11, err := mn.LinkPeers(p1, p1)
107 - if err != nil {
108 - t.Fatal(err)
109 - }
110 - if !(l11.Networks()[0] == n1 && l11.Networks()[1] == n1) {
111 - t.Error("l11 networks incorrect")
112 - }
113 -
114 - l23, err := mn.LinkPeers(p2, p3)
115 - if err != nil {
116 - t.Fatal(err)
117 - }
118 - if !(l23.Networks()[0] == n2 && l23.Networks()[1] == n3) &&
119 - !(l23.Networks()[0] == n3 && l23.Networks()[1] == n2) {
120 - t.Error("l23 networks incorrect")
121 - }
122 -
123 - l32, err := mn.LinkPeers(p3, p2)
124 - if err != nil {
125 - t.Fatal(err)
126 - }
127 - if !(l32.Networks()[0] == n2 && l32.Networks()[1] == n3) &&
128 - !(l32.Networks()[0] == n3 && l32.Networks()[1] == n2) {
129 - t.Error("l32 networks incorrect")
130 - }
131 -
132 - // check things
133 -
134 - links12 := mn.LinksBetweenPeers(p1, p2)
135 - if len(links12) != 1 {
136 - t.Errorf("should be 1 link bt. p1 and p2 (found %d)", len(links12))
137 - }
138 - if links12[0] != l12 {
139 - t.Error("links 1-2 should be l12.")
140 - }
141 -
142 - links11 := mn.LinksBetweenPeers(p1, p1)
143 - if len(links11) != 1 {
144 - t.Errorf("should be 1 link bt. p1 and p1 (found %d)", len(links11))
145 - }
146 - if links11[0] != l11 {
147 - t.Error("links 1-1 should be l11.")
148 - }
149 -
150 - links23 := mn.LinksBetweenPeers(p2, p3)
151 - if len(links23) != 2 {
152 - t.Errorf("should be 2 link bt. p2 and p3 (found %d)", len(links23))
153 - }
154 - if !((links23[0] == l23 && links23[1] == l32) ||
155 - (links23[0] == l32 && links23[1] == l23)) {
156 - t.Error("links 2-3 should be l23 and l32.")
157 - }
158 -
159 - // unlinking
160 -
161 - if err := mn.UnlinkPeers(p2, p1); err != nil {
162 - t.Error(err)
163 - }
164 -
165 - // check only one link affected:
166 -
167 - links12 = mn.LinksBetweenPeers(p1, p2)
168 - if len(links12) != 0 {
169 - t.Errorf("should be 0 now...", len(links12))
170 - }
171 -
172 - links11 = mn.LinksBetweenPeers(p1, p1)
173 - if len(links11) != 1 {
174 - t.Errorf("should be 1 link bt. p1 and p1 (found %d)", len(links11))
175 - }
176 - if links11[0] != l11 {
177 - t.Error("links 1-1 should be l11.")
178 - }
179 -
180 - links23 = mn.LinksBetweenPeers(p2, p3)
181 - if len(links23) != 2 {
182 - t.Errorf("should be 2 link bt. p2 and p3 (found %d)", len(links23))
183 - }
184 - if !((links23[0] == l23 && links23[1] == l32) ||
185 - (links23[0] == l32 && links23[1] == l23)) {
186 - t.Error("links 2-3 should be l23 and l32.")
187 - }
188 -
189 - // check connecting
190 -
191 - // first, no conns
192 - if len(n2.Conns()) > 0 || len(n3.Conns()) > 0 {
193 - t.Error("should have 0 conn. Got: (%d, %d)", len(n2.Conns()), len(n3.Conns()))
194 - }
195 -
196 - // connect p2->p3
197 - if _, err := n2.DialPeer(ctx, p3); err != nil {
198 - t.Error(err)
199 - }
200 -
201 - if len(n2.Conns()) != 1 || len(n3.Conns()) != 1 {
202 - t.Errorf("should have (1,1) conn. Got: (%d, %d)", len(n2.Conns()), len(n3.Conns()))
203 - }
204 -
205 - // p := PrinterTo(os.Stdout)
206 - // p.NetworkConns(n1)
207 - // p.NetworkConns(n2)
208 - // p.NetworkConns(n3)
209 -
210 - // can create a stream 2->3, 3->2,
211 - if _, err := n2.NewStream(p3); err != nil {
212 - t.Error(err)
213 - }
214 - if _, err := n3.NewStream(p2); err != nil {
215 - t.Error(err)
216 - }
217 -
218 - // but not 1->2 nor 2->2 (not linked), nor 1->1 (not connected)
219 - if _, err := n1.NewStream(p2); err == nil {
220 - t.Error("should not be able to connect")
221 - }
222 - if _, err := n2.NewStream(p2); err == nil {
223 - t.Error("should not be able to connect")
224 - }
225 - if _, err := n1.NewStream(p1); err == nil {
226 - t.Error("should not be able to connect")
227 - }
228 -
229 - // connect p1->p1 (should work)
230 - if _, err := n1.DialPeer(ctx, p1); err != nil {
231 - t.Error("p1 should be able to dial self.", err)
232 - }
233 -
234 - // and a stream too
235 - if _, err := n1.NewStream(p1); err != nil {
236 - t.Error(err)
237 - }
238 -
239 - // connect p1->p2
240 - if _, err := n1.DialPeer(ctx, p2); err == nil {
241 - t.Error("p1 should not be able to dial p2, not connected...")
242 - }
243 -
244 - // connect p3->p1
245 - if _, err := n3.DialPeer(ctx, p1); err == nil {
246 - t.Error("p3 should not be able to dial p1, not connected...")
247 - }
248 -
249 - // relink p1->p2
250 -
251 - l12, err = mn.LinkPeers(p1, p2)
252 - if err != nil {
253 - t.Fatal(err)
254 - }
255 - if !(l12.Networks()[0] == n1 && l12.Networks()[1] == n2) &&
256 - !(l12.Networks()[0] == n2 && l12.Networks()[1] == n1) {
257 - t.Error("l12 networks incorrect")
258 - }
259 -
260 - // should now be able to connect
261 -
262 - // connect p1->p2
263 - if _, err := n1.DialPeer(ctx, p2); err != nil {
264 - t.Error(err)
265 - }
266 -
267 - // and a stream should work now too :)
268 - if _, err := n2.NewStream(p3); err != nil {
269 - t.Error(err)
270 - }
271 -
272 -}
273 -
274 -func TestStreams(t *testing.T) {
275 -
276 - mn, err := FullMeshConnected(context.Background(), 3)
277 - if err != nil {
278 - t.Fatal(err)
279 - }
280 -
281 - handler := func(s inet.Stream) {
282 - b := make([]byte, 4)
283 - if _, err := io.ReadFull(s, b); err != nil {
284 - panic(err)
285 - }
286 - if !bytes.Equal(b, []byte("beep")) {
287 - panic("bytes mismatch")
288 - }
289 - if _, err := s.Write([]byte("boop")); err != nil {
290 - panic(err)
291 - }
292 - s.Close()
293 - }
294 -
295 - hosts := mn.Hosts()
296 - for _, h := range mn.Hosts() {
297 - h.SetStreamHandler(protocol.TestingID, handler)
298 - }
299 -
300 - s, err := hosts[0].NewStream(protocol.TestingID, hosts[1].ID())
301 - if err != nil {
302 - t.Fatal(err)
303 - }
304 -
305 - if _, err := s.Write([]byte("beep")); err != nil {
306 - panic(err)
307 - }
308 - b := make([]byte, 4)
309 - if _, err := io.ReadFull(s, b); err != nil {
310 - panic(err)
311 - }
312 - if !bytes.Equal(b, []byte("boop")) {
313 - panic("bytes mismatch 2")
314 - }
315 -
316 -}
317 -
318 -func makePinger(st string, n int) func(inet.Stream) {
319 - return func(s inet.Stream) {
320 - go func() {
321 - defer s.Close()
322 -
323 - for i := 0; i < n; i++ {
324 - b := make([]byte, 4+len(st))
325 - if _, err := s.Write([]byte("ping" + st)); err != nil {
326 - panic(err)
327 - }
328 - if _, err := io.ReadFull(s, b); err != nil {
329 - panic(err)
330 - }
331 - if !bytes.Equal(b, []byte("pong"+st)) {
332 - panic("bytes mismatch")
333 - }
334 - }
335 - }()
336 - }
337 -}
338 -
339 -func makePonger(st string) func(inet.Stream) {
340 - return func(s inet.Stream) {
341 - go func() {
342 - defer s.Close()
343 -
344 - for {
345 - b := make([]byte, 4+len(st))
346 - if _, err := io.ReadFull(s, b); err != nil {
347 - if err == io.EOF {
348 - return
349 - }
350 - panic(err)
351 - }
352 - if !bytes.Equal(b, []byte("ping"+st)) {
353 - panic("bytes mismatch")
354 - }
355 - if _, err := s.Write([]byte("pong" + st)); err != nil {
356 - panic(err)
357 - }
358 - }
359 - }()
360 - }
361 -}
362 -
363 -func TestStreamsStress(t *testing.T) {
364 - nnodes := 100
365 - if detectrace.WithRace() {
366 - nnodes = 50
367 - }
368 -
369 - mn, err := FullMeshConnected(context.Background(), nnodes)
370 - if err != nil {
371 - t.Fatal(err)
372 - }
373 -
374 - hosts := mn.Hosts()
375 - for _, h := range hosts {
376 - ponger := makePonger(string(protocol.TestingID))
377 - h.SetStreamHandler(protocol.TestingID, ponger)
378 - }
379 -
380 - var wg sync.WaitGroup
381 - for i := 0; i < 1000; i++ {
382 - wg.Add(1)
383 - go func(i int) {
384 - defer wg.Done()
385 - from := rand.Intn(len(hosts))
386 - to := rand.Intn(len(hosts))
387 - s, err := hosts[from].NewStream(protocol.TestingID, hosts[to].ID())
388 - if err != nil {
389 - log.Debugf("%d (%s) %d (%s)", from, hosts[from], to, hosts[to])
390 - panic(err)
391 - }
392 -
393 - log.Infof("%d start pinging", i)
394 - makePinger("pingpong", rand.Intn(100))(s)
395 - log.Infof("%d done pinging", i)
396 - }(i)
397 - }
398 -
399 - wg.Wait()
400 -}
401 -
402 -func TestAdding(t *testing.T) {
403 -
404 - mn := New(context.Background())
405 -
406 - peers := []peer.ID{}
407 - for i := 0; i < 3; i++ {
408 - sk, _, err := testutil.RandTestKeyPair(512)
409 - if err != nil {
410 - t.Fatal(err)
411 - }
412 -
413 - a := testutil.RandLocalTCPAddress()
414 - h, err := mn.AddPeer(sk, a)
415 - if err != nil {
416 - t.Fatal(err)
417 - }
418 -
419 - peers = append(peers, h.ID())
420 - }
421 -
422 - p1 := peers[0]
423 - p2 := peers[1]
424 -
425 - // link them
426 - for _, p1 := range peers {
427 - for _, p2 := range peers {
428 - if _, err := mn.LinkPeers(p1, p2); err != nil {
429 - t.Error(err)
430 - }
431 - }
432 - }
433 -
434 - // set the new stream handler on p2
435 - h2 := mn.Host(p2)
436 - if h2 == nil {
437 - t.Fatalf("no host for %s", p2)
438 - }
439 - h2.SetStreamHandler(protocol.TestingID, func(s inet.Stream) {
440 - defer s.Close()
441 -
442 - b := make([]byte, 4)
443 - if _, err := io.ReadFull(s, b); err != nil {
444 - panic(err)
445 - }
446 - if string(b) != "beep" {
447 - panic("did not beep!")
448 - }
449 -
450 - if _, err := s.Write([]byte("boop")); err != nil {
451 - panic(err)
452 - }
453 - })
454 -
455 - // connect p1 to p2
456 - if _, err := mn.ConnectPeers(p1, p2); err != nil {
457 - t.Fatal(err)
458 - }
459 -
460 - // talk to p2
461 - h1 := mn.Host(p1)
462 - if h1 == nil {
463 - t.Fatalf("no network for %s", p1)
464 - }
465 -
466 - s, err := h1.NewStream(protocol.TestingID, p2)
467 - if err != nil {
468 - t.Fatal(err)
469 - }
470 -
471 - if _, err := s.Write([]byte("beep")); err != nil {
472 - t.Error(err)
473 - }
474 - b := make([]byte, 4)
475 - if _, err := io.ReadFull(s, b); err != nil {
476 - t.Error(err)
477 - }
478 - if !bytes.Equal(b, []byte("boop")) {
479 - t.Error("bytes mismatch 2")
480 - }
481 -
482 -}
483 -
484 -func TestRateLimiting(t *testing.T) {
485 - rl := NewRatelimiter(10)
486 -
487 - if !within(rl.Limit(10), time.Duration(float32(time.Second)), time.Millisecond/10) {
488 - t.Fail()
489 - }
490 - if !within(rl.Limit(10), time.Duration(float32(time.Second*2)), time.Millisecond) {
491 - t.Fail()
492 - }
493 - if !within(rl.Limit(10), time.Duration(float32(time.Second*3)), time.Millisecond) {
494 - t.Fail()
495 - }
496 -
497 - if within(rl.Limit(10), time.Duration(float32(time.Second*3)), time.Millisecond) {
498 - t.Fail()
499 - }
500 -
501 - rl.UpdateBandwidth(50)
502 - if !within(rl.Limit(75), time.Duration(float32(time.Second)*1.5), time.Millisecond/10) {
503 - t.Fail()
504 - }
505 -
506 - if within(rl.Limit(75), time.Duration(float32(time.Second)*1.5), time.Millisecond/10) {
507 - t.Fail()
508 - }
509 -
510 - rl.UpdateBandwidth(100)
511 - if !within(rl.Limit(1), time.Duration(time.Millisecond*10), time.Millisecond/10) {
512 - t.Fail()
513 - }
514 -
515 - if within(rl.Limit(1), time.Duration(time.Millisecond*10), time.Millisecond/10) {
516 - t.Fail()
517 - }
518 -}
519 -
520 -func within(t1 time.Duration, t2 time.Duration, tolerance time.Duration) bool {
521 - return math.Abs(float64(t1)-float64(t2)) < float64(tolerance)
522 -}
523 -
524 -func TestLimitedStreams(t *testing.T) {
525 - mn, err := FullMeshConnected(context.Background(), 2)
526 - if err != nil {
527 - t.Fatal(err)
528 - }
529 -
530 - var wg sync.WaitGroup
531 - messages := 4
532 - messageSize := 500
533 - handler := func(s inet.Stream) {
534 - b := make([]byte, messageSize)
535 - for i := 0; i < messages; i++ {
536 - if _, err := io.ReadFull(s, b); err != nil {
537 - log.Fatal(err)
538 - }
539 - if !bytes.Equal(b[:4], []byte("ping")) {
540 - log.Fatal("bytes mismatch")
541 - }
542 - wg.Done()
543 - }
544 - s.Close()
545 - }
546 -
547 - hosts := mn.Hosts()
548 - for _, h := range mn.Hosts() {
549 - h.SetStreamHandler(protocol.TestingID, handler)
550 - }
551 -
552 - peers := mn.Peers()
553 - links := mn.LinksBetweenPeers(peers[0], peers[1])
554 - // 1000 byte per second bandwidth
555 - bps := float64(1000)
556 - opts := links[0].Options()
557 - opts.Bandwidth = bps
558 - for _, link := range links {
559 - link.SetOptions(opts)
560 - }
561 -
562 - s, err := hosts[0].NewStream(protocol.TestingID, hosts[1].ID())
563 - if err != nil {
564 - t.Fatal(err)
565 - }
566 -
567 - filler := make([]byte, messageSize-4)
568 - data := append([]byte("ping"), filler...)
569 - before := time.Now()
570 - for i := 0; i < messages; i++ {
571 - wg.Add(1)
572 - if _, err := s.Write(data); err != nil {
573 - panic(err)
574 - }
575 - }
576 -
577 - wg.Wait()
578 - if !within(time.Since(before), time.Duration(time.Second*2), time.Second/3) {
579 - t.Fatal("Expected 2ish seconds but got ", time.Since(before))
580 - }
581 -}
p2p/net/mock/ratelimiter.go deleted
-75
@@ -1,75 +0,0 @@
1 -package mocknet
2 -
3 -import (
4 - "sync"
5 - "time"
6 -)
7 -
8 -// A ratelimiter is used by a link to determine how long to wait before sending
9 -// data given a bandwidth cap.
10 -type ratelimiter struct {
11 - lock sync.Mutex
12 - bandwidth float64 // bytes per nanosecond
13 - allowance float64 // in bytes
14 - maxAllowance float64 // in bytes
15 - lastUpdate time.Time // when allowance was updated last
16 - count int // number of times rate limiting was applied
17 - duration time.Duration // total delay introduced due to rate limiting
18 -}
19 -
20 -// Creates a new ratelimiter with bandwidth (in bytes/sec)
21 -func NewRatelimiter(bandwidth float64) *ratelimiter {
22 - // convert bandwidth to bytes per nanosecond
23 - b := bandwidth / float64(time.Second)
24 - return &ratelimiter{
25 - bandwidth: b,
26 - allowance: 0,
27 - maxAllowance: bandwidth,
28 - lastUpdate: time.Now(),
29 - }
30 -}
31 -
32 -// Changes bandwidth of a ratelimiter and resets its allowance
33 -func (r *ratelimiter) UpdateBandwidth(bandwidth float64) {
34 - r.lock.Lock()
35 - defer r.lock.Unlock()
36 - // Convert bandwidth from bytes/second to bytes/nanosecond
37 - b := bandwidth / float64(time.Second)
38 - r.bandwidth = b
39 - // Reset allowance
40 - r.allowance = 0
41 - r.maxAllowance = bandwidth
42 - r.lastUpdate = time.Now()
43 -}
44 -
45 -// Returns how long to wait before sending data with length 'dataSize' bytes
46 -func (r *ratelimiter) Limit(dataSize int) time.Duration {
47 - r.lock.Lock()
48 - defer r.lock.Unlock()
49 - // update time
50 - var duration time.Duration = time.Duration(0)
51 - if r.bandwidth == 0 {
52 - return duration
53 - }
54 - current := time.Now()
55 - elapsedTime := current.Sub(r.lastUpdate)
56 - r.lastUpdate = current
57 -
58 - allowance := r.allowance + float64(elapsedTime)*r.bandwidth
59 - // allowance can't exceed bandwidth
60 - if allowance > r.maxAllowance {
61 - allowance = r.maxAllowance
62 - }
63 -
64 - allowance -= float64(dataSize)
65 - if allowance < 0 {
66 - // sleep until allowance is back to 0
67 - duration = time.Duration(-allowance / r.bandwidth)
68 - // rate limiting was applied, record stats
69 - r.count++
70 - r.duration += duration
71 - }
72 -
73 - r.allowance = allowance
74 - return duration
75 -}
p2p/net/swarm/addr/addr.go deleted
-275
@@ -1,275 +0,0 @@
1 -package addrutil
2 -
3 -import (
4 - "fmt"
5 -
6 - logging "github.com/ipfs/go-ipfs/vendor/QmQg1J6vikuXF9oDvm4wpdeAUvvkVEKW1EYDw9HhTMnP2b/go-log"
7 -
8 - ma "github.com/ipfs/go-ipfs/Godeps/_workspace/src/github.com/jbenet/go-multiaddr"
9 - manet "github.com/ipfs/go-ipfs/Godeps/_workspace/src/github.com/jbenet/go-multiaddr-net"
10 - context "github.com/ipfs/go-ipfs/Godeps/_workspace/src/golang.org/x/net/context"
11 -)
12 -
13 -var log = logging.Logger("p2p/net/swarm/addr")
14 -
15 -// SupportedTransportStrings is the list of supported transports for the swarm.
16 -// These are strings of encapsulated multiaddr protocols. E.g.:
17 -// /ip4/tcp
18 -var SupportedTransportStrings = []string{
19 - "/ip4/tcp",
20 - "/ip6/tcp",
21 - "/ip4/udp/utp",
22 - "/ip6/udp/utp",
23 - // "/ip4/udp/udt", disabled because the lib doesnt work on arm
24 - // "/ip6/udp/udt", disabled because the lib doesnt work on arm
25 -}
26 -
27 -// SupportedTransportProtocols is the list of supported transports for the swarm.
28 -// These are []ma.Protocol lists. Populated at runtime from SupportedTransportStrings
29 -var SupportedTransportProtocols = [][]ma.Protocol{}
30 -
31 -func init() {
32 - // initialize SupportedTransportProtocols
33 - transports := make([][]ma.Protocol, len(SupportedTransportStrings))
34 - for _, s := range SupportedTransportStrings {
35 - t, err := ma.ProtocolsWithString(s)
36 - if err != nil {
37 - panic(err) // important to fix this in the codebase
38 - }
39 - transports = append(transports, t)
40 - }
41 - SupportedTransportProtocols = transports
42 -}
43 -
44 -// FilterAddrs is a filter that removes certain addresses, according to filter.
45 -// if filter returns true, the address is kept.
46 -func FilterAddrs(a []ma.Multiaddr, filter func(ma.Multiaddr) bool) []ma.Multiaddr {
47 - b := make([]ma.Multiaddr, 0, len(a))
48 - for _, addr := range a {
49 - if filter(addr) {
50 - b = append(b, addr)
51 - }
52 - }
53 - return b
54 -}
55 -
56 -// FilterUsableAddrs removes certain addresses
57 -// from a list. the addresses removed are those known NOT
58 -// to work with our network. Namely, addresses with UTP.
59 -func FilterUsableAddrs(a []ma.Multiaddr) []ma.Multiaddr {
60 - return FilterAddrs(a, func(m ma.Multiaddr) bool {
61 - return AddrUsable(m, false)
62 - })
63 -}
64 -
65 -// AddrOverNonLocalIP returns whether the addr uses a non-local ip link
66 -func AddrOverNonLocalIP(a ma.Multiaddr) bool {
67 - split := ma.Split(a)
68 - if len(split) < 1 {
69 - return false
70 - }
71 - if manet.IsIP6LinkLocal(split[0]) {
72 - return false
73 - }
74 - return true
75 -}
76 -
77 -// AddrUsable returns whether our network can use this addr.
78 -// We only use the transports in SupportedTransportStrings,
79 -// and we do not link local addresses. Loopback is ok
80 -// as we need to be able to connect to multiple ipfs nodes
81 -// in the same machine.
82 -func AddrUsable(a ma.Multiaddr, partial bool) bool {
83 - if a == nil {
84 - return false
85 - }
86 -
87 - if !AddrOverNonLocalIP(a) {
88 - return false
89 - }
90 -
91 - // test the address protocol list is in SupportedTransportProtocols
92 - matches := func(supported, test []ma.Protocol) bool {
93 - if len(test) > len(supported) {
94 - return false
95 - }
96 -
97 - // when partial, it's ok if test < supported.
98 - if !partial && len(supported) != len(test) {
99 - return false
100 - }
101 -
102 - for i := range test {
103 - if supported[i].Code != test[i].Code {
104 - return false
105 - }
106 - }
107 - return true
108 - }
109 -
110 - transport := a.Protocols()
111 - for _, supported := range SupportedTransportProtocols {
112 - if matches(supported, transport) {
113 - return true
114 - }
115 - }
116 -
117 - return false
118 -}
119 -
120 -// ResolveUnspecifiedAddress expands an unspecified ip addresses (/ip4/0.0.0.0, /ip6/::) to
121 -// use the known local interfaces. If ifaceAddr is nil, we request interface addresses
122 -// from the network stack. (this is so you can provide a cached value if resolving many addrs)
123 -func ResolveUnspecifiedAddress(resolve ma.Multiaddr, ifaceAddrs []ma.Multiaddr) ([]ma.Multiaddr, error) {
124 - // split address into its components
125 - split := ma.Split(resolve)
126 -
127 - // if first component (ip) is not unspecified, use it as is.
128 - if !manet.IsIPUnspecified(split[0]) {
129 - return []ma.Multiaddr{resolve}, nil
130 - }
131 -
132 - out := make([]ma.Multiaddr, 0, len(ifaceAddrs))
133 - for _, ia := range ifaceAddrs {
134 - // must match the first protocol to be resolve.
135 - if ia.Protocols()[0].Code != resolve.Protocols()[0].Code {
136 - continue
137 - }
138 -
139 - split[0] = ia
140 - joined := ma.Join(split...)
141 - out = append(out, joined)
142 - log.Debug("adding resolved addr:", resolve, joined, out)
143 - }
144 - if len(out) < 1 {
145 - return nil, fmt.Errorf("failed to resolve: %s", resolve)
146 - }
147 - return out, nil
148 -}
149 -
150 -// ResolveUnspecifiedAddresses expands unspecified ip addresses (/ip4/0.0.0.0, /ip6/::) to
151 -// use the known local interfaces.
152 -func ResolveUnspecifiedAddresses(unspecAddrs, ifaceAddrs []ma.Multiaddr) ([]ma.Multiaddr, error) {
153 -
154 - // todo optimize: only fetch these if we have a "any" addr.
155 - if len(ifaceAddrs) < 1 {
156 - var err error
157 - ifaceAddrs, err = InterfaceAddresses()
158 - if err != nil {
159 - return nil, err
160 - }
161 - // log.Debug("InterfaceAddresses:", ifaceAddrs)
162 - }
163 -
164 - var outputAddrs []ma.Multiaddr
165 - for _, a := range unspecAddrs {
166 - // unspecified?
167 - resolved, err := ResolveUnspecifiedAddress(a, ifaceAddrs)
168 - if err != nil {
169 - continue // optimistic. if we cant resolve anything, we'll know at the bottom.
170 - }
171 - // log.Debug("resolved:", a, resolved)
172 - outputAddrs = append(outputAddrs, resolved...)
173 - }
174 -
175 - if len(outputAddrs) < 1 {
176 - return nil, fmt.Errorf("failed to specify addrs: %s", unspecAddrs)
177 - }
178 -
179 - log.Event(context.TODO(), "interfaceListenAddresses", func() logging.Loggable {
180 - var addrs []string
181 - for _, addr := range outputAddrs {
182 - addrs = append(addrs, addr.String())
183 - }
184 - return logging.Metadata{"addresses": addrs}
185 - }())
186 -
187 - log.Debug("ResolveUnspecifiedAddresses:", unspecAddrs, ifaceAddrs, outputAddrs)
188 - return outputAddrs, nil
189 -}
190 -
191 -// InterfaceAddresses returns a list of addresses associated with local machine
192 -// Note: we do not return link local addresses. IP loopback is ok, because we
193 -// may be connecting to other nodes in the same machine.
194 -func InterfaceAddresses() ([]ma.Multiaddr, error) {
195 - maddrs, err := manet.InterfaceMultiaddrs()
196 - if err != nil {
197 - return nil, err
198 - }
199 - log.Debug("InterfaceAddresses: from manet:", maddrs)
200 -
201 - var out []ma.Multiaddr
202 - for _, a := range maddrs {
203 - if !AddrUsable(a, true) { // partial
204 - // log.Debug("InterfaceAddresses: skipping unusable:", a)
205 - continue
206 - }
207 -
208 - out = append(out, a)
209 - }
210 -
211 - log.Debug("InterfaceAddresses: usable:", out)
212 - return out, nil
213 -}
214 -
215 -// AddrInList returns whether or not an address is part of a list.
216 -// this is useful to check if NAT is happening (or other bugs?)
217 -func AddrInList(addr ma.Multiaddr, list []ma.Multiaddr) bool {
218 - for _, addr2 := range list {
219 - if addr.Equal(addr2) {
220 - return true
221 - }
222 - }
223 - return false
224 -}
225 -
226 -// AddrIsShareableOnWAN returns whether the given address should be shareable on the
227 -// wide area network (wide internet).
228 -func AddrIsShareableOnWAN(addr ma.Multiaddr) bool {
229 - s := ma.Split(addr)
230 - if len(s) < 1 {
231 - return false
232 - }
233 - a := s[0]
234 - if manet.IsIPLoopback(a) || manet.IsIP6LinkLocal(a) || manet.IsIPUnspecified(a) {
235 - return false
236 - }
237 - return manet.IsThinWaist(a)
238 -}
239 -
240 -// WANShareableAddrs filters addresses based on whether they're shareable on WAN
241 -func WANShareableAddrs(inp []ma.Multiaddr) []ma.Multiaddr {
242 - return FilterAddrs(inp, AddrIsShareableOnWAN)
243 -}
244 -
245 -// Subtract filters out all addrs in b from a
246 -func Subtract(a, b []ma.Multiaddr) []ma.Multiaddr {
247 - return FilterAddrs(a, func(m ma.Multiaddr) bool {
248 - for _, bb := range b {
249 - if m.Equal(bb) {
250 - return false
251 - }
252 - }
253 - return true
254 - })
255 -}
256 -
257 -// CheckNATWarning checks if our observed addresses differ. if so,
258 -// informs the user that certain things might not work yet
259 -func CheckNATWarning(observed, expected ma.Multiaddr, listen []ma.Multiaddr) {
260 - if observed.Equal(expected) {
261 - return
262 - }
263 -
264 - if !AddrInList(observed, listen) { // probably a nat
265 - log.Warningf(natWarning, observed, listen)
266 - }
267 -}
268 -
269 -const natWarning = `Remote peer observed our address to be: %s
270 -The local addresses are: %s
271 -Thus, connection is going through NAT, and other connections may fail.
272 -
273 -IPFS NAT traversal is still under development. Please bug us on github or irc to fix this.
274 -Baby steps: http://jbenet.static.s3.amazonaws.com/271dfcf/baby-steps.gif
275 -`
p2p/net/swarm/addr/addr_test.go deleted
-226
@@ -1,226 +0,0 @@
1 -package addrutil
2 -
3 -import (
4 - "testing"
5 -
6 - ma "github.com/ipfs/go-ipfs/Godeps/_workspace/src/github.com/jbenet/go-multiaddr"
7 - manet "github.com/ipfs/go-ipfs/Godeps/_workspace/src/github.com/jbenet/go-multiaddr-net"
8 -)
9 -
10 -func newMultiaddr(t *testing.T, s string) ma.Multiaddr {
11 - maddr, err := ma.NewMultiaddr(s)
12 - if err != nil {
13 - t.Fatal(err)
14 - }
15 - return maddr
16 -}
17 -
18 -func TestFilterAddrs(t *testing.T) {
19 -
20 - bad := []ma.Multiaddr{
21 - newMultiaddr(t, "/ip4/1.2.3.4/udp/1234"), // unreliable
22 - newMultiaddr(t, "/ip4/1.2.3.4/udp/1234/sctp/1234"), // not in manet
23 - newMultiaddr(t, "/ip4/1.2.3.4/udp/1234/udt"), // udt is broken on arm
24 - newMultiaddr(t, "/ip6/fe80::1/tcp/1234"), // link local
25 - newMultiaddr(t, "/ip6/fe80::100/tcp/1234"), // link local
26 - }
27 -
28 - good := []ma.Multiaddr{
29 - newMultiaddr(t, "/ip4/127.0.0.1/tcp/1234"),
30 - newMultiaddr(t, "/ip6/::1/tcp/1234"),
31 - newMultiaddr(t, "/ip4/1.2.3.4/udp/1234/utp"),
32 - }
33 -
34 - goodAndBad := append(good, bad...)
35 -
36 - // test filters
37 -
38 - for _, a := range bad {
39 - if AddrUsable(a, false) {
40 - t.Errorf("addr %s should be unusable", a)
41 - }
42 - }
43 -
44 - for _, a := range good {
45 - if !AddrUsable(a, false) {
46 - t.Errorf("addr %s should be usable", a)
47 - }
48 - }
49 -
50 - subtestAddrsEqual(t, FilterUsableAddrs(bad), []ma.Multiaddr{})
51 - subtestAddrsEqual(t, FilterUsableAddrs(good), good)
52 - subtestAddrsEqual(t, FilterUsableAddrs(goodAndBad), good)
53 -}
54 -
55 -func subtestAddrsEqual(t *testing.T, a, b []ma.Multiaddr) {
56 - if len(a) != len(b) {
57 - t.Error(t)
58 - }
59 -
60 - in := func(addr ma.Multiaddr, l []ma.Multiaddr) bool {
61 - for _, addr2 := range l {
62 - if addr.Equal(addr2) {
63 - return true
64 - }
65 - }
66 - return false
67 - }
68 -
69 - for _, aa := range a {
70 - if !in(aa, b) {
71 - t.Errorf("%s not in %s", aa, b)
72 - }
73 - }
74 -}
75 -
76 -func TestInterfaceAddrs(t *testing.T) {
77 - addrs, err := InterfaceAddresses()
78 - if err != nil {
79 - t.Fatal(err)
80 - }
81 -
82 - if len(addrs) < 1 {
83 - t.Error("no addresses")
84 - }
85 -
86 - for _, a := range addrs {
87 - if manet.IsIP6LinkLocal(a) {
88 - t.Error("should not return ip link local addresses", a)
89 - }
90 - }
91 -
92 - if len(addrs) < 1 {
93 - t.Error("no good interface addrs")
94 - }
95 -}
96 -
97 -func TestResolvingAddrs(t *testing.T) {
98 -
99 - unspec := []ma.Multiaddr{
100 - newMultiaddr(t, "/ip4/0.0.0.0/tcp/1234"),
101 - newMultiaddr(t, "/ip4/1.2.3.4/tcp/1234"),
102 - newMultiaddr(t, "/ip6/::/tcp/1234"),
103 - newMultiaddr(t, "/ip6/::100/tcp/1234"),
104 - }
105 -
106 - iface := []ma.Multiaddr{
107 - newMultiaddr(t, "/ip4/127.0.0.1"),
108 - newMultiaddr(t, "/ip4/10.20.30.40"),
109 - newMultiaddr(t, "/ip6/::1"),
110 - newMultiaddr(t, "/ip6/::f"),
111 - }
112 -
113 - spec := []ma.Multiaddr{
114 - newMultiaddr(t, "/ip4/127.0.0.1/tcp/1234"),
115 - newMultiaddr(t, "/ip4/10.20.30.40/tcp/1234"),
116 - newMultiaddr(t, "/ip4/1.2.3.4/tcp/1234"),
117 - newMultiaddr(t, "/ip6/::1/tcp/1234"),
118 - newMultiaddr(t, "/ip6/::f/tcp/1234"),
119 - newMultiaddr(t, "/ip6/::100/tcp/1234"),
120 - }
121 -
122 - actual, err := ResolveUnspecifiedAddresses(unspec, iface)
123 - if err != nil {
124 - t.Fatal(err)
125 - }
126 -
127 - for i, a := range actual {
128 - if !a.Equal(spec[i]) {
129 - t.Error(a, " != ", spec[i])
130 - }
131 - }
132 -
133 - ip4u := []ma.Multiaddr{newMultiaddr(t, "/ip4/0.0.0.0")}
134 - ip4i := []ma.Multiaddr{newMultiaddr(t, "/ip4/1.2.3.4")}
135 -
136 - ip6u := []ma.Multiaddr{newMultiaddr(t, "/ip6/::")}
137 - ip6i := []ma.Multiaddr{newMultiaddr(t, "/ip6/::1")}
138 -
139 - if _, err := ResolveUnspecifiedAddress(ip4u[0], ip6i); err == nil {
140 - t.Fatal("should have failed")
141 - }
142 - if _, err := ResolveUnspecifiedAddress(ip6u[0], ip4i); err == nil {
143 - t.Fatal("should have failed")
144 - }
145 -
146 - if _, err := ResolveUnspecifiedAddresses(ip6u, ip4i); err == nil {
147 - t.Fatal("should have failed")
148 - }
149 - if _, err := ResolveUnspecifiedAddresses(ip4u, ip6i); err == nil {
150 - t.Fatal("should have failed")
151 - }
152 -
153 -}
154 -
155 -func TestWANShareable(t *testing.T) {
156 -
157 - wanok := []ma.Multiaddr{
158 - newMultiaddr(t, "/ip4/1.2.3.4/tcp/1234"),
159 - newMultiaddr(t, "/ip6/abcd::1/tcp/1234"),
160 - }
161 -
162 - wanbad := []ma.Multiaddr{
163 - newMultiaddr(t, "/ip4/127.0.0.1/tcp/1234"),
164 - newMultiaddr(t, "/ip4/0.0.0.0/tcp/1234"),
165 - newMultiaddr(t, "/ip6/::1/tcp/1234"),
166 - newMultiaddr(t, "/ip6/::/tcp/1234"),
167 - newMultiaddr(t, "/ip6/fe80::1/tcp/1234"),
168 - newMultiaddr(t, "/ip6/fe80::/tcp/1234"),
169 - }
170 -
171 - for _, a := range wanok {
172 - if !AddrIsShareableOnWAN(a) {
173 - t.Error("should be true", a)
174 - }
175 - }
176 -
177 - for _, a := range wanbad {
178 - if AddrIsShareableOnWAN(a) {
179 - t.Error("should be false", a)
180 - }
181 - }
182 -
183 - wanok2 := WANShareableAddrs(wanok)
184 - if len(wanok) != len(wanok2) {
185 - t.Error("should be the same")
186 - }
187 -
188 - wanbad2 := WANShareableAddrs(wanbad)
189 - if len(wanbad2) != 0 {
190 - t.Error("should be zero")
191 - }
192 -}
193 -
194 -func TestSubtract(t *testing.T) {
195 -
196 - a := []ma.Multiaddr{
197 - newMultiaddr(t, "/ip4/127.0.0.1/tcp/1234"),
198 - newMultiaddr(t, "/ip4/0.0.0.0/tcp/1234"),
199 - newMultiaddr(t, "/ip6/::1/tcp/1234"),
200 - newMultiaddr(t, "/ip6/::/tcp/1234"),
201 - newMultiaddr(t, "/ip6/fe80::1/tcp/1234"),
202 - newMultiaddr(t, "/ip6/fe80::/tcp/1234"),
203 - }
204 -
205 - b := []ma.Multiaddr{
206 - newMultiaddr(t, "/ip4/127.0.0.1/tcp/1234"),
207 - newMultiaddr(t, "/ip6/::1/tcp/1234"),
208 - newMultiaddr(t, "/ip6/fe80::1/tcp/1234"),
209 - }
210 -
211 - c1 := []ma.Multiaddr{
212 - newMultiaddr(t, "/ip4/0.0.0.0/tcp/1234"),
213 - newMultiaddr(t, "/ip6/::/tcp/1234"),
214 - newMultiaddr(t, "/ip6/fe80::/tcp/1234"),
215 - }
216 -
217 - c2 := Subtract(a, b)
218 - if len(c1) != len(c2) {
219 - t.Error("should be the same")
220 - }
221 - for i, ca := range c1 {
222 - if !c2[i].Equal(ca) {
223 - t.Error("should be the same", ca, c2[i])
224 - }
225 - }
226 -}
p2p/net/swarm/dial_test.go deleted
-476
@@ -1,476 +0,0 @@
1 -package swarm
2 -
3 -import (
4 - "net"
5 - "sort"
6 - "sync"
7 - "testing"
8 - "time"
9 -
10 - addrutil "github.com/ipfs/go-ipfs/p2p/net/swarm/addr"
11 - peer "github.com/ipfs/go-ipfs/p2p/peer"
12 -
13 - testutil "github.com/ipfs/go-ipfs/util/testutil"
14 - ci "github.com/ipfs/go-ipfs/util/testutil/ci"
15 -
16 - ma "github.com/ipfs/go-ipfs/Godeps/_workspace/src/github.com/jbenet/go-multiaddr"
17 - manet "github.com/ipfs/go-ipfs/Godeps/_workspace/src/github.com/jbenet/go-multiaddr-net"
18 - context "github.com/ipfs/go-ipfs/Godeps/_workspace/src/golang.org/x/net/context"
19 -)
20 -
21 -func acceptAndHang(l net.Listener) {
22 - conns := make([]net.Conn, 0, 10)
23 - for {
24 - c, err := l.Accept()
25 - if err != nil {
26 - break
27 - }
28 - if c != nil {
29 - conns = append(conns, c)
30 - }
31 - }
32 - for _, c := range conns {
33 - c.Close()
34 - }
35 -}
36 -
37 -func TestSimultDials(t *testing.T) {
38 - // t.Skip("skipping for another test")
39 - t.Parallel()
40 -
41 - ctx := context.Background()
42 - swarms := makeSwarms(ctx, t, 2)
43 -
44 - // connect everyone
45 - {
46 - var wg sync.WaitGroup
47 - connect := func(s *Swarm, dst peer.ID, addr ma.Multiaddr) {
48 - // copy for other peer
49 - log.Debugf("TestSimultOpen: connecting: %s --> %s (%s)", s.local, dst, addr)
50 - s.peers.AddAddr(dst, addr, peer.TempAddrTTL)
51 - if _, err := s.Dial(ctx, dst); err != nil {
52 - t.Fatal("error swarm dialing to peer", err)
53 - }
54 - wg.Done()
55 - }
56 -
57 - ifaceAddrs0, err := swarms[0].InterfaceListenAddresses()
58 - if err != nil {
59 - t.Fatal(err)
60 - }
61 - ifaceAddrs1, err := swarms[1].InterfaceListenAddresses()
62 - if err != nil {
63 - t.Fatal(err)
64 - }
65 -
66 - log.Info("Connecting swarms simultaneously.")
67 - for i := 0; i < 10; i++ { // connect 10x for each.
68 - wg.Add(2)
69 - go connect(swarms[0], swarms[1].local, ifaceAddrs1[0])
70 - go connect(swarms[1], swarms[0].local, ifaceAddrs0[0])
71 - }
72 - wg.Wait()
73 - }
74 -
75 - // should still just have 1, at most 2 connections :)
76 - c01l := len(swarms[0].ConnectionsToPeer(swarms[1].local))
77 - if c01l > 2 {
78 - t.Error("0->1 has", c01l)
79 - }
80 - c10l := len(swarms[1].ConnectionsToPeer(swarms[0].local))
81 - if c10l > 2 {
82 - t.Error("1->0 has", c10l)
83 - }
84 -
85 - for _, s := range swarms {
86 - s.Close()
87 - }
88 -}
89 -
90 -func newSilentPeer(t *testing.T) (peer.ID, ma.Multiaddr, net.Listener) {
91 - dst := testutil.RandPeerIDFatal(t)
92 - lst, err := net.Listen("tcp4", "0.0.0.0:0")
93 - if err != nil {
94 - t.Fatal(err)
95 - }
96 - addr, err := manet.FromNetAddr(lst.Addr())
97 - if err != nil {
98 - t.Fatal(err)
99 - }
100 - addrs := []ma.Multiaddr{addr}
101 - addrs, err = addrutil.ResolveUnspecifiedAddresses(addrs, nil)
102 - if err != nil {
103 - t.Fatal(err)
104 - }
105 - t.Log("new silent peer:", dst, addrs[0])
106 - return dst, addrs[0], lst
107 -}
108 -
109 -func TestDialWait(t *testing.T) {
110 - // t.Skip("skipping for another test")
111 - t.Parallel()
112 -
113 - ctx := context.Background()
114 - swarms := makeSwarms(ctx, t, 1)
115 - s1 := swarms[0]
116 - defer s1.Close()
117 -
118 - s1.dialT = time.Millisecond * 300 // lower timeout for tests.
119 - if ci.IsRunning() {
120 - s1.dialT = time.Second
121 - }
122 -
123 - // dial to a non-existent peer.
124 - s2p, s2addr, s2l := newSilentPeer(t)
125 - go acceptAndHang(s2l)
126 - defer s2l.Close()
127 - s1.peers.AddAddr(s2p, s2addr, peer.PermanentAddrTTL)
128 -
129 - before := time.Now()
130 - if c, err := s1.Dial(ctx, s2p); err == nil {
131 - defer c.Close()
132 - t.Fatal("error swarm dialing to unknown peer worked...", err)
133 - } else {
134 - t.Log("correctly got error:", err)
135 - }
136 - duration := time.Now().Sub(before)
137 -
138 - dt := s1.dialT
139 - if duration < dt*dialAttempts {
140 - t.Error("< DialTimeout * dialAttempts not being respected", duration, dt*dialAttempts)
141 - }
142 - if duration > 2*dt*dialAttempts {
143 - t.Error("> 2*DialTimeout * dialAttempts not being respected", duration, 2*dt*dialAttempts)
144 - }
145 -
146 - if !s1.backf.Backoff(s2p) {
147 - t.Error("s2 should now be on backoff")
148 - }
149 -}
150 -
151 -func TestDialBackoff(t *testing.T) {
152 - // t.Skip("skipping for another test")
153 - if ci.IsRunning() {
154 - t.Skip("travis will never have fun with this test")
155 - }
156 -
157 - t.Parallel()
158 -
159 - ctx := context.Background()
160 - swarms := makeSwarms(ctx, t, 2)
161 - s1 := swarms[0]
162 - s2 := swarms[1]
163 - defer s1.Close()
164 - defer s2.Close()
165 -
166 - s1.dialT = time.Second // lower timeout for tests.
167 - s2.dialT = time.Second // lower timeout for tests.
168 -
169 - s2addrs, err := s2.InterfaceListenAddresses()
170 - if err != nil {
171 - t.Fatal(err)
172 - }
173 - s1.peers.AddAddrs(s2.local, s2addrs, peer.PermanentAddrTTL)
174 -
175 - // dial to a non-existent peer.
176 - s3p, s3addr, s3l := newSilentPeer(t)
177 - go acceptAndHang(s3l)
178 - defer s3l.Close()
179 - s1.peers.AddAddr(s3p, s3addr, peer.PermanentAddrTTL)
180 -
181 - // in this test we will:
182 - // 1) dial 10x to each node.
183 - // 2) all dials should hang
184 - // 3) s1->s2 should succeed.
185 - // 4) s1->s3 should not (and should place s3 on backoff)
186 - // 5) disconnect entirely
187 - // 6) dial 10x to each node again
188 - // 7) s3 dials should all return immediately (except 1)
189 - // 8) s2 dials should all hang, and succeed
190 - // 9) last s3 dial ends, unsuccessful
191 -
192 - dialOnlineNode := func(dst peer.ID, times int) <-chan bool {
193 - ch := make(chan bool)
194 - for i := 0; i < times; i++ {
195 - go func() {
196 - if _, err := s1.Dial(ctx, dst); err != nil {
197 - t.Error("error dialing", dst, err)
198 - ch <- false
199 - } else {
200 - ch <- true
201 - }
202 - }()
203 - }
204 - return ch
205 - }
206 -
207 - dialOfflineNode := func(dst peer.ID, times int) <-chan bool {
208 - ch := make(chan bool)
209 - for i := 0; i < times; i++ {
210 - go func() {
211 - if c, err := s1.Dial(ctx, dst); err != nil {
212 - ch <- false
213 - } else {
214 - t.Error("succeeded in dialing", dst)
215 - ch <- true
216 - c.Close()
217 - }
218 - }()
219 - }
220 - return ch
221 - }
222 -
223 - {
224 - // 1) dial 10x to each node.
225 - N := 10
226 - s2done := dialOnlineNode(s2.local, N)
227 - s3done := dialOfflineNode(s3p, N)
228 -
229 - // when all dials should be done by:
230 - dialTimeout1x := time.After(s1.dialT)
231 - // dialTimeout1Ax := time.After(s1.dialT * 2) // dialAttempts)
232 - dialTimeout10Ax := time.After(s1.dialT * 2 * 10) // dialAttempts * 10)
233 -
234 - // 2) all dials should hang
235 - select {
236 - case <-s2done:
237 - t.Error("s2 should not happen immediately")
238 - case <-s3done:
239 - t.Error("s3 should not happen yet")
240 - case <-time.After(time.Millisecond):
241 - // s2 may finish very quickly, so let's get out.
242 - }
243 -
244 - // 3) s1->s2 should succeed.
245 - for i := 0; i < N; i++ {
246 - select {
247 - case r := <-s2done:
248 - if !r {
249 - t.Error("s2 should not fail")
250 - }
251 - case <-s3done:
252 - t.Error("s3 should not happen yet")
253 - case <-dialTimeout1x:
254 - t.Error("s2 took too long")
255 - }
256 - }
257 -
258 - select {
259 - case <-s2done:
260 - t.Error("s2 should have no more")
261 - case <-s3done:
262 - t.Error("s3 should not happen yet")
263 - case <-dialTimeout1x: // let it pass
264 - }
265 -
266 - // 4) s1->s3 should not (and should place s3 on backoff)
267 - // N-1 should finish before dialTimeout1x * 2
268 - for i := 0; i < N; i++ {
269 - select {
270 - case <-s2done:
271 - t.Error("s2 should have no more")
272 - case r := <-s3done:
273 - if r {
274 - t.Error("s3 should not succeed")
275 - }
276 - case <-(dialTimeout1x):
277 - if i < (N - 1) {
278 - t.Fatal("s3 took too long")
279 - }
280 - t.Log("dialTimeout1x * 1.3 hit for last peer")
281 - case <-dialTimeout10Ax:
282 - t.Fatal("s3 took too long")
283 - }
284 - }
285 -
286 - // check backoff state
287 - if s1.backf.Backoff(s2.local) {
288 - t.Error("s2 should not be on backoff")
289 - }
290 - if !s1.backf.Backoff(s3p) {
291 - t.Error("s3 should be on backoff")
292 - }
293 -
294 - // 5) disconnect entirely
295 -
296 - for _, c := range s1.Connections() {
297 - c.Close()
298 - }
299 - for i := 0; i < 100 && len(s1.Connections()) > 0; i++ {
300 - <-time.After(time.Millisecond)
301 - }
302 - if len(s1.Connections()) > 0 {
303 - t.Fatal("s1 conns must exit")
304 - }
305 - }
306 -
307 - {
308 - // 6) dial 10x to each node again
309 - N := 10
310 - s2done := dialOnlineNode(s2.local, N)
311 - s3done := dialOfflineNode(s3p, N)
312 -
313 - // when all dials should be done by:
314 - dialTimeout1x := time.After(s1.dialT)
315 - // dialTimeout1Ax := time.After(s1.dialT * 2) // dialAttempts)
316 - dialTimeout10Ax := time.After(s1.dialT * 2 * 10) // dialAttempts * 10)
317 -
318 - // 7) s3 dials should all return immediately (except 1)
319 - for i := 0; i < N-1; i++ {
320 - select {
321 - case <-s2done:
322 - t.Error("s2 should not succeed yet")
323 - case r := <-s3done:
324 - if r {
325 - t.Error("s3 should not succeed")
326 - }
327 - case <-dialTimeout1x:
328 - t.Fatal("s3 took too long")
329 - }
330 - }
331 -
332 - // 8) s2 dials should all hang, and succeed
333 - for i := 0; i < N; i++ {
334 - select {
335 - case r := <-s2done:
336 - if !r {
337 - t.Error("s2 should succeed")
338 - }
339 - // case <-s3done:
340 - case <-(dialTimeout1x):
341 - t.Fatal("s3 took too long")
342 - }
343 - }
344 -
345 - // 9) the last s3 should return, failed.
346 - select {
347 - case <-s2done:
348 - t.Error("s2 should have no more")
349 - case r := <-s3done:
350 - if r {
351 - t.Error("s3 should not succeed")
352 - }
353 - case <-dialTimeout10Ax:
354 - t.Fatal("s3 took too long")
355 - }
356 -
357 - // check backoff state (the same)
358 - if s1.backf.Backoff(s2.local) {
359 - t.Error("s2 should not be on backoff")
360 - }
361 - if !s1.backf.Backoff(s3p) {
362 - t.Error("s3 should be on backoff")
363 - }
364 -
365 - }
366 -}
367 -
368 -func TestDialBackoffClears(t *testing.T) {
369 - // t.Skip("skipping for another test")
370 - t.Parallel()
371 -
372 - ctx := context.Background()
373 - swarms := makeSwarms(ctx, t, 2)
374 - s1 := swarms[0]
375 - s2 := swarms[1]
376 - defer s1.Close()
377 - defer s2.Close()
378 - s1.dialT = time.Millisecond * 300 // lower timeout for tests.
379 - s2.dialT = time.Millisecond * 300 // lower timeout for tests.
380 - if ci.IsRunning() {
381 - s1.dialT = 2 * time.Second
382 - s2.dialT = 2 * time.Second
383 - }
384 -
385 - // use another address first, that accept and hang on conns
386 - _, s2bad, s2l := newSilentPeer(t)
387 - go acceptAndHang(s2l)
388 - defer s2l.Close()
389 -
390 - // phase 1 -- dial to non-operational addresses
391 - s1.peers.AddAddr(s2.local, s2bad, peer.PermanentAddrTTL)
392 -
393 - before := time.Now()
394 - if c, err := s1.Dial(ctx, s2.local); err == nil {
395 - t.Fatal("dialing to broken addr worked...", err)
396 - defer c.Close()
397 - } else {
398 - t.Log("correctly got error:", err)
399 - }
400 - duration := time.Now().Sub(before)
401 -
402 - dt := s1.dialT
403 - if duration < dt*dialAttempts {
404 - t.Error("< DialTimeout * dialAttempts not being respected", duration, dt*dialAttempts)
405 - }
406 - if duration > 2*dt*dialAttempts {
407 - t.Error("> 2*DialTimeout * dialAttempts not being respected", duration, 2*dt*dialAttempts)
408 - }
409 -
410 - if !s1.backf.Backoff(s2.local) {
411 - t.Error("s2 should now be on backoff")
412 - } else {
413 - t.Log("correctly added to backoff")
414 - }
415 -
416 - // phase 2 -- add the working address. dial should succeed.
417 - ifaceAddrs1, err := swarms[1].InterfaceListenAddresses()
418 - if err != nil {
419 - t.Fatal(err)
420 - }
421 - s1.peers.AddAddrs(s2.local, ifaceAddrs1, peer.PermanentAddrTTL)
422 -
423 - if _, err := s1.Dial(ctx, s2.local); err == nil {
424 - t.Fatal("should have failed to dial backed off peer")
425 - }
426 -
427 - time.Sleep(baseBackoffTime)
428 -
429 - if c, err := s1.Dial(ctx, s2.local); err != nil {
430 - t.Fatal(err)
431 - } else {
432 - c.Close()
433 - t.Log("correctly connected")
434 - }
435 -
436 - if s1.backf.Backoff(s2.local) {
437 - t.Error("s2 should no longer be on backoff")
438 - } else {
439 - t.Log("correctly cleared backoff")
440 - }
441 -}
442 -
443 -func mkAddr(t *testing.T, s string) ma.Multiaddr {
444 - a, err := ma.NewMultiaddr(s)
445 - if err != nil {
446 - t.Fatal(err)
447 - }
448 -
449 - return a
450 -}
451 -
452 -func TestAddressSorting(t *testing.T) {
453 - u1 := mkAddr(t, "/ip4/152.12.23.53/udp/1234/utp")
454 - u2l := mkAddr(t, "/ip4/127.0.0.1/udp/1234/utp")
455 - local := mkAddr(t, "/ip4/127.0.0.1/tcp/1234")
456 - norm := mkAddr(t, "/ip4/6.5.4.3/tcp/1234")
457 -
458 - l := AddrList{local, u1, u2l, norm}
459 - sort.Sort(l)
460 -
461 - if !l[0].Equal(u2l) {
462 - t.Fatal("expected utp local addr to be sorted first: ", l[0])
463 - }
464 -
465 - if !l[1].Equal(u1) {
466 - t.Fatal("expected utp addr to be sorted second")
467 - }
468 -
469 - if !l[2].Equal(local) {
470 - t.Fatal("expected tcp localhost addr thid")
471 - }
472 -
473 - if !l[3].Equal(norm) {
474 - t.Fatal("expected normal addr last")
475 - }
476 -}
p2p/net/swarm/peers_test.go deleted
-72
@@ -1,72 +0,0 @@
1 -package swarm
2 -
3 -import (
4 - "testing"
5 -
6 - peer "github.com/ipfs/go-ipfs/p2p/peer"
7 -
8 - ma "github.com/ipfs/go-ipfs/Godeps/_workspace/src/github.com/jbenet/go-multiaddr"
9 - context "github.com/ipfs/go-ipfs/Godeps/_workspace/src/golang.org/x/net/context"
10 -)
11 -
12 -func TestPeers(t *testing.T) {
13 - // t.Skip("skipping for another test")
14 -
15 - ctx := context.Background()
16 - swarms := makeSwarms(ctx, t, 2)
17 - s1 := swarms[0]
18 - s2 := swarms[1]
19 -
20 - connect := func(s *Swarm, dst peer.ID, addr ma.Multiaddr) {
21 - // TODO: make a DialAddr func.
22 - s.peers.AddAddr(dst, addr, peer.PermanentAddrTTL)
23 - // t.Logf("connections from %s", s.LocalPeer())
24 - // for _, c := range s.ConnectionsToPeer(dst) {
25 - // t.Logf("connection from %s to %s: %v", s.LocalPeer(), dst, c)
26 - // }
27 - // t.Logf("")
28 - if _, err := s.Dial(ctx, dst); err != nil {
29 - t.Fatal("error swarm dialing to peer", err)
30 - }
31 - // t.Log(s.swarm.Dump())
32 - }
33 -
34 - s1GotConn := make(chan struct{}, 0)
35 - s2GotConn := make(chan struct{}, 0)
36 - s1.SetConnHandler(func(c *Conn) {
37 - s1GotConn <- struct{}{}
38 - })
39 - s2.SetConnHandler(func(c *Conn) {
40 - s2GotConn <- struct{}{}
41 - })
42 -
43 - connect(s1, s2.LocalPeer(), s2.ListenAddresses()[0])
44 - <-s2GotConn // have to wait here so the other side catches up.
45 - connect(s2, s1.LocalPeer(), s1.ListenAddresses()[0])
46 -
47 - for i := 0; i < 100; i++ {
48 - connect(s1, s2.LocalPeer(), s2.ListenAddresses()[0])
49 - connect(s2, s1.LocalPeer(), s1.ListenAddresses()[0])
50 - }
51 -
52 - for _, s := range swarms {
53 - log.Infof("%s swarm routing table: %s", s.local, s.Peers())
54 - }
55 -
56 - test := func(s *Swarm) {
57 - expect := 1
58 - actual := len(s.Peers())
59 - if actual != expect {
60 - t.Errorf("%s has %d peers, not %d: %v", s.LocalPeer(), actual, expect, s.Peers())
61 - t.Log(s.swarm.Dump())
62 - }
63 - actual = len(s.Connections())
64 - if actual != expect {
65 - t.Errorf("%s has %d conns, not %d: %v", s.LocalPeer(), actual, expect, s.Connections())
66 - t.Log(s.swarm.Dump())
67 - }
68 - }
69 -
70 - test(s1)
71 - test(s2)
72 -}
p2p/net/swarm/simul_test.go deleted
-77
@@ -1,77 +0,0 @@
1 -package swarm
2 -
3 -import (
4 - "runtime"
5 - "sync"
6 - "testing"
7 - "time"
8 -
9 - peer "github.com/ipfs/go-ipfs/p2p/peer"
10 - ci "github.com/ipfs/go-ipfs/util/testutil/ci"
11 -
12 - ma "github.com/ipfs/go-ipfs/Godeps/_workspace/src/github.com/jbenet/go-multiaddr"
13 - context "github.com/ipfs/go-ipfs/Godeps/_workspace/src/golang.org/x/net/context"
14 -)
15 -
16 -func TestSimultOpen(t *testing.T) {
17 - // t.Skip("skipping for another test")
18 - t.Parallel()
19 -
20 - ctx := context.Background()
21 - swarms := makeSwarms(ctx, t, 2)
22 -
23 - // connect everyone
24 - {
25 - var wg sync.WaitGroup
26 - connect := func(s *Swarm, dst peer.ID, addr ma.Multiaddr) {
27 - // copy for other peer
28 - log.Debugf("TestSimultOpen: connecting: %s --> %s (%s)", s.local, dst, addr)
29 - s.peers.AddAddr(dst, addr, peer.PermanentAddrTTL)
30 - if _, err := s.Dial(ctx, dst); err != nil {
31 - t.Fatal("error swarm dialing to peer", err)
32 - }
33 - wg.Done()
34 - }
35 -
36 - log.Info("Connecting swarms simultaneously.")
37 - wg.Add(2)
38 - go connect(swarms[0], swarms[1].local, swarms[1].ListenAddresses()[0])
39 - go connect(swarms[1], swarms[0].local, swarms[0].ListenAddresses()[0])
40 - wg.Wait()
41 - }
42 -
43 - for _, s := range swarms {
44 - s.Close()
45 - }
46 -}
47 -
48 -func TestSimultOpenMany(t *testing.T) {
49 - // t.Skip("very very slow")
50 -
51 - addrs := 20
52 - rounds := 10
53 - if ci.IsRunning() || runtime.GOOS == "darwin" {
54 - // osx has a limit of 256 file descriptors
55 - addrs = 10
56 - rounds = 5
57 - }
58 - SubtestSwarm(t, addrs, rounds)
59 -}
60 -
61 -func TestSimultOpenFewStress(t *testing.T) {
62 - if testing.Short() {
63 - t.SkipNow()
64 - }
65 - // t.Skip("skipping for another test")
66 - t.Parallel()
67 -
68 - msgs := 40
69 - swarms := 2
70 - rounds := 10
71 - // rounds := 100
72 -
73 - for i := 0; i < rounds; i++ {
74 - SubtestSwarm(t, swarms, msgs)
75 - <-time.After(10 * time.Millisecond)
76 - }
77 -}
p2p/net/swarm/swarm.go deleted
-344
@@ -1,344 +0,0 @@
1 -// package swarm implements a connection muxer with a pair of channels
2 -// to synchronize all network communication.
3 -package swarm
4 -
5 -import (
6 - "fmt"
7 - "sync"
8 - "time"
9 -
10 - metrics "github.com/ipfs/go-ipfs/metrics"
11 - mconn "github.com/ipfs/go-ipfs/metrics/conn"
12 - inet "github.com/ipfs/go-ipfs/p2p/net"
13 - conn "github.com/ipfs/go-ipfs/p2p/net/conn"
14 - filter "github.com/ipfs/go-ipfs/p2p/net/filter"
15 - addrutil "github.com/ipfs/go-ipfs/p2p/net/swarm/addr"
16 - transport "github.com/ipfs/go-ipfs/p2p/net/transport"
17 - peer "github.com/ipfs/go-ipfs/p2p/peer"
18 - logging "github.com/ipfs/go-ipfs/vendor/QmQg1J6vikuXF9oDvm4wpdeAUvvkVEKW1EYDw9HhTMnP2b/go-log"
19 -
20 - ma "github.com/ipfs/go-ipfs/Godeps/_workspace/src/github.com/jbenet/go-multiaddr"
21 - ps "github.com/ipfs/go-ipfs/Godeps/_workspace/src/github.com/jbenet/go-peerstream"
22 - pst "github.com/ipfs/go-ipfs/Godeps/_workspace/src/github.com/jbenet/go-stream-muxer"
23 - psmss "github.com/ipfs/go-ipfs/Godeps/_workspace/src/github.com/jbenet/go-stream-muxer/multistream"
24 - "github.com/ipfs/go-ipfs/Godeps/_workspace/src/github.com/jbenet/goprocess"
25 - goprocessctx "github.com/ipfs/go-ipfs/Godeps/_workspace/src/github.com/jbenet/goprocess/context"
26 - prom "github.com/ipfs/go-ipfs/Godeps/_workspace/src/github.com/prometheus/client_golang/prometheus"
27 - mafilter "github.com/ipfs/go-ipfs/Godeps/_workspace/src/github.com/whyrusleeping/multiaddr-filter"
28 - context "github.com/ipfs/go-ipfs/Godeps/_workspace/src/golang.org/x/net/context"
29 -)
30 -
31 -var log = logging.Logger("swarm2")
32 -
33 -var PSTransport pst.Transport
34 -
35 -var peersTotal = prom.NewGaugeVec(prom.GaugeOpts{
36 - Namespace: "ipfs",
37 - Subsystem: "p2p",
38 - Name: "peers_total",
39 - Help: "Number of connected peers",
40 -}, []string{"peer_id"})
41 -
42 -func init() {
43 - PSTransport = psmss.NewTransport()
44 -}
45 -
46 -// Swarm is a connection muxer, allowing connections to other peers to
47 -// be opened and closed, while still using the same Chan for all
48 -// communication. The Chan sends/receives Messages, which note the
49 -// destination or source Peer.
50 -//
51 -// Uses peerstream.Swarm
52 -type Swarm struct {
53 - swarm *ps.Swarm
54 - local peer.ID
55 - peers peer.Peerstore
56 - connh ConnHandler
57 -
58 - dsync dialsync
59 - backf dialbackoff
60 - dialT time.Duration // mainly for tests
61 -
62 - dialer *conn.Dialer
63 -
64 - notifmu sync.RWMutex
65 - notifs map[inet.Notifiee]ps.Notifiee
66 -
67 - transports []transport.Transport
68 -
69 - // filters for addresses that shouldnt be dialed
70 - Filters *filter.Filters
71 -
72 - // file descriptor rate limited
73 - fdRateLimit chan struct{}
74 -
75 - proc goprocess.Process
76 - ctx context.Context
77 - bwc metrics.Reporter
78 -}
79 -
80 -// NewSwarm constructs a Swarm, with a Chan.
81 -func NewSwarm(ctx context.Context, listenAddrs []ma.Multiaddr,
82 - local peer.ID, peers peer.Peerstore, bwc metrics.Reporter) (*Swarm, error) {
83 -
84 - listenAddrs, err := filterAddrs(listenAddrs)
85 - if err != nil {
86 - return nil, err
87 - }
88 -
89 - wrap := func(c transport.Conn) transport.Conn {
90 - return mconn.WrapConn(bwc, c)
91 - }
92 -
93 - s := &Swarm{
94 - swarm: ps.NewSwarm(PSTransport),
95 - local: local,
96 - peers: peers,
97 - ctx: ctx,
98 - dialT: DialTimeout,
99 - notifs: make(map[inet.Notifiee]ps.Notifiee),
100 - transports: []transport.Transport{
101 - transport.NewTCPTransport(),
102 - transport.NewUtpTransport(),
103 - },
104 - bwc: bwc,
105 - fdRateLimit: make(chan struct{}, concurrentFdDials),
106 - Filters: filter.NewFilters(),
107 - dialer: conn.NewDialer(local, peers.PrivKey(local), wrap),
108 - }
109 -
110 - // configure Swarm
111 - s.proc = goprocessctx.WithContextAndTeardown(ctx, s.teardown)
112 - s.SetConnHandler(nil) // make sure to setup our own conn handler.
113 -
114 - // setup swarm metrics
115 - prom.MustRegisterOrGet(peersTotal)
116 - s.Notify((*metricsNotifiee)(s))
117 -
118 - err = s.setupInterfaces(listenAddrs)
119 - if err != nil {
120 - return nil, err
121 - }
122 -
123 - return s, nil
124 -}
125 -
126 -func (s *Swarm) teardown() error {
127 - return s.swarm.Close()
128 -}
129 -
130 -func (s *Swarm) AddAddrFilter(f string) error {
131 - m, err := mafilter.NewMask(f)
132 - if err != nil {
133 - return err
134 - }
135 -
136 - s.Filters.AddDialFilter(m)
137 - return nil
138 -}
139 -func filterAddrs(listenAddrs []ma.Multiaddr) ([]ma.Multiaddr, error) {
140 - if len(listenAddrs) > 0 {
141 - filtered := addrutil.FilterUsableAddrs(listenAddrs)
142 - if len(filtered) < 1 {
143 - return nil, fmt.Errorf("swarm cannot use any addr in: %s", listenAddrs)
144 - }
145 - listenAddrs = filtered
146 - }
147 - return listenAddrs, nil
148 -}
149 -
150 -func (s *Swarm) Listen(addrs ...ma.Multiaddr) error {
151 - addrs, err := filterAddrs(addrs)
152 - if err != nil {
153 - return err
154 - }
155 -
156 - return s.setupInterfaces(addrs)
157 -}
158 -
159 -// Process returns the Process of the swarm
160 -func (s *Swarm) Process() goprocess.Process {
161 - return s.proc
162 -}
163 -
164 -// Context returns the context of the swarm
165 -func (s *Swarm) Context() context.Context {
166 - return s.ctx
167 -}
168 -
169 -// Close stops the Swarm.
170 -func (s *Swarm) Close() error {
171 - return s.proc.Close()
172 -}
173 -
174 -// StreamSwarm returns the underlying peerstream.Swarm
175 -func (s *Swarm) StreamSwarm() *ps.Swarm {
176 - return s.swarm
177 -}
178 -
179 -// SetConnHandler assigns the handler for new connections.
180 -// See peerstream. You will rarely use this. See SetStreamHandler
181 -func (s *Swarm) SetConnHandler(handler ConnHandler) {
182 -
183 - // handler is nil if user wants to clear the old handler.
184 - if handler == nil {
185 - s.swarm.SetConnHandler(func(psconn *ps.Conn) {
186 - s.connHandler(psconn)
187 - })
188 - return
189 - }
190 -
191 - s.swarm.SetConnHandler(func(psconn *ps.Conn) {
192 - // sc is nil if closed in our handler.
193 - if sc := s.connHandler(psconn); sc != nil {
194 - // call the user's handler. in a goroutine for sync safety.
195 - go handler(sc)
196 - }
197 - })
198 -}
199 -
200 -// SetStreamHandler assigns the handler for new streams.
201 -// See peerstream.
202 -func (s *Swarm) SetStreamHandler(handler inet.StreamHandler) {
203 - s.swarm.SetStreamHandler(func(s *ps.Stream) {
204 - handler(wrapStream(s))
205 - })
206 -}
207 -
208 -// NewStreamWithPeer creates a new stream on any available connection to p
209 -func (s *Swarm) NewStreamWithPeer(p peer.ID) (*Stream, error) {
210 - // if we have no connections, try connecting.
211 - if len(s.ConnectionsToPeer(p)) == 0 {
212 - log.Debug("Swarm: NewStreamWithPeer no connections. Attempting to connect...")
213 - if _, err := s.Dial(s.Context(), p); err != nil {
214 - return nil, err
215 - }
216 - }
217 - log.Debug("Swarm: NewStreamWithPeer...")
218 -
219 - st, err := s.swarm.NewStreamWithGroup(p)
220 - return wrapStream(st), err
221 -}
222 -
223 -// StreamsWithPeer returns all the live Streams to p
224 -func (s *Swarm) StreamsWithPeer(p peer.ID) []*Stream {
225 - return wrapStreams(ps.StreamsWithGroup(p, s.swarm.Streams()))
226 -}
227 -
228 -// ConnectionsToPeer returns all the live connections to p
229 -func (s *Swarm) ConnectionsToPeer(p peer.ID) []*Conn {
230 - return wrapConns(ps.ConnsWithGroup(p, s.swarm.Conns()))
231 -}
232 -
233 -// Connections returns a slice of all connections.
234 -func (s *Swarm) Connections() []*Conn {
235 - return wrapConns(s.swarm.Conns())
236 -}
237 -
238 -// CloseConnection removes a given peer from swarm + closes the connection
239 -func (s *Swarm) CloseConnection(p peer.ID) error {
240 - conns := s.swarm.ConnsWithGroup(p) // boom.
241 - for _, c := range conns {
242 - c.Close()
243 - }
244 - return nil
245 -}
246 -
247 -// Peers returns a copy of the set of peers swarm is connected to.
248 -func (s *Swarm) Peers() []peer.ID {
249 - conns := s.Connections()
250 -
251 - seen := make(map[peer.ID]struct{})
252 - peers := make([]peer.ID, 0, len(conns))
253 - for _, c := range conns {
254 - p := c.RemotePeer()
255 - if _, found := seen[p]; found {
256 - continue
257 - }
258 -
259 - seen[p] = struct{}{}
260 - peers = append(peers, p)
261 - }
262 - return peers
263 -}
264 -
265 -// LocalPeer returns the local peer swarm is associated to.
266 -func (s *Swarm) LocalPeer() peer.ID {
267 - return s.local
268 -}
269 -
270 -// notifyAll sends a signal to all Notifiees
271 -func (s *Swarm) notifyAll(notify func(inet.Notifiee)) {
272 - s.notifmu.RLock()
273 - for f := range s.notifs {
274 - go notify(f)
275 - }
276 - s.notifmu.RUnlock()
277 -}
278 -
279 -// Notify signs up Notifiee to receive signals when events happen
280 -func (s *Swarm) Notify(f inet.Notifiee) {
281 - // wrap with our notifiee, to translate function calls
282 - n := &ps2netNotifee{net: (*Network)(s), not: f}
283 -
284 - s.notifmu.Lock()
285 - s.notifs[f] = n
286 - s.notifmu.Unlock()
287 -
288 - // register for notifications in the peer swarm.
289 - s.swarm.Notify(n)
290 -}
291 -
292 -// StopNotify unregisters Notifiee fromr receiving signals
293 -func (s *Swarm) StopNotify(f inet.Notifiee) {
294 - s.notifmu.Lock()
295 - n, found := s.notifs[f]
296 - if found {
297 - delete(s.notifs, f)
298 - }
299 - s.notifmu.Unlock()
300 -
301 - if found {
302 - s.swarm.StopNotify(n)
303 - }
304 -}
305 -
306 -type ps2netNotifee struct {
307 - net *Network
308 - not inet.Notifiee
309 -}
310 -
311 -func (n *ps2netNotifee) Connected(c *ps.Conn) {
312 - n.not.Connected(n.net, inet.Conn((*Conn)(c)))
313 -}
314 -
315 -func (n *ps2netNotifee) Disconnected(c *ps.Conn) {
316 - n.not.Disconnected(n.net, inet.Conn((*Conn)(c)))
317 -}
318 -
319 -func (n *ps2netNotifee) OpenedStream(s *ps.Stream) {
320 - n.not.OpenedStream(n.net, inet.Stream((*Stream)(s)))
321 -}
322 -
323 -func (n *ps2netNotifee) ClosedStream(s *ps.Stream) {
324 - n.not.ClosedStream(n.net, inet.Stream((*Stream)(s)))
325 -}
326 -
327 -type metricsNotifiee Swarm
328 -
329 -func (nn *metricsNotifiee) Connected(n inet.Network, v inet.Conn) {
330 - peersTotalGauge(n.LocalPeer()).Set(float64(len(n.Conns())))
331 -}
332 -
333 -func (nn *metricsNotifiee) Disconnected(n inet.Network, v inet.Conn) {
334 - peersTotalGauge(n.LocalPeer()).Set(float64(len(n.Conns())))
335 -}
336 -
337 -func (nn *metricsNotifiee) OpenedStream(n inet.Network, v inet.Stream) {}
338 -func (nn *metricsNotifiee) ClosedStream(n inet.Network, v inet.Stream) {}
339 -func (nn *metricsNotifiee) Listen(n inet.Network, a ma.Multiaddr) {}
340 -func (nn *metricsNotifiee) ListenClose(n inet.Network, a ma.Multiaddr) {}
341 -
342 -func peersTotalGauge(id peer.ID) prom.Gauge {
343 - return peersTotal.With(prom.Labels{"peer_id": id.Pretty()})
344 -}
p2p/net/swarm/swarm_addr.go deleted
-39
@@ -1,39 +0,0 @@
1 -package swarm
2 -
3 -import (
4 - conn "github.com/ipfs/go-ipfs/p2p/net/conn"
5 - addrutil "github.com/ipfs/go-ipfs/p2p/net/swarm/addr"
6 -
7 - ma "github.com/ipfs/go-ipfs/Godeps/_workspace/src/github.com/jbenet/go-multiaddr"
8 -)
9 -
10 -// ListenAddresses returns a list of addresses at which this swarm listens.
11 -func (s *Swarm) ListenAddresses() []ma.Multiaddr {
12 - listeners := s.swarm.Listeners()
13 - addrs := make([]ma.Multiaddr, 0, len(listeners))
14 - for _, l := range listeners {
15 - if l2, ok := l.NetListener().(conn.Listener); ok {
16 - addrs = append(addrs, l2.Multiaddr())
17 - }
18 - }
19 - return addrs
20 -}
21 -
22 -// InterfaceListenAddresses returns a list of addresses at which this swarm
23 -// listens. It expands "any interface" addresses (/ip4/0.0.0.0, /ip6/::) to
24 -// use the known local interfaces.
25 -func (s *Swarm) InterfaceListenAddresses() ([]ma.Multiaddr, error) {
26 - return addrutil.ResolveUnspecifiedAddresses(s.ListenAddresses(), nil)
27 -}
28 -
29 -// checkNATWarning checks if our observed addresses differ. if so,
30 -// informs the user that certain things might not work yet
31 -func checkNATWarning(s *Swarm, observed ma.Multiaddr, expected ma.Multiaddr) {
32 - listen, err := s.InterfaceListenAddresses()
33 - if err != nil {
34 - log.Debugf("Error retrieving swarm.InterfaceListenAddresses: %s", err)
35 - return
36 - }
37 -
38 - addrutil.CheckNATWarning(observed, expected, listen)
39 -}
p2p/net/swarm/swarm_addr_test.go deleted
-123
@@ -1,123 +0,0 @@
1 -package swarm
2 -
3 -import (
4 - "testing"
5 -
6 - metrics "github.com/ipfs/go-ipfs/metrics"
7 - addrutil "github.com/ipfs/go-ipfs/p2p/net/swarm/addr"
8 - peer "github.com/ipfs/go-ipfs/p2p/peer"
9 - testutil "github.com/ipfs/go-ipfs/util/testutil"
10 -
11 - ma "github.com/ipfs/go-ipfs/Godeps/_workspace/src/github.com/jbenet/go-multiaddr"
12 - context "github.com/ipfs/go-ipfs/Godeps/_workspace/src/golang.org/x/net/context"
13 -)
14 -
15 -func TestFilterAddrs(t *testing.T) {
16 -
17 - m := func(s string) ma.Multiaddr {
18 - maddr, err := ma.NewMultiaddr(s)
19 - if err != nil {
20 - t.Fatal(err)
21 - }
22 - return maddr
23 - }
24 -
25 - bad := []ma.Multiaddr{
26 - m("/ip4/1.2.3.4/udp/1234"), // unreliable
27 - m("/ip4/1.2.3.4/udp/1234/sctp/1234"), // not in manet
28 - m("/ip4/1.2.3.4/udp/1234/udt"), // udt is broken on arm
29 - m("/ip6/fe80::1/tcp/0"), // link local
30 - m("/ip6/fe80::100/tcp/1234"), // link local
31 - }
32 -
33 - good := []ma.Multiaddr{
34 - m("/ip4/127.0.0.1/tcp/0"),
35 - m("/ip6/::1/tcp/0"),
36 - m("/ip4/1.2.3.4/udp/1234/utp"),
37 - }
38 -
39 - goodAndBad := append(good, bad...)
40 -
41 - // test filters
42 -
43 - for _, a := range bad {
44 - if addrutil.AddrUsable(a, false) {
45 - t.Errorf("addr %s should be unusable", a)
46 - }
47 - }
48 -
49 - for _, a := range good {
50 - if !addrutil.AddrUsable(a, false) {
51 - t.Errorf("addr %s should be usable", a)
52 - }
53 - }
54 -
55 - subtestAddrsEqual(t, addrutil.FilterUsableAddrs(bad), []ma.Multiaddr{})
56 - subtestAddrsEqual(t, addrutil.FilterUsableAddrs(good), good)
57 - subtestAddrsEqual(t, addrutil.FilterUsableAddrs(goodAndBad), good)
58 -
59 - // now test it with swarm
60 -
61 - id, err := testutil.RandPeerID()
62 - if err != nil {
63 - t.Fatal(err)
64 - }
65 -
66 - ps := peer.NewPeerstore()
67 - ctx := context.Background()
68 -
69 - if _, err := NewNetwork(ctx, bad, id, ps, metrics.NewBandwidthCounter()); err == nil {
70 - t.Fatal("should have failed to create swarm")
71 - }
72 -
73 - if _, err := NewNetwork(ctx, goodAndBad, id, ps, metrics.NewBandwidthCounter()); err != nil {
74 - t.Fatal("should have succeeded in creating swarm", err)
75 - }
76 -}
77 -
78 -func subtestAddrsEqual(t *testing.T, a, b []ma.Multiaddr) {
79 - if len(a) != len(b) {
80 - t.Error(t)
81 - }
82 -
83 - in := func(addr ma.Multiaddr, l []ma.Multiaddr) bool {
84 - for _, addr2 := range l {
85 - if addr.Equal(addr2) {
86 - return true
87 - }
88 - }
89 - return false
90 - }
91 -
92 - for _, aa := range a {
93 - if !in(aa, b) {
94 - t.Errorf("%s not in %s", aa, b)
95 - }
96 - }
97 -}
98 -
99 -func TestDialBadAddrs(t *testing.T) {
100 -
101 - m := func(s string) ma.Multiaddr {
102 - maddr, err := ma.NewMultiaddr(s)
103 - if err != nil {
104 - t.Fatal(err)
105 - }
106 - return maddr
107 - }
108 -
109 - ctx := context.Background()
110 - s := makeSwarms(ctx, t, 1)[0]
111 -
112 - test := func(a ma.Multiaddr) {
113 - p := testutil.RandPeerIDFatal(t)
114 - s.peers.AddAddr(p, a, peer.PermanentAddrTTL)
115 - if _, err := s.Dial(ctx, p); err == nil {
116 - t.Error("swarm should not dial: %s", m)
117 - }
118 - }
119 -
120 - test(m("/ip6/fe80::1")) // link local
121 - test(m("/ip6/fe80::100")) // link local
122 - test(m("/ip4/127.0.0.1/udp/1234/utp")) // utp
123 -}
p2p/net/swarm/swarm_conn.go deleted
-141
@@ -1,141 +0,0 @@
1 -package swarm
2 -
3 -import (
4 - "fmt"
5 -
6 - ic "github.com/ipfs/go-ipfs/p2p/crypto"
7 - inet "github.com/ipfs/go-ipfs/p2p/net"
8 - conn "github.com/ipfs/go-ipfs/p2p/net/conn"
9 - peer "github.com/ipfs/go-ipfs/p2p/peer"
10 -
11 - ma "github.com/ipfs/go-ipfs/Godeps/_workspace/src/github.com/jbenet/go-multiaddr"
12 - ps "github.com/ipfs/go-ipfs/Godeps/_workspace/src/github.com/jbenet/go-peerstream"
13 - context "github.com/ipfs/go-ipfs/Godeps/_workspace/src/golang.org/x/net/context"
14 -)
15 -
16 -// a Conn is a simple wrapper around a ps.Conn that also exposes
17 -// some of the methods from the underlying conn.Conn.
18 -// There's **five** "layers" to each connection:
19 -// * 0. the net.Conn - underlying net.Conn (TCP/UDP/UTP/etc)
20 -// * 1. the manet.Conn - provides multiaddr friendly Conn
21 -// * 2. the conn.Conn - provides Peer friendly Conn (inc Secure channel)
22 -// * 3. the peerstream.Conn - provides peerstream / spdysptream happiness
23 -// * 4. the Conn - abstracts everyting out, exposing only key parts of underlying layers
24 -// (I know, this is kinda crazy. it's more historical than a good design. though the
25 -// layers do build up pieces of functionality. and they're all just io.RW :) )
26 -type Conn ps.Conn
27 -
28 -// ConnHandler is called when new conns are opened from remote peers.
29 -// See peerstream.ConnHandler
30 -type ConnHandler func(*Conn)
31 -
32 -func (c *Conn) StreamConn() *ps.Conn {
33 - return (*ps.Conn)(c)
34 -}
35 -
36 -func (c *Conn) RawConn() conn.Conn {
37 - // righly panic if these things aren't true. it is an expected
38 - // invariant that these Conns are all of the typewe expect:
39 - // ps.Conn wrapping a conn.Conn
40 - // if we get something else it is programmer error.
41 - return (*ps.Conn)(c).NetConn().(conn.Conn)
42 -}
43 -
44 -func (c *Conn) String() string {
45 - return fmt.Sprintf("<SwarmConn %s>", c.RawConn())
46 -}
47 -
48 -// LocalMultiaddr is the Multiaddr on this side
49 -func (c *Conn) LocalMultiaddr() ma.Multiaddr {
50 - return c.RawConn().LocalMultiaddr()
51 -}
52 -
53 -// LocalPeer is the Peer on our side of the connection
54 -func (c *Conn) LocalPeer() peer.ID {
55 - return c.RawConn().LocalPeer()
56 -}
57 -
58 -// RemoteMultiaddr is the Multiaddr on the remote side
59 -func (c *Conn) RemoteMultiaddr() ma.Multiaddr {
60 - return c.RawConn().RemoteMultiaddr()
61 -}
62 -
63 -// RemotePeer is the Peer on the remote side
64 -func (c *Conn) RemotePeer() peer.ID {
65 - return c.RawConn().RemotePeer()
66 -}
67 -
68 -// LocalPrivateKey is the public key of the peer on this side
69 -func (c *Conn) LocalPrivateKey() ic.PrivKey {
70 - return c.RawConn().LocalPrivateKey()
71 -}
72 -
73 -// RemotePublicKey is the public key of the peer on the remote side
74 -func (c *Conn) RemotePublicKey() ic.PubKey {
75 - return c.RawConn().RemotePublicKey()
76 -}
77 -
78 -// NewSwarmStream returns a new Stream from this connection
79 -func (c *Conn) NewSwarmStream() (*Stream, error) {
80 - s, err := c.StreamConn().NewStream()
81 - return wrapStream(s), err
82 -}
83 -
84 -// NewStream returns a new Stream from this connection
85 -func (c *Conn) NewStream() (inet.Stream, error) {
86 - s, err := c.NewSwarmStream()
87 - return inet.Stream(s), err
88 -}
89 -
90 -func (c *Conn) Close() error {
91 - return c.StreamConn().Close()
92 -}
93 -
94 -func wrapConn(psc *ps.Conn) (*Conn, error) {
95 - // grab the underlying connection.
96 - if _, ok := psc.NetConn().(conn.Conn); !ok {
97 - // this should never happen. if we see it ocurring it means that we added
98 - // a Listener to the ps.Swarm that is NOT one of our net/conn.Listener.
99 - return nil, fmt.Errorf("swarm connHandler: invalid conn (not a conn.Conn): %s", psc)
100 - }
101 - return (*Conn)(psc), nil
102 -}
103 -
104 -// wrapConns returns a *Conn for all these ps.Conns
105 -func wrapConns(conns1 []*ps.Conn) []*Conn {
106 - conns2 := make([]*Conn, len(conns1))
107 - for i, c1 := range conns1 {
108 - if c2, err := wrapConn(c1); err == nil {
109 - conns2[i] = c2
110 - }
111 - }
112 - return conns2
113 -}
114 -
115 -// newConnSetup does the swarm's "setup" for a connection. returns the underlying
116 -// conn.Conn this method is used by both swarm.Dial and ps.Swarm connHandler
117 -func (s *Swarm) newConnSetup(ctx context.Context, psConn *ps.Conn) (*Conn, error) {
118 -
119 - // wrap with a Conn
120 - sc, err := wrapConn(psConn)
121 - if err != nil {
122 - return nil, err
123 - }
124 -
125 - // if we have a public key, make sure we add it to our peerstore!
126 - // This is an important detail. Otherwise we must fetch the public
127 - // key from the DHT or some other system.
128 - if pk := sc.RemotePublicKey(); pk != nil {
129 - s.peers.AddPubKey(sc.RemotePeer(), pk)
130 - }
131 -
132 - // ok great! we can use it. add it to our group.
133 -
134 - // set the RemotePeer as a group on the conn. this lets us group
135 - // connections in the StreamSwarm by peer, and get a streams from
136 - // any available connection in the group (better multiconn):
137 - // swarm.StreamSwarm().NewStreamWithGroup(remotePeer)
138 - psConn.AddGroup(sc.RemotePeer())
139 -
140 - return sc, nil
141 -}
p2p/net/swarm/swarm_dial.go deleted
-586
@@ -1,586 +0,0 @@
1 -package swarm
2 -
3 -import (
4 - "bytes"
5 - "errors"
6 - "fmt"
7 - "sort"
8 - "sync"
9 - "time"
10 -
11 - "github.com/ipfs/go-ipfs/Godeps/_workspace/src/github.com/jbenet/go-multiaddr-net"
12 - conn "github.com/ipfs/go-ipfs/p2p/net/conn"
13 - addrutil "github.com/ipfs/go-ipfs/p2p/net/swarm/addr"
14 - peer "github.com/ipfs/go-ipfs/p2p/peer"
15 - lgbl "github.com/ipfs/go-ipfs/util/eventlog/loggables"
16 -
17 - ma "github.com/ipfs/go-ipfs/Godeps/_workspace/src/github.com/jbenet/go-multiaddr"
18 - context "github.com/ipfs/go-ipfs/Godeps/_workspace/src/golang.org/x/net/context"
19 -)
20 -
21 -// Diagram of dial sync:
22 -//
23 -// many callers of Dial() synched w. dials many addrs results to callers
24 -// ----------------------\ dialsync use earliest /--------------
25 -// -----------------------\ |----------\ /----------------
26 -// ------------------------>------------<------- >---------<-----------------
27 -// -----------------------| \----x \----------------
28 -// ----------------------| \-----x \---------------
29 -// any may fail if no addr at end
30 -// retry dialAttempt x
31 -
32 -var (
33 - ErrDialBackoff = errors.New("dial backoff")
34 - ErrDialFailed = errors.New("dial attempt failed")
35 - ErrDialToSelf = errors.New("dial to self attempted")
36 -)
37 -
38 -// dialAttempts governs how many times a goroutine will try to dial a given peer.
39 -// Note: this is down to one, as we have _too many dials_ atm. To add back in,
40 -// add loop back in Dial(.)
41 -const dialAttempts = 1
42 -
43 -// number of concurrent outbound dials over transports that consume file descriptors
44 -const concurrentFdDials = 160
45 -
46 -// DialTimeout is the amount of time each dial attempt has. We can think about making
47 -// this larger down the road, or putting more granular timeouts (i.e. within each
48 -// subcomponent of Dial)
49 -var DialTimeout time.Duration = time.Second * 10
50 -
51 -// dialsync is a small object that helps manage ongoing dials.
52 -// this way, if we receive many simultaneous dial requests, one
53 -// can do its thing, while the rest wait.
54 -//
55 -// this interface is so would-be dialers can just:
56 -//
57 -// for {
58 -// c := findConnectionToPeer(peer)
59 -// if c != nil {
60 -// return c
61 -// }
62 -//
63 -// // ok, no connections. should we dial?
64 -// if ok, wait := dialsync.Lock(peer); !ok {
65 -// <-wait // can optionally wait
66 -// continue
67 -// }
68 -// defer dialsync.Unlock(peer)
69 -//
70 -// c := actuallyDial(peer)
71 -// return c
72 -// }
73 -//
74 -type dialsync struct {
75 - // ongoing is a map of tickets for the current peers being dialed.
76 - // this way, we dont kick off N dials simultaneously.
77 - ongoing map[peer.ID]chan struct{}
78 - lock sync.Mutex
79 -}
80 -
81 -// Lock governs the beginning of a dial attempt.
82 -// If there are no ongoing dials, it returns true, and the client is now
83 -// scheduled to dial. Every other goroutine that calls startDial -- with
84 -//the same dst -- will block until client is done. The client MUST call
85 -// ds.Unlock(p) when it is done, to unblock the other callers.
86 -// The client is not reponsible for achieving a successful dial, only for
87 -// reporting the end of the attempt (calling ds.Unlock(p)).
88 -//
89 -// see the example below `dialsync`
90 -func (ds *dialsync) Lock(dst peer.ID) (bool, chan struct{}) {
91 - ds.lock.Lock()
92 - if ds.ongoing == nil { // init if not ready
93 - ds.ongoing = make(map[peer.ID]chan struct{})
94 - }
95 - wait, found := ds.ongoing[dst]
96 - if !found {
97 - ds.ongoing[dst] = make(chan struct{})
98 - }
99 - ds.lock.Unlock()
100 -
101 - if found {
102 - return false, wait
103 - }
104 -
105 - // ok! you're signed up to dial!
106 - return true, nil
107 -}
108 -
109 -// Unlock releases waiters to a dial attempt. see Lock.
110 -// if Unlock(p) is called without calling Lock(p) first, Unlock panics.
111 -func (ds *dialsync) Unlock(dst peer.ID) {
112 - ds.lock.Lock()
113 - wait, found := ds.ongoing[dst]
114 - if !found {
115 - panic("called dialDone with no ongoing dials to peer: " + dst.Pretty())
116 - }
117 -
118 - delete(ds.ongoing, dst) // remove ongoing dial
119 - close(wait) // release everyone else
120 - ds.lock.Unlock()
121 -}
122 -
123 -// dialbackoff is a struct used to avoid over-dialing the same, dead peers.
124 -// Whenever we totally time out on a peer (all three attempts), we add them
125 -// to dialbackoff. Then, whenevers goroutines would _wait_ (dialsync), they
126 -// check dialbackoff. If it's there, they don't wait and exit promptly with
127 -// an error. (the single goroutine that is actually dialing continues to
128 -// dial). If a dial is successful, the peer is removed from backoff.
129 -// Example:
130 -//
131 -// for {
132 -// if ok, wait := dialsync.Lock(p); !ok {
133 -// if backoff.Backoff(p) {
134 -// return errDialFailed
135 -// }
136 -// <-wait
137 -// continue
138 -// }
139 -// defer dialsync.Unlock(p)
140 -// c, err := actuallyDial(p)
141 -// if err != nil {
142 -// dialbackoff.AddBackoff(p)
143 -// continue
144 -// }
145 -// dialbackoff.Clear(p)
146 -// }
147 -//
148 -
149 -type dialbackoff struct {
150 - entries map[peer.ID]*backoffPeer
151 - lock sync.RWMutex
152 -}
153 -
154 -type backoffPeer struct {
155 - tries int
156 - until time.Time
157 -}
158 -
159 -func (db *dialbackoff) init() {
160 - if db.entries == nil {
161 - db.entries = make(map[peer.ID]*backoffPeer)
162 - }
163 -}
164 -
165 -// Backoff returns whether the client should backoff from dialing
166 -// peer p
167 -func (db *dialbackoff) Backoff(p peer.ID) (backoff bool) {
168 - db.lock.Lock()
169 - defer db.lock.Unlock()
170 - db.init()
171 - bp, found := db.entries[p]
172 - if found && time.Now().Before(bp.until) {
173 - return true
174 - }
175 -
176 - return false
177 -}
178 -
179 -const baseBackoffTime = time.Second * 5
180 -const maxBackoffTime = time.Minute * 5
181 -
182 -// AddBackoff lets other nodes know that we've entered backoff with
183 -// peer p, so dialers should not wait unnecessarily. We still will
184 -// attempt to dial with one goroutine, in case we get through.
185 -func (db *dialbackoff) AddBackoff(p peer.ID) {
186 - db.lock.Lock()
187 - defer db.lock.Unlock()
188 - db.init()
189 - bp, ok := db.entries[p]
190 - if !ok {
191 - db.entries[p] = &backoffPeer{
192 - tries: 1,
193 - until: time.Now().Add(baseBackoffTime),
194 - }
195 - return
196 - }
197 -
198 - expTimeAdd := time.Second * time.Duration(bp.tries*bp.tries)
199 - if expTimeAdd > maxBackoffTime {
200 - expTimeAdd = maxBackoffTime
201 - }
202 - bp.until = time.Now().Add(baseBackoffTime + expTimeAdd)
203 - bp.tries++
204 -}
205 -
206 -// Clear removes a backoff record. Clients should call this after a
207 -// successful Dial.
208 -func (db *dialbackoff) Clear(p peer.ID) {
209 - db.lock.Lock()
210 - defer db.lock.Unlock()
211 - db.init()
212 - delete(db.entries, p)
213 -}
214 -
215 -// Dial connects to a peer.
216 -//
217 -// The idea is that the client of Swarm does not need to know what network
218 -// the connection will happen over. Swarm can use whichever it choses.
219 -// This allows us to use various transport protocols, do NAT traversal/relay,
220 -// etc. to achive connection.
221 -func (s *Swarm) Dial(ctx context.Context, p peer.ID) (*Conn, error) {
222 - var logdial = lgbl.Dial("swarm", s.LocalPeer(), p, nil, nil)
223 - if p == s.local {
224 - log.Event(ctx, "swarmDialSelf", logdial)
225 - return nil, ErrDialToSelf
226 - }
227 -
228 - return s.gatedDialAttempt(ctx, p)
229 -}
230 -
231 -func (s *Swarm) bestConnectionToPeer(p peer.ID) *Conn {
232 - cs := s.ConnectionsToPeer(p)
233 - for _, conn := range cs {
234 - if conn != nil { // dump out the first one we find. (TODO pick better)
235 - return conn
236 - }
237 - }
238 - return nil
239 -}
240 -
241 -// gatedDialAttempt is an attempt to dial a node. It is gated by the swarm's
242 -// dial synchronization systems: dialsync and dialbackoff.
243 -func (s *Swarm) gatedDialAttempt(ctx context.Context, p peer.ID) (*Conn, error) {
244 - var logdial = lgbl.Dial("swarm", s.LocalPeer(), p, nil, nil)
245 - defer log.EventBegin(ctx, "swarmDialAttemptSync", logdial).Done()
246 -
247 - // check if we already have an open connection first
248 - conn := s.bestConnectionToPeer(p)
249 - if conn != nil {
250 - return conn, nil
251 - }
252 -
253 - // check if there's an ongoing dial to this peer
254 - if ok, wait := s.dsync.Lock(p); ok {
255 - defer s.dsync.Unlock(p)
256 -
257 - // if this peer has been backed off, lets get out of here
258 - if s.backf.Backoff(p) {
259 - log.Event(ctx, "swarmDialBackoff", logdial)
260 - return nil, ErrDialBackoff
261 - }
262 -
263 - // ok, we have been charged to dial! let's do it.
264 - // if it succeeds, dial will add the conn to the swarm itself.
265 - defer log.EventBegin(ctx, "swarmDialAttemptStart", logdial).Done()
266 - ctxT, cancel := context.WithTimeout(ctx, s.dialT)
267 - conn, err := s.dial(ctxT, p)
268 - cancel()
269 - log.Debugf("dial end %s", conn)
270 - if err != nil {
271 - log.Event(ctx, "swarmDialBackoffAdd", logdial)
272 - s.backf.AddBackoff(p) // let others know to backoff
273 -
274 - // ok, we failed. try again. (if loop is done, our error is output)
275 - return nil, fmt.Errorf("dial attempt failed: %s", err)
276 - }
277 - log.Event(ctx, "swarmDialBackoffClear", logdial)
278 - s.backf.Clear(p) // okay, no longer need to backoff
279 - return conn, nil
280 -
281 - } else {
282 - // we did not dial. we must wait for someone else to dial.
283 -
284 - // check whether we should backoff first...
285 - if s.backf.Backoff(p) {
286 - log.Event(ctx, "swarmDialBackoff", logdial)
287 - return nil, ErrDialBackoff
288 - }
289 -
290 - defer log.EventBegin(ctx, "swarmDialWait", logdial).Done()
291 - select {
292 - case <-wait: // wait for that other dial to finish.
293 -
294 - // see if it worked, OR we got an incoming dial in the meantime...
295 - conn := s.bestConnectionToPeer(p)
296 - if conn != nil {
297 - return conn, nil
298 - }
299 - return nil, ErrDialFailed
300 - case <-ctx.Done(): // or we may have to bail...
301 - return nil, ctx.Err()
302 - }
303 - }
304 -}
305 -
306 -// dial is the actual swarm's dial logic, gated by Dial.
307 -func (s *Swarm) dial(ctx context.Context, p peer.ID) (*Conn, error) {
308 - var logdial = lgbl.Dial("swarm", s.LocalPeer(), p, nil, nil)
309 - if p == s.local {
310 - log.Event(ctx, "swarmDialDoDialSelf", logdial)
311 - return nil, ErrDialToSelf
312 - }
313 - defer log.EventBegin(ctx, "swarmDialDo", logdial).Done()
314 - logdial["dial"] = "failure" // start off with failure. set to "success" at the end.
315 -
316 - sk := s.peers.PrivKey(s.local)
317 - logdial["encrypted"] = (sk != nil) // log wether this will be an encrypted dial or not.
318 - if sk == nil {
319 - // fine for sk to be nil, just log.
320 - log.Debug("Dial not given PrivateKey, so WILL NOT SECURE conn.")
321 - }
322 -
323 - // get remote peer addrs
324 - remoteAddrs := s.peers.Addrs(p)
325 - // make sure we can use the addresses.
326 - remoteAddrs = addrutil.FilterUsableAddrs(remoteAddrs)
327 - // drop out any addrs that would just dial ourselves. use ListenAddresses
328 - // as that is a more authoritative view than localAddrs.
329 - ila, _ := s.InterfaceListenAddresses()
330 - remoteAddrs = addrutil.Subtract(remoteAddrs, ila)
331 - remoteAddrs = addrutil.Subtract(remoteAddrs, s.peers.Addrs(s.local))
332 -
333 - log.Debugf("%s swarm dialing %s -- local:%s remote:%s", s.local, p, s.ListenAddresses(), remoteAddrs)
334 - if len(remoteAddrs) == 0 {
335 - err := errors.New("peer has no addresses")
336 - logdial["error"] = err
337 - return nil, err
338 - }
339 -
340 - remoteAddrs = s.filterAddrs(remoteAddrs)
341 - if len(remoteAddrs) == 0 {
342 - err := errors.New("all adresses for peer have been filtered out")
343 - logdial["error"] = err
344 - return nil, err
345 - }
346 -
347 - // try to get a connection to any addr
348 - connC, err := s.dialAddrs(ctx, p, remoteAddrs)
349 - if err != nil {
350 - logdial["error"] = err
351 - return nil, err
352 - }
353 - logdial["netconn"] = lgbl.NetConn(connC)
354 -
355 - // ok try to setup the new connection.
356 - defer log.EventBegin(ctx, "swarmDialDoSetup", logdial, lgbl.NetConn(connC)).Done()
357 - swarmC, err := dialConnSetup(ctx, s, connC)
358 - if err != nil {
359 - logdial["error"] = err
360 - connC.Close() // close the connection. didn't work out :(
361 - return nil, err
362 - }
363 -
364 - logdial["dial"] = "success"
365 - return swarmC, nil
366 -}
367 -
368 -func (s *Swarm) dialAddrs(ctx context.Context, p peer.ID, remoteAddrs []ma.Multiaddr) (conn.Conn, error) {
369 -
370 - // sort addresses so preferred addresses are dialed sooner
371 - sort.Sort(AddrList(remoteAddrs))
372 -
373 - // try to connect to one of the peer's known addresses.
374 - // we dial concurrently to each of the addresses, which:
375 - // * makes the process faster overall
376 - // * attempts to get the fastest connection available.
377 - // * mitigates the waste of trying bad addresses
378 - log.Debugf("%s swarm dialing %s %s", s.local, p, remoteAddrs)
379 -
380 - ctx, cancel := context.WithCancel(ctx)
381 - defer cancel() // cancel work when we exit func
382 -
383 - conns := make(chan conn.Conn)
384 - errs := make(chan error, len(remoteAddrs))
385 -
386 - // dialSingleAddr is used in the rate-limited async thing below.
387 - dialSingleAddr := func(addr ma.Multiaddr) {
388 - // rebind chans in scope so we can nil them out easily
389 - connsout := conns
390 - errsout := errs
391 -
392 - connC, err := s.dialAddr(ctx, p, addr)
393 - if err != nil {
394 - connsout = nil
395 - } else if connC == nil {
396 - // NOTE: this really should never happen
397 - log.Errorf("failed to dial %s %s and got no error!", p, addr)
398 - err = fmt.Errorf("failed to dial %s %s", p, addr)
399 - connsout = nil
400 - } else {
401 - errsout = nil
402 - }
403 -
404 - // check parent still wants our results
405 - select {
406 - case <-ctx.Done():
407 - if connC != nil {
408 - connC.Close()
409 - }
410 - case errsout <- err:
411 - case connsout <- connC:
412 - }
413 - }
414 -
415 - // this whole thing is in a goroutine so we can use foundConn
416 - // to end early.
417 - go func() {
418 - limiter := make(chan struct{}, 8)
419 - for _, addr := range remoteAddrs {
420 - // returns whatever ratelimiting is acceptable for workerAddr.
421 - // may not rate limit at all.
422 - rl := s.addrDialRateLimit(addr)
423 - select {
424 - case <-ctx.Done(): // our context was cancelled
425 - return
426 - case rl <- struct{}{}:
427 - // take the token, move on
428 - }
429 -
430 - select {
431 - case <-ctx.Done(): // our context was cancelled
432 - return
433 - case limiter <- struct{}{}:
434 - // take the token, move on
435 - }
436 -
437 - go func(rlc <-chan struct{}, a ma.Multiaddr) {
438 - dialSingleAddr(a)
439 - <-limiter
440 - <-rlc
441 - }(rl, addr)
442 - }
443 - }()
444 -
445 - // wair for the results.
446 - exitErr := fmt.Errorf("failed to dial %s", p)
447 - for range remoteAddrs {
448 - select {
449 - case exitErr = <-errs: //
450 - log.Debug("dial error: ", exitErr)
451 - case connC := <-conns:
452 - // take the first + return asap
453 - return connC, nil
454 - case <-ctx.Done():
455 - // break out and return error
456 - break
457 - }
458 - }
459 - return nil, exitErr
460 -}
461 -
462 -func (s *Swarm) dialAddr(ctx context.Context, p peer.ID, addr ma.Multiaddr) (conn.Conn, error) {
463 - log.Debugf("%s swarm dialing %s %s", s.local, p, addr)
464 -
465 - connC, err := s.dialer.Dial(ctx, addr, p)
466 - if err != nil {
467 - return nil, fmt.Errorf("%s --> %s dial attempt failed: %s", s.local, p, err)
468 - }
469 -
470 - // if the connection is not to whom we thought it would be...
471 - remotep := connC.RemotePeer()
472 - if remotep != p {
473 - connC.Close()
474 - return nil, fmt.Errorf("misdial to %s through %s (got %s)", p, addr, remotep)
475 - }
476 -
477 - // if the connection is to ourselves...
478 - // this can happen TONS when Loopback addrs are advertized.
479 - // (this should be caught by two checks above, but let's just make sure.)
480 - if remotep == s.local {
481 - connC.Close()
482 - return nil, fmt.Errorf("misdial to %s through %s (got self)", p, addr)
483 - }
484 -
485 - // success! we got one!
486 - return connC, nil
487 -}
488 -
489 -func (s *Swarm) filterAddrs(addrs []ma.Multiaddr) []ma.Multiaddr {
490 - var out []ma.Multiaddr
491 - for _, a := range addrs {
492 - if !s.Filters.AddrBlocked(a) {
493 - out = append(out, a)
494 - }
495 - }
496 - return out
497 -}
498 -
499 -// dialConnSetup is the setup logic for a connection from the dial side. it
500 -// needs to add the Conn to the StreamSwarm, then run newConnSetup
501 -func dialConnSetup(ctx context.Context, s *Swarm, connC conn.Conn) (*Conn, error) {
502 -
503 - psC, err := s.swarm.AddConn(connC)
504 - if err != nil {
505 - // connC is closed by caller if we fail.
506 - return nil, fmt.Errorf("failed to add conn to ps.Swarm: %s", err)
507 - }
508 -
509 - // ok try to setup the new connection. (newConnSetup will add to group)
510 - swarmC, err := s.newConnSetup(ctx, psC)
511 - if err != nil {
512 - psC.Close() // we need to make sure psC is Closed.
513 - return nil, err
514 - }
515 -
516 - return swarmC, err
517 -}
518 -
519 -// addrDialRateLimit returns a ratelimiting channel for dialing transport
520 -// addrs like a. for example, tcp is fd-ratelimited. utp is not ratelimited.
521 -func (s *Swarm) addrDialRateLimit(a ma.Multiaddr) chan struct{} {
522 - if isFDCostlyTransport(a) {
523 - return s.fdRateLimit
524 - }
525 -
526 - // do not rate limit it at all
527 - return make(chan struct{}, 1)
528 -}
529 -
530 -func isFDCostlyTransport(a ma.Multiaddr) bool {
531 - return isTCPMultiaddr(a)
532 -}
533 -
534 -func isTCPMultiaddr(a ma.Multiaddr) bool {
535 - p := a.Protocols()
536 - return len(p) == 2 && (p[0].Name == "ip4" || p[0].Name == "ip6") && p[1].Name == "tcp"
537 -}
538 -
539 -type AddrList []ma.Multiaddr
540 -
541 -func (al AddrList) Len() int {
542 - return len(al)
543 -}
544 -
545 -func (al AddrList) Swap(i, j int) {
546 - al[i], al[j] = al[j], al[i]
547 -}
548 -
549 -func (al AddrList) Less(i, j int) bool {
550 - a := al[i]
551 - b := al[j]
552 -
553 - // dial localhost addresses next, they should fail immediately
554 - lba := manet.IsIPLoopback(a)
555 - lbb := manet.IsIPLoopback(b)
556 - if lba {
557 - if !lbb {
558 - return true
559 - }
560 - }
561 -
562 - // dial utp and similar 'non-fd-consuming' addresses first
563 - fda := isFDCostlyTransport(a)
564 - fdb := isFDCostlyTransport(b)
565 - if !fda {
566 - if fdb {
567 - return true
568 - }
569 -
570 - // if neither consume fd's, assume equal ordering
571 - return false
572 - }
573 -
574 - // if 'b' doesnt take a file descriptor
575 - if !fdb {
576 - return false
577 - }
578 -
579 - // if 'b' is loopback and both take file descriptors
580 - if lbb {
581 - return false
582 - }
583 -
584 - // for the rest, just sort by bytes
585 - return bytes.Compare(a.Bytes(), b.Bytes()) > 0
586 -}
p2p/net/swarm/swarm_listen.go deleted
-164
@@ -1,164 +0,0 @@
1 -package swarm
2 -
3 -import (
4 - "fmt"
5 -
6 - mconn "github.com/ipfs/go-ipfs/metrics/conn"
7 - inet "github.com/ipfs/go-ipfs/p2p/net"
8 - conn "github.com/ipfs/go-ipfs/p2p/net/conn"
9 - transport "github.com/ipfs/go-ipfs/p2p/net/transport"
10 - lgbl "github.com/ipfs/go-ipfs/util/eventlog/loggables"
11 -
12 - ma "github.com/ipfs/go-ipfs/Godeps/_workspace/src/github.com/jbenet/go-multiaddr"
13 - ps "github.com/ipfs/go-ipfs/Godeps/_workspace/src/github.com/jbenet/go-peerstream"
14 - context "github.com/ipfs/go-ipfs/Godeps/_workspace/src/golang.org/x/net/context"
15 -)
16 -
17 -// Open listeners and reuse-dialers for the given addresses
18 -func (s *Swarm) setupInterfaces(addrs []ma.Multiaddr) error {
19 - errs := make([]error, len(addrs))
20 - var succeeded int
21 - for i, a := range addrs {
22 - tpt := s.transportForAddr(a)
23 - if tpt == nil {
24 - errs[i] = fmt.Errorf("no transport for address: %s", a)
25 - continue
26 - }
27 -
28 - d, err := tpt.Dialer(a, transport.TimeoutOpt(DialTimeout), transport.ReusePorts)
29 - if err != nil {
30 - errs[i] = err
31 - continue
32 - }
33 -
34 - s.dialer.AddDialer(d)
35 -
36 - list, err := tpt.Listen(a)
37 - if err != nil {
38 - errs[i] = err
39 - continue
40 - }
41 -
42 - err = s.addListener(list)
43 - if err != nil {
44 - errs[i] = err
45 - continue
46 - }
47 - succeeded++
48 - }
49 -
50 - for i, e := range errs {
51 - if e != nil {
52 - log.Warning("listen on %s failed: %s", addrs[i], errs[i])
53 - }
54 - }
55 - if succeeded == 0 && len(addrs) > 0 {
56 - return fmt.Errorf("failed to listen on any addresses: %s", errs)
57 - }
58 -
59 - return nil
60 -}
61 -
62 -func (s *Swarm) transportForAddr(a ma.Multiaddr) transport.Transport {
63 - for _, t := range s.transports {
64 - if t.Matches(a) {
65 - return t
66 - }
67 - }
68 -
69 - return nil
70 -}
71 -
72 -func (s *Swarm) addListener(tptlist transport.Listener) error {
73 -
74 - sk := s.peers.PrivKey(s.local)
75 - if sk == nil {
76 - // may be fine for sk to be nil, just log a warning.
77 - log.Warning("Listener not given PrivateKey, so WILL NOT SECURE conns.")
78 - }
79 -
80 - list, err := conn.WrapTransportListener(s.Context(), tptlist, s.local, sk)
81 - if err != nil {
82 - return err
83 - }
84 -
85 - list.SetAddrFilters(s.Filters)
86 -
87 - if cw, ok := list.(conn.ListenerConnWrapper); ok {
88 - cw.SetConnWrapper(func(c transport.Conn) transport.Conn {
89 - return mconn.WrapConn(s.bwc, c)
90 - })
91 - }
92 -
93 - return s.addConnListener(list)
94 -}
95 -
96 -func (s *Swarm) addConnListener(list conn.Listener) error {
97 - // AddListener to the peerstream Listener. this will begin accepting connections
98 - // and streams!
99 - sl, err := s.swarm.AddListener(list)
100 - if err != nil {
101 - return err
102 - }
103 - log.Debugf("Swarm Listeners at %s", s.ListenAddresses())
104 -
105 - maddr := list.Multiaddr()
106 -
107 - // signal to our notifiees on successful conn.
108 - s.notifyAll(func(n inet.Notifiee) {
109 - n.Listen((*Network)(s), maddr)
110 - })
111 -
112 - // go consume peerstream's listen accept errors. note, these ARE errors.
113 - // they may be killing the listener, and if we get _any_ we should be
114 - // fixing this in our conn.Listener (to ignore them or handle them
115 - // differently.)
116 - go func(ctx context.Context, sl *ps.Listener) {
117 -
118 - // signal to our notifiees closing
119 - defer s.notifyAll(func(n inet.Notifiee) {
120 - n.ListenClose((*Network)(s), maddr)
121 - })
122 -
123 - for {
124 - select {
125 - case err, more := <-sl.AcceptErrors():
126 - if !more {
127 - return
128 - }
129 - log.Errorf("swarm listener accept error: %s", err)
130 - case <-ctx.Done():
131 - return
132 - }
133 - }
134 - }(s.Context(), sl)
135 -
136 - return nil
137 -}
138 -
139 -// connHandler is called by the StreamSwarm whenever a new connection is added
140 -// here we configure it slightly. Note that this is sequential, so if anything
141 -// will take a while do it in a goroutine.
142 -// See https://godoc.org/github.com/jbenet/go-peerstream for more information
143 -func (s *Swarm) connHandler(c *ps.Conn) *Conn {
144 - ctx := context.Background()
145 - // this context is for running the handshake, which -- when receiveing connections
146 - // -- we have no bound on beyond what the transport protocol bounds it at.
147 - // note that setup + the handshake are bounded by underlying io.
148 - // (i.e. if TCP or UDP disconnects (or the swarm closes), we're done.
149 - // Q: why not have a shorter handshake? think about an HTTP server on really slow conns.
150 - // as long as the conn is live (TCP says its online), it tries its best. we follow suit.)
151 -
152 - sc, err := s.newConnSetup(ctx, c)
153 - if err != nil {
154 - log.Debug(err)
155 - log.Event(ctx, "newConnHandlerDisconnect", lgbl.NetConn(c.NetConn()), lgbl.Error(err))
156 - c.Close() // boom. close it.
157 - return nil
158 - }
159 -
160 - // if a peer dials us, remove from dial backoff.
161 - s.backf.Clear(sc.RemotePeer())
162 -
163 - return sc
164 -}
p2p/net/swarm/swarm_net.go deleted
-172
@@ -1,172 +0,0 @@
1 -package swarm
2 -
3 -import (
4 - "fmt"
5 -
6 - peer "github.com/ipfs/go-ipfs/p2p/peer"
7 -
8 - metrics "github.com/ipfs/go-ipfs/metrics"
9 - inet "github.com/ipfs/go-ipfs/p2p/net"
10 -
11 - ma "github.com/ipfs/go-ipfs/Godeps/_workspace/src/github.com/jbenet/go-multiaddr"
12 - "github.com/ipfs/go-ipfs/Godeps/_workspace/src/github.com/jbenet/goprocess"
13 - context "github.com/ipfs/go-ipfs/Godeps/_workspace/src/golang.org/x/net/context"
14 -)
15 -
16 -// Network implements the inet.Network interface.
17 -// It is simply a swarm, with a few different functions
18 -// to implement inet.Network.
19 -type Network Swarm
20 -
21 -// NewNetwork constructs a new network and starts listening on given addresses.
22 -func NewNetwork(ctx context.Context, listen []ma.Multiaddr, local peer.ID,
23 - peers peer.Peerstore, bwc metrics.Reporter) (*Network, error) {
24 -
25 - s, err := NewSwarm(ctx, listen, local, peers, bwc)
26 - if err != nil {
27 - return nil, err
28 - }
29 -
30 - return (*Network)(s), nil
31 -}
32 -
33 -// DialPeer attempts to establish a connection to a given peer.
34 -// Respects the context.
35 -func (n *Network) DialPeer(ctx context.Context, p peer.ID) (inet.Conn, error) {
36 - log.Debugf("[%s] network dialing peer [%s]", n.local, p)
37 - sc, err := n.Swarm().Dial(ctx, p)
38 - if err != nil {
39 - return nil, err
40 - }
41 -
42 - log.Debugf("network for %s finished dialing %s", n.local, p)
43 - return inet.Conn(sc), nil
44 -}
45 -
46 -// Process returns the network's Process
47 -func (n *Network) Process() goprocess.Process {
48 - return n.proc
49 -}
50 -
51 -// Swarm returns the network's peerstream.Swarm
52 -func (n *Network) Swarm() *Swarm {
53 - return (*Swarm)(n)
54 -}
55 -
56 -// LocalPeer the network's LocalPeer
57 -func (n *Network) LocalPeer() peer.ID {
58 - return n.Swarm().LocalPeer()
59 -}
60 -
61 -// Peers returns the known peer IDs from the Peerstore
62 -func (n *Network) Peers() []peer.ID {
63 - return n.Swarm().Peers()
64 -}
65 -
66 -// Peers returns the Peerstore, which tracks known peers
67 -func (n *Network) Peerstore() peer.Peerstore {
68 - return n.Swarm().peers
69 -}
70 -
71 -// Conns returns the connected peers
72 -func (n *Network) Conns() []inet.Conn {
73 - conns1 := n.Swarm().Connections()
74 - out := make([]inet.Conn, len(conns1))
75 - for i, c := range conns1 {
76 - out[i] = inet.Conn(c)
77 - }
78 - return out
79 -}
80 -
81 -// ConnsToPeer returns the connections in this Netowrk for given peer.
82 -func (n *Network) ConnsToPeer(p peer.ID) []inet.Conn {
83 - conns1 := n.Swarm().ConnectionsToPeer(p)
84 - out := make([]inet.Conn, len(conns1))
85 - for i, c := range conns1 {
86 - out[i] = inet.Conn(c)
87 - }
88 - return out
89 -}
90 -
91 -// ClosePeer connection to peer
92 -func (n *Network) ClosePeer(p peer.ID) error {
93 - return n.Swarm().CloseConnection(p)
94 -}
95 -
96 -// close is the real teardown function
97 -func (n *Network) close() error {
98 - return n.Swarm().Close()
99 -}
100 -
101 -// Close calls the ContextCloser func
102 -func (n *Network) Close() error {
103 - return n.Swarm().proc.Close()
104 -}
105 -
106 -// Listen tells the network to start listening on given multiaddrs.
107 -func (n *Network) Listen(addrs ...ma.Multiaddr) error {
108 - return n.Swarm().Listen(addrs...)
109 -}
110 -
111 -// ListenAddresses returns a list of addresses at which this network listens.
112 -func (n *Network) ListenAddresses() []ma.Multiaddr {
113 - return n.Swarm().ListenAddresses()
114 -}
115 -
116 -// InterfaceListenAddresses returns a list of addresses at which this network
117 -// listens. It expands "any interface" addresses (/ip4/0.0.0.0, /ip6/::) to
118 -// use the known local interfaces.
119 -func (n *Network) InterfaceListenAddresses() ([]ma.Multiaddr, error) {
120 - return n.Swarm().InterfaceListenAddresses()
121 -}
122 -
123 -// Connectedness returns a state signaling connection capabilities
124 -// For now only returns Connected || NotConnected. Expand into more later.
125 -func (n *Network) Connectedness(p peer.ID) inet.Connectedness {
126 - c := n.Swarm().ConnectionsToPeer(p)
127 - if c != nil && len(c) > 0 {
128 - return inet.Connected
129 - }
130 - return inet.NotConnected
131 -}
132 -
133 -// NewStream returns a new stream to given peer p.
134 -// If there is no connection to p, attempts to create one.
135 -func (n *Network) NewStream(p peer.ID) (inet.Stream, error) {
136 - log.Debugf("[%s] network opening stream to peer [%s]", n.local, p)
137 - s, err := n.Swarm().NewStreamWithPeer(p)
138 - if err != nil {
139 - return nil, err
140 - }
141 -
142 - return inet.Stream(s), nil
143 -}
144 -
145 -// SetHandler sets the protocol handler on the Network's Muxer.
146 -// This operation is threadsafe.
147 -func (n *Network) SetStreamHandler(h inet.StreamHandler) {
148 - n.Swarm().SetStreamHandler(h)
149 -}
150 -
151 -// SetConnHandler sets the conn handler on the Network.
152 -// This operation is threadsafe.
153 -func (n *Network) SetConnHandler(h inet.ConnHandler) {
154 - n.Swarm().SetConnHandler(func(c *Conn) {
155 - h(inet.Conn(c))
156 - })
157 -}
158 -
159 -// String returns a string representation of Network.
160 -func (n *Network) String() string {
161 - return fmt.Sprintf("<Network %s>", n.LocalPeer())
162 -}
163 -
164 -// Notify signs up Notifiee to receive signals when events happen
165 -func (n *Network) Notify(f inet.Notifiee) {
166 - n.Swarm().Notify(f)
167 -}
168 -
169 -// StopNotify unregisters Notifiee fromr receiving signals
170 -func (n *Network) StopNotify(f inet.Notifiee) {
171 - n.Swarm().StopNotify(f)
172 -}
p2p/net/swarm/swarm_net_test.go deleted
-77
@@ -1,77 +0,0 @@
1 -package swarm_test
2 -
3 -import (
4 - "fmt"
5 - "testing"
6 - "time"
7 -
8 - context "github.com/ipfs/go-ipfs/Godeps/_workspace/src/golang.org/x/net/context"
9 - inet "github.com/ipfs/go-ipfs/p2p/net"
10 - testutil "github.com/ipfs/go-ipfs/p2p/test/util"
11 -)
12 -
13 -// TestConnectednessCorrect starts a few networks, connects a few
14 -// and tests Connectedness value is correct.
15 -func TestConnectednessCorrect(t *testing.T) {
16 -
17 - ctx := context.Background()
18 -
19 - nets := make([]inet.Network, 4)
20 - for i := 0; i < 4; i++ {
21 - nets[i] = testutil.GenSwarmNetwork(t, ctx)
22 - }
23 -
24 - // connect 0-1, 0-2, 0-3, 1-2, 2-3
25 -
26 - dial := func(a, b inet.Network) {
27 - testutil.DivulgeAddresses(b, a)
28 - if _, err := a.DialPeer(ctx, b.LocalPeer()); err != nil {
29 - t.Fatalf("Failed to dial: %s", err)
30 - }
31 - }
32 -
33 - dial(nets[0], nets[1])
34 - dial(nets[0], nets[3])
35 - dial(nets[1], nets[2])
36 - dial(nets[3], nets[2])
37 -
38 - // there's something wrong with dial, i think. it's not finishing
39 - // completely. there must be some async stuff.
40 - <-time.After(100 * time.Millisecond)
41 -
42 - // test those connected show up correctly
43 -
44 - // test connected
45 - expectConnectedness(t, nets[0], nets[1], inet.Connected)
46 - expectConnectedness(t, nets[0], nets[3], inet.Connected)
47 - expectConnectedness(t, nets[1], nets[2], inet.Connected)
48 - expectConnectedness(t, nets[3], nets[2], inet.Connected)
49 -
50 - // test not connected
51 - expectConnectedness(t, nets[0], nets[2], inet.NotConnected)
52 - expectConnectedness(t, nets[1], nets[3], inet.NotConnected)
53 -
54 - for _, n := range nets {
55 - n.Close()
56 - }
57 -}
58 -
59 -func expectConnectedness(t *testing.T, a, b inet.Network, expected inet.Connectedness) {
60 - es := "%s is connected to %s, but Connectedness incorrect. %s %s"
61 - if a.Connectedness(b.LocalPeer()) != expected {
62 - t.Errorf(es, a, b, printConns(a), printConns(b))
63 - }
64 -
65 - // test symmetric case
66 - if b.Connectedness(a.LocalPeer()) != expected {
67 - t.Errorf(es, b, a, printConns(b), printConns(a))
68 - }
69 -}
70 -
71 -func printConns(n inet.Network) string {
72 - s := fmt.Sprintf("Connections in %s:\n", n)
73 - for _, c := range n.Conns() {
74 - s = s + fmt.Sprintf("- %s\n", c)
75 - }
76 - return s
77 -}
p2p/net/swarm/swarm_notif_test.go deleted
-210
@@ -1,210 +0,0 @@
1 -package swarm
2 -
3 -import (
4 - "testing"
5 - "time"
6 -
7 - ma "github.com/ipfs/go-ipfs/Godeps/_workspace/src/github.com/jbenet/go-multiaddr"
8 - context "github.com/ipfs/go-ipfs/Godeps/_workspace/src/golang.org/x/net/context"
9 -
10 - inet "github.com/ipfs/go-ipfs/p2p/net"
11 - peer "github.com/ipfs/go-ipfs/p2p/peer"
12 -)
13 -
14 -func TestNotifications(t *testing.T) {
15 - ctx := context.Background()
16 - swarms := makeSwarms(ctx, t, 5)
17 - defer func() {
18 - for _, s := range swarms {
19 - s.Close()
20 - }
21 - }()
22 -
23 - timeout := 5 * time.Second
24 -
25 - // signup notifs
26 - notifiees := make([]*netNotifiee, len(swarms))
27 - for i, swarm := range swarms {
28 - n := newNetNotifiee()
29 - swarm.Notify(n)
30 - notifiees[i] = n
31 - }
32 -
33 - connectSwarms(t, ctx, swarms)
34 -
35 - <-time.After(time.Millisecond)
36 - // should've gotten 5 by now.
37 -
38 - // test everyone got the correct connection opened calls
39 - for i, s := range swarms {
40 - n := notifiees[i]
41 - notifs := make(map[peer.ID][]inet.Conn)
42 - for j, s2 := range swarms {
43 - if i == j {
44 - continue
45 - }
46 -
47 - // this feels a little sketchy, but its probably okay
48 - for len(s.ConnectionsToPeer(s2.LocalPeer())) != len(notifs[s2.LocalPeer()]) {
49 - select {
50 - case c := <-n.connected:
51 - nfp := notifs[c.RemotePeer()]
52 - notifs[c.RemotePeer()] = append(nfp, c)
53 - case <-time.After(timeout):
54 - t.Fatal("timeout")
55 - }
56 - }
57 - }
58 -
59 - for p, cons := range notifs {
60 - expect := s.ConnectionsToPeer(p)
61 - if len(expect) != len(cons) {
62 - t.Fatal("got different number of connections")
63 - }
64 -
65 - for _, c := range cons {
66 - var found bool
67 - for _, c2 := range expect {
68 - if c == c2 {
69 - found = true
70 - break
71 - }
72 - }
73 -
74 - if !found {
75 - t.Fatal("connection not found!")
76 - }
77 - }
78 - }
79 - }
80 -
81 - complement := func(c inet.Conn) (*Swarm, *netNotifiee, *Conn) {
82 - for i, s := range swarms {
83 - for _, c2 := range s.Connections() {
84 - if c.LocalMultiaddr().Equal(c2.RemoteMultiaddr()) &&
85 - c2.LocalMultiaddr().Equal(c.RemoteMultiaddr()) {
86 - return s, notifiees[i], c2
87 - }
88 - }
89 - }
90 - t.Fatal("complementary conn not found", c)
91 - return nil, nil, nil
92 - }
93 -
94 - testOCStream := func(n *netNotifiee, s inet.Stream) {
95 - var s2 inet.Stream
96 - select {
97 - case s2 = <-n.openedStream:
98 - t.Log("got notif for opened stream")
99 - case <-time.After(timeout):
100 - t.Fatal("timeout")
101 - }
102 - if s != s2 {
103 - t.Fatal("got incorrect stream", s.Conn(), s2.Conn())
104 - }
105 -
106 - select {
107 - case s2 = <-n.closedStream:
108 - t.Log("got notif for closed stream")
109 - case <-time.After(timeout):
110 - t.Fatal("timeout")
111 - }
112 - if s != s2 {
113 - t.Fatal("got incorrect stream", s.Conn(), s2.Conn())
114 - }
115 - }
116 -
117 - streams := make(chan inet.Stream)
118 - for _, s := range swarms {
119 - s.SetStreamHandler(func(s inet.Stream) {
120 - streams <- s
121 - s.Close()
122 - })
123 - }
124 -
125 - // open a streams in each conn
126 - for i, s := range swarms {
127 - for _, c := range s.Connections() {
128 - _, n2, _ := complement(c)
129 -
130 - st1, err := c.NewStream()
131 - if err != nil {
132 - t.Error(err)
133 - } else {
134 - st1.Write([]byte("hello"))
135 - st1.Close()
136 - testOCStream(notifiees[i], st1)
137 - st2 := <-streams
138 - testOCStream(n2, st2)
139 - }
140 - }
141 - }
142 -
143 - // close conns
144 - for i, s := range swarms {
145 - n := notifiees[i]
146 - for _, c := range s.Connections() {
147 - _, n2, c2 := complement(c)
148 - c.Close()
149 - c2.Close()
150 -
151 - var c3, c4 inet.Conn
152 - select {
153 - case c3 = <-n.disconnected:
154 - case <-time.After(timeout):
155 - t.Fatal("timeout")
156 - }
157 - if c != c3 {
158 - t.Fatal("got incorrect conn", c, c3)
159 - }
160 -
161 - select {
162 - case c4 = <-n2.disconnected:
163 - case <-time.After(timeout):
164 - t.Fatal("timeout")
165 - }
166 - if c2 != c4 {
167 - t.Fatal("got incorrect conn", c, c2)
168 - }
169 - }
170 - }
171 -}
172 -
173 -type netNotifiee struct {
174 - listen chan ma.Multiaddr
175 - listenClose chan ma.Multiaddr
176 - connected chan inet.Conn
177 - disconnected chan inet.Conn
178 - openedStream chan inet.Stream
179 - closedStream chan inet.Stream
180 -}
181 -
182 -func newNetNotifiee() *netNotifiee {
183 - return &netNotifiee{
184 - listen: make(chan ma.Multiaddr),
185 - listenClose: make(chan ma.Multiaddr),
186 - connected: make(chan inet.Conn),
187 - disconnected: make(chan inet.Conn),
188 - openedStream: make(chan inet.Stream),
189 - closedStream: make(chan inet.Stream),
190 - }
191 -}
192 -
193 -func (nn *netNotifiee) Listen(n inet.Network, a ma.Multiaddr) {
194 - nn.listen <- a
195 -}
196 -func (nn *netNotifiee) ListenClose(n inet.Network, a ma.Multiaddr) {
197 - nn.listenClose <- a
198 -}
199 -func (nn *netNotifiee) Connected(n inet.Network, v inet.Conn) {
200 - nn.connected <- v
201 -}
202 -func (nn *netNotifiee) Disconnected(n inet.Network, v inet.Conn) {
203 - nn.disconnected <- v
204 -}
205 -func (nn *netNotifiee) OpenedStream(n inet.Network, v inet.Stream) {
206 - nn.openedStream <- v
207 -}
208 -func (nn *netNotifiee) ClosedStream(n inet.Network, v inet.Stream) {
209 - nn.closedStream <- v
210 -}
p2p/net/swarm/swarm_stream.go deleted
-54
@@ -1,54 +0,0 @@
1 -package swarm
2 -
3 -import (
4 - inet "github.com/ipfs/go-ipfs/p2p/net"
5 -
6 - ps "github.com/ipfs/go-ipfs/Godeps/_workspace/src/github.com/jbenet/go-peerstream"
7 -)
8 -
9 -// a Stream is a wrapper around a ps.Stream that exposes a way to get
10 -// our Conn and Swarm (instead of just the ps.Conn and ps.Swarm)
11 -type Stream ps.Stream
12 -
13 -// Stream returns the underlying peerstream.Stream
14 -func (s *Stream) Stream() *ps.Stream {
15 - return (*ps.Stream)(s)
16 -}
17 -
18 -// Conn returns the Conn associated with this Stream, as an inet.Conn
19 -func (s *Stream) Conn() inet.Conn {
20 - return s.SwarmConn()
21 -}
22 -
23 -// SwarmConn returns the Conn associated with this Stream, as a *Conn
24 -func (s *Stream) SwarmConn() *Conn {
25 - return (*Conn)(s.Stream().Conn())
26 -}
27 -
28 -// Read reads bytes from a stream.
29 -func (s *Stream) Read(p []byte) (n int, err error) {
30 - return s.Stream().Read(p)
31 -}
32 -
33 -// Write writes bytes to a stream, flushing for each call.
34 -func (s *Stream) Write(p []byte) (n int, err error) {
35 - return s.Stream().Write(p)
36 -}
37 -
38 -// Close closes the stream, indicating this side is finished
39 -// with the stream.
40 -func (s *Stream) Close() error {
41 - return s.Stream().Close()
42 -}
43 -
44 -func wrapStream(pss *ps.Stream) *Stream {
45 - return (*Stream)(pss)
46 -}
47 -
48 -func wrapStreams(st []*ps.Stream) []*Stream {
49 - out := make([]*Stream, len(st))
50 - for i, s := range st {
51 - out[i] = wrapStream(s)
52 - }
53 - return out
54 -}
p2p/net/swarm/swarm_test.go deleted
-339
@@ -1,339 +0,0 @@
1 -package swarm
2 -
3 -import (
4 - "bytes"
5 - "fmt"
6 - "io"
7 - "net"
8 - "sync"
9 - "testing"
10 - "time"
11 -
12 - metrics "github.com/ipfs/go-ipfs/metrics"
13 - inet "github.com/ipfs/go-ipfs/p2p/net"
14 - peer "github.com/ipfs/go-ipfs/p2p/peer"
15 - testutil "github.com/ipfs/go-ipfs/util/testutil"
16 -
17 - ma "github.com/ipfs/go-ipfs/Godeps/_workspace/src/github.com/jbenet/go-multiaddr"
18 - context "github.com/ipfs/go-ipfs/Godeps/_workspace/src/golang.org/x/net/context"
19 -)
20 -
21 -func EchoStreamHandler(stream inet.Stream) {
22 - go func() {
23 - defer stream.Close()
24 -
25 - // pull out the ipfs conn
26 - c := stream.Conn()
27 - log.Infof("%s ponging to %s", c.LocalPeer(), c.RemotePeer())
28 -
29 - buf := make([]byte, 4)
30 -
31 - for {
32 - if _, err := stream.Read(buf); err != nil {
33 - if err != io.EOF {
34 - log.Info("ping receive error:", err)
35 - }
36 - return
37 - }
38 -
39 - if !bytes.Equal(buf, []byte("ping")) {
40 - log.Infof("ping receive error: ping != %s %v", buf, buf)
41 - return
42 - }
43 -
44 - if _, err := stream.Write([]byte("pong")); err != nil {
45 - log.Info("pond send error:", err)
46 - return
47 - }
48 - }
49 - }()
50 -}
51 -
52 -func makeSwarms(ctx context.Context, t *testing.T, num int) []*Swarm {
53 - swarms := make([]*Swarm, 0, num)
54 -
55 - for i := 0; i < num; i++ {
56 - localnp := testutil.RandPeerNetParamsOrFatal(t)
57 -
58 - peerstore := peer.NewPeerstore()
59 - peerstore.AddPubKey(localnp.ID, localnp.PubKey)
60 - peerstore.AddPrivKey(localnp.ID, localnp.PrivKey)
61 -
62 - addrs := []ma.Multiaddr{localnp.Addr}
63 - swarm, err := NewSwarm(ctx, addrs, localnp.ID, peerstore, metrics.NewBandwidthCounter())
64 - if err != nil {
65 - t.Fatal(err)
66 - }
67 -
68 - swarm.SetStreamHandler(EchoStreamHandler)
69 - swarms = append(swarms, swarm)
70 - }
71 -
72 - return swarms
73 -}
74 -
75 -func connectSwarms(t *testing.T, ctx context.Context, swarms []*Swarm) {
76 -
77 - var wg sync.WaitGroup
78 - connect := func(s *Swarm, dst peer.ID, addr ma.Multiaddr) {
79 - // TODO: make a DialAddr func.
80 - s.peers.AddAddr(dst, addr, peer.PermanentAddrTTL)
81 - if _, err := s.Dial(ctx, dst); err != nil {
82 - t.Fatal("error swarm dialing to peer", err)
83 - }
84 - wg.Done()
85 - }
86 -
87 - log.Info("Connecting swarms simultaneously.")
88 - for _, s1 := range swarms {
89 - for _, s2 := range swarms {
90 - if s2.local != s1.local { // don't connect to self.
91 - wg.Add(1)
92 - connect(s1, s2.LocalPeer(), s2.ListenAddresses()[0]) // try the first.
93 - }
94 - }
95 - }
96 - wg.Wait()
97 -
98 - for _, s := range swarms {
99 - log.Infof("%s swarm routing table: %s", s.local, s.Peers())
100 - }
101 -}
102 -
103 -func SubtestSwarm(t *testing.T, SwarmNum int, MsgNum int) {
104 - // t.Skip("skipping for another test")
105 -
106 - ctx := context.Background()
107 - swarms := makeSwarms(ctx, t, SwarmNum)
108 -
109 - // connect everyone
110 - connectSwarms(t, ctx, swarms)
111 -
112 - // ping/pong
113 - for _, s1 := range swarms {
114 - log.Debugf("-------------------------------------------------------")
115 - log.Debugf("%s ping pong round", s1.local)
116 - log.Debugf("-------------------------------------------------------")
117 -
118 - _, cancel := context.WithCancel(ctx)
119 - got := map[peer.ID]int{}
120 - errChan := make(chan error, MsgNum*len(swarms))
121 - streamChan := make(chan *Stream, MsgNum)
122 -
123 - // send out "ping" x MsgNum to every peer
124 - go func() {
125 - defer close(streamChan)
126 -
127 - var wg sync.WaitGroup
128 - send := func(p peer.ID) {
129 - defer wg.Done()
130 -
131 - // first, one stream per peer (nice)
132 - stream, err := s1.NewStreamWithPeer(p)
133 - if err != nil {
134 - errChan <- err
135 - return
136 - }
137 -
138 - // send out ping!
139 - for k := 0; k < MsgNum; k++ { // with k messages
140 - msg := "ping"
141 - log.Debugf("%s %s %s (%d)", s1.local, msg, p, k)
142 - if _, err := stream.Write([]byte(msg)); err != nil {
143 - errChan <- err
144 - continue
145 - }
146 - }
147 -
148 - // read it later
149 - streamChan <- stream
150 - }
151 -
152 - for _, s2 := range swarms {
153 - if s2.local == s1.local {
154 - continue // dont send to self...
155 - }
156 -
157 - wg.Add(1)
158 - go send(s2.local)
159 - }
160 - wg.Wait()
161 - }()
162 -
163 - // receive "pong" x MsgNum from every peer
164 - go func() {
165 - defer close(errChan)
166 - count := 0
167 - countShouldBe := MsgNum * (len(swarms) - 1)
168 - for stream := range streamChan { // one per peer
169 - defer stream.Close()
170 -
171 - // get peer on the other side
172 - p := stream.Conn().RemotePeer()
173 -
174 - // receive pings
175 - msgCount := 0
176 - msg := make([]byte, 4)
177 - for k := 0; k < MsgNum; k++ { // with k messages
178 -
179 - // read from the stream
180 - if _, err := stream.Read(msg); err != nil {
181 - errChan <- err
182 - continue
183 - }
184 -
185 - if string(msg) != "pong" {
186 - errChan <- fmt.Errorf("unexpected message: %s", msg)
187 - continue
188 - }
189 -
190 - log.Debugf("%s %s %s (%d)", s1.local, msg, p, k)
191 - msgCount++
192 - }
193 -
194 - got[p] = msgCount
195 - count += msgCount
196 - }
197 -
198 - if count != countShouldBe {
199 - errChan <- fmt.Errorf("count mismatch: %d != %d", count, countShouldBe)
200 - }
201 - }()
202 -
203 - // check any errors (blocks till consumer is done)
204 - for err := range errChan {
205 - if err != nil {
206 - t.Error(err.Error())
207 - }
208 - }
209 -
210 - log.Debugf("%s got pongs", s1.local)
211 - if (len(swarms) - 1) != len(got) {
212 - t.Errorf("got (%d) less messages than sent (%d).", len(got), len(swarms))
213 - }
214 -
215 - for p, n := range got {
216 - if n != MsgNum {
217 - t.Error("peer did not get all msgs", p, n, "/", MsgNum)
218 - }
219 - }
220 -
221 - cancel()
222 - <-time.After(10 * time.Millisecond)
223 - }
224 -
225 - for _, s := range swarms {
226 - s.Close()
227 - }
228 -}
229 -
230 -func TestSwarm(t *testing.T) {
231 - // t.Skip("skipping for another test")
232 - t.Parallel()
233 -
234 - // msgs := 1000
235 - msgs := 100
236 - swarms := 5
237 - SubtestSwarm(t, swarms, msgs)
238 -}
239 -
240 -func TestBasicSwarm(t *testing.T) {
241 - // t.Skip("skipping for another test")
242 - t.Parallel()
243 -
244 - msgs := 1
245 - swarms := 2
246 - SubtestSwarm(t, swarms, msgs)
247 -}
248 -
249 -func TestConnHandler(t *testing.T) {
250 - // t.Skip("skipping for another test")
251 - t.Parallel()
252 -
253 - ctx := context.Background()
254 - swarms := makeSwarms(ctx, t, 5)
255 -
256 - gotconn := make(chan struct{}, 10)
257 - swarms[0].SetConnHandler(func(conn *Conn) {
258 - gotconn <- struct{}{}
259 - })
260 -
261 - connectSwarms(t, ctx, swarms)
262 -
263 - <-time.After(time.Millisecond)
264 - // should've gotten 5 by now.
265 -
266 - swarms[0].SetConnHandler(nil)
267 -
268 - expect := 4
269 - for i := 0; i < expect; i++ {
270 - select {
271 - case <-time.After(time.Second):
272 - t.Fatal("failed to get connections")
273 - case <-gotconn:
274 - }
275 - }
276 -
277 - select {
278 - case <-gotconn:
279 - t.Fatalf("should have connected to %d swarms", expect)
280 - default:
281 - }
282 -}
283 -
284 -func TestAddrBlocking(t *testing.T) {
285 - ctx := context.Background()
286 - swarms := makeSwarms(ctx, t, 2)
287 -
288 - swarms[0].SetConnHandler(func(conn *Conn) {
289 - t.Fatal("no connections should happen!")
290 - })
291 -
292 - _, block, err := net.ParseCIDR("127.0.0.1/8")
293 - if err != nil {
294 - t.Fatal(err)
295 - }
296 -
297 - swarms[1].Filters.AddDialFilter(block)
298 -
299 - swarms[1].peers.AddAddr(swarms[0].LocalPeer(), swarms[0].ListenAddresses()[0], peer.PermanentAddrTTL)
300 - _, err = swarms[1].Dial(ctx, swarms[0].LocalPeer())
301 - if err == nil {
302 - t.Fatal("dial should have failed")
303 - }
304 -
305 - swarms[0].peers.AddAddr(swarms[1].LocalPeer(), swarms[1].ListenAddresses()[0], peer.PermanentAddrTTL)
306 - _, err = swarms[0].Dial(ctx, swarms[1].LocalPeer())
307 - if err == nil {
308 - t.Fatal("dial should have failed")
309 - }
310 -}
311 -
312 -func TestFilterBounds(t *testing.T) {
313 - ctx := context.Background()
314 - swarms := makeSwarms(ctx, t, 2)
315 -
316 - conns := make(chan struct{}, 8)
317 - swarms[0].SetConnHandler(func(conn *Conn) {
318 - conns <- struct{}{}
319 - })
320 -
321 - // Address that we wont be dialing from
322 - _, block, err := net.ParseCIDR("192.0.0.1/8")
323 - if err != nil {
324 - t.Fatal(err)
325 - }
326 -
327 - // set filter on both sides, shouldnt matter
328 - swarms[1].Filters.AddDialFilter(block)
329 - swarms[0].Filters.AddDialFilter(block)
330 -
331 - connectSwarms(t, ctx, swarms)
332 -
333 - select {
334 - case <-time.After(time.Second):
335 - t.Fatal("should have gotten connection")
336 - case <-conns:
337 - t.Log("got connect")
338 - }
339 -}
p2p/net/transport/reuseport.go deleted
-65
@@ -1,65 +0,0 @@
1 -package transport
2 -
3 -import (
4 - "net"
5 - "os"
6 - "strings"
7 - "syscall"
8 -
9 - reuseport "github.com/ipfs/go-ipfs/Godeps/_workspace/src/github.com/jbenet/go-reuseport"
10 -)
11 -
12 -// envReuseport is the env variable name used to turn off reuse port.
13 -// It default to true.
14 -const envReuseport = "IPFS_REUSEPORT"
15 -
16 -// envReuseportVal stores the value of envReuseport. defaults to true.
17 -var envReuseportVal = true
18 -
19 -func init() {
20 - v := strings.ToLower(os.Getenv(envReuseport))
21 - if v == "false" || v == "f" || v == "0" {
22 - envReuseportVal = false
23 - log.Infof("REUSEPORT disabled (IPFS_REUSEPORT=%s)", v)
24 - }
25 -}
26 -
27 -// reuseportIsAvailable returns whether reuseport is available to be used. This
28 -// is here because we want to be able to turn reuseport on and off selectively.
29 -// For now we use an ENV variable, as this handles our pressing need:
30 -//
31 -// IPFS_REUSEPORT=false ipfs daemon
32 -//
33 -// If this becomes a sought after feature, we could add this to the config.
34 -// In the end, reuseport is a stop-gap.
35 -func ReuseportIsAvailable() bool {
36 - return envReuseportVal && reuseport.Available()
37 -}
38 -
39 -// ReuseErrShouldRetry diagnoses whether to retry after a reuse error.
40 -// if we failed to bind, we should retry. if bind worked and this is a
41 -// real dial error (remote end didnt answer) then we should not retry.
42 -func ReuseErrShouldRetry(err error) bool {
43 - if err == nil {
44 - return false // hey, it worked! no need to retry.
45 - }
46 -
47 - // if it's a network timeout error, it's a legitimate failure.
48 - if nerr, ok := err.(net.Error); ok && nerr.Timeout() {
49 - return false
50 - }
51 -
52 - errno, ok := err.(syscall.Errno)
53 - if !ok { // not an errno? who knows what this is. retry.
54 - return true
55 - }
56 -
57 - switch errno {
58 - case syscall.EADDRINUSE, syscall.EADDRNOTAVAIL:
59 - return true // failure to bind. retry.
60 - case syscall.ECONNREFUSED:
61 - return false // real dial error
62 - default:
63 - return true // optimistically default to retry.
64 - }
65 -}
p2p/net/transport/tcp.go deleted
-236
@@ -1,236 +0,0 @@
1 -package transport
2 -
3 -import (
4 - "fmt"
5 - "net"
6 - "sync"
7 - "time"
8 -
9 - ma "github.com/ipfs/go-ipfs/Godeps/_workspace/src/github.com/jbenet/go-multiaddr"
10 - manet "github.com/ipfs/go-ipfs/Godeps/_workspace/src/github.com/jbenet/go-multiaddr-net"
11 - reuseport "github.com/ipfs/go-ipfs/Godeps/_workspace/src/github.com/jbenet/go-reuseport"
12 - context "github.com/ipfs/go-ipfs/Godeps/_workspace/src/golang.org/x/net/context"
13 - lgbl "github.com/ipfs/go-ipfs/util/eventlog/loggables"
14 -)
15 -
16 -type TcpTransport struct {
17 - dlock sync.Mutex
18 - dialers map[string]Dialer
19 -
20 - llock sync.Mutex
21 - listeners map[string]Listener
22 -}
23 -
24 -func NewTCPTransport() *TcpTransport {
25 - return &TcpTransport{
26 - dialers: make(map[string]Dialer),
27 - listeners: make(map[string]Listener),
28 - }
29 -}
30 -
31 -func (t *TcpTransport) Dialer(laddr ma.Multiaddr, opts ...DialOpt) (Dialer, error) {
32 - t.dlock.Lock()
33 - defer t.dlock.Unlock()
34 - s := laddr.String()
35 - d, found := t.dialers[s]
36 - if found {
37 - return d, nil
38 - }
39 - var base manet.Dialer
40 -
41 - var doReuse bool
42 - for _, o := range opts {
43 - switch o := o.(type) {
44 - case TimeoutOpt:
45 - base.Timeout = time.Duration(o)
46 - case ReuseportOpt:
47 - doReuse = bool(o)
48 - default:
49 - return nil, fmt.Errorf("unrecognized option: %#v", o)
50 - }
51 - }
52 -
53 - tcpd, err := t.newTcpDialer(base, laddr, doReuse)
54 - if err != nil {
55 - return nil, err
56 - }
57 -
58 - t.dialers[s] = tcpd
59 - return tcpd, nil
60 -}
61 -
62 -func (t *TcpTransport) Listen(laddr ma.Multiaddr) (Listener, error) {
63 - t.llock.Lock()
64 - defer t.llock.Unlock()
65 - s := laddr.String()
66 - l, found := t.listeners[s]
67 - if found {
68 - return l, nil
69 - }
70 -
71 - list, err := manetListen(laddr)
72 - if err != nil {
73 - return nil, err
74 - }
75 -
76 - tlist := &tcpListener{
77 - list: list,
78 - transport: t,
79 - }
80 -
81 - t.listeners[s] = tlist
82 - return tlist, nil
83 -}
84 -
85 -func manetListen(addr ma.Multiaddr) (manet.Listener, error) {
86 - network, naddr, err := manet.DialArgs(addr)
87 - if err != nil {
88 - return nil, err
89 - }
90 -
91 - if ReuseportIsAvailable() {
92 - nl, err := reuseport.Listen(network, naddr)
93 - if err == nil {
94 - // hey, it worked!
95 - return manet.WrapNetListener(nl)
96 - }
97 - // reuseport is available, but we failed to listen. log debug, and retry normally.
98 - log.Debugf("reuseport available, but failed to listen: %s %s, %s", network, naddr, err)
99 - }
100 -
101 - // either reuseport not available, or it failed. try normally.
102 - return manet.Listen(addr)
103 -}
104 -
105 -func (t *TcpTransport) Matches(a ma.Multiaddr) bool {
106 - return IsTcpMultiaddr(a)
107 -}
108 -
109 -type tcpDialer struct {
110 - laddr ma.Multiaddr
111 -
112 - doReuse bool
113 -
114 - rd reuseport.Dialer
115 - madialer manet.Dialer
116 -
117 - transport Transport
118 -}
119 -
120 -func (t *TcpTransport) newTcpDialer(base manet.Dialer, laddr ma.Multiaddr, doReuse bool) (*tcpDialer, error) {
121 - // get the local net.Addr manually
122 - la, err := manet.ToNetAddr(laddr)
123 - if err != nil {
124 - return nil, err // something wrong with laddr.
125 - }
126 -
127 - if doReuse && ReuseportIsAvailable() {
128 - rd := reuseport.Dialer{
129 - D: net.Dialer{
130 - LocalAddr: la,
131 - Timeout: base.Timeout,
132 - },
133 - }
134 -
135 - return &tcpDialer{
136 - doReuse: true,
137 - laddr: laddr,
138 - rd: rd,
139 - madialer: base,
140 - transport: t,
141 - }, nil
142 - }
143 -
144 - return &tcpDialer{
145 - doReuse: false,
146 - laddr: laddr,
147 - madialer: base,
148 - transport: t,
149 - }, nil
150 -}
151 -
152 -func (d *tcpDialer) Dial(raddr ma.Multiaddr) (Conn, error) {
153 - var c manet.Conn
154 - var err error
155 - if d.doReuse {
156 - c, err = d.reuseDial(raddr)
157 - } else {
158 - c, err = d.madialer.Dial(raddr)
159 - }
160 -
161 - if err != nil {
162 - return nil, err
163 - }
164 -
165 - return &connWrap{
166 - Conn: c,
167 - transport: d.transport,
168 - }, nil
169 -}
170 -
171 -func (d *tcpDialer) reuseDial(raddr ma.Multiaddr) (manet.Conn, error) {
172 - logdial := lgbl.Dial("conn", "", "", d.laddr, raddr)
173 - rpev := log.EventBegin(context.TODO(), "tptDialReusePort", logdial)
174 -
175 - network, netraddr, err := manet.DialArgs(raddr)
176 - if err != nil {
177 - return nil, err
178 - }
179 -
180 - con, err := d.rd.Dial(network, netraddr)
181 - if err == nil {
182 - logdial["reuseport"] = "success"
183 - rpev.Done()
184 - return manet.WrapNetConn(con)
185 - }
186 -
187 - if !ReuseErrShouldRetry(err) {
188 - logdial["reuseport"] = "failure"
189 - logdial["error"] = err
190 - rpev.Done()
191 - return nil, err
192 - }
193 -
194 - logdial["reuseport"] = "retry"
195 - logdial["error"] = err
196 - rpev.Done()
197 -
198 - return d.madialer.Dial(raddr)
199 -}
200 -
201 -func (d *tcpDialer) Matches(a ma.Multiaddr) bool {
202 - return IsTcpMultiaddr(a)
203 -}
204 -
205 -type tcpListener struct {
206 - list manet.Listener
207 - transport Transport
208 -}
209 -
210 -func (d *tcpListener) Accept() (Conn, error) {
211 - c, err := d.list.Accept()
212 - if err != nil {
213 - return nil, err
214 - }
215 -
216 - return &connWrap{
217 - Conn: c,
218 - transport: d.transport,
219 - }, nil
220 -}
221 -
222 -func (d *tcpListener) Addr() net.Addr {
223 - return d.list.Addr()
224 -}
225 -
226 -func (t *tcpListener) Multiaddr() ma.Multiaddr {
227 - return t.list.Multiaddr()
228 -}
229 -
230 -func (t *tcpListener) NetListener() net.Listener {
231 - return t.list.NetListener()
232 -}
233 -
234 -func (d *tcpListener) Close() error {
235 - return d.list.Close()
236 -}
p2p/net/transport/transport.go deleted
-61
@@ -1,61 +0,0 @@
1 -package transport
2 -
3 -import (
4 - "net"
5 - "time"
6 -
7 - ma "github.com/ipfs/go-ipfs/Godeps/_workspace/src/github.com/jbenet/go-multiaddr"
8 - manet "github.com/ipfs/go-ipfs/Godeps/_workspace/src/github.com/jbenet/go-multiaddr-net"
9 - logging "github.com/ipfs/go-ipfs/vendor/QmQg1J6vikuXF9oDvm4wpdeAUvvkVEKW1EYDw9HhTMnP2b/go-log"
10 -)
11 -
12 -var log = logging.Logger("transport")
13 -
14 -type Conn interface {
15 - manet.Conn
16 -
17 - Transport() Transport
18 -}
19 -
20 -type Transport interface {
21 - Dialer(laddr ma.Multiaddr, opts ...DialOpt) (Dialer, error)
22 - Listen(laddr ma.Multiaddr) (Listener, error)
23 - Matches(ma.Multiaddr) bool
24 -}
25 -
26 -type Dialer interface {
27 - Dial(raddr ma.Multiaddr) (Conn, error)
28 - Matches(ma.Multiaddr) bool
29 -}
30 -
31 -type Listener interface {
32 - Accept() (Conn, error)
33 - Close() error
34 - Addr() net.Addr
35 - Multiaddr() ma.Multiaddr
36 -}
37 -
38 -type connWrap struct {
39 - manet.Conn
40 - transport Transport
41 -}
42 -
43 -func (cw *connWrap) Transport() Transport {
44 - return cw.transport
45 -}
46 -
47 -type DialOpt interface{}
48 -type TimeoutOpt time.Duration
49 -type ReuseportOpt bool
50 -
51 -var ReusePorts ReuseportOpt = true
52 -
53 -func IsTcpMultiaddr(a ma.Multiaddr) bool {
54 - p := a.Protocols()
55 - return len(p) == 2 && (p[0].Name == "ip4" || p[0].Name == "ip6") && p[1].Name == "tcp"
56 -}
57 -
58 -func IsUtpMultiaddr(a ma.Multiaddr) bool {
59 - p := a.Protocols()
60 - return len(p) == 3 && p[2].Name == "utp"
61 -}
p2p/net/transport/utp.go deleted
-148
@@ -1,148 +0,0 @@
1 -package transport
2 -
3 -import (
4 - "net"
5 - "sync"
6 -
7 - utp "github.com/ipfs/go-ipfs/Godeps/_workspace/src/github.com/anacrolix/utp"
8 - ma "github.com/ipfs/go-ipfs/Godeps/_workspace/src/github.com/jbenet/go-multiaddr"
9 - manet "github.com/ipfs/go-ipfs/Godeps/_workspace/src/github.com/jbenet/go-multiaddr-net"
10 - mautp "github.com/ipfs/go-ipfs/Godeps/_workspace/src/github.com/jbenet/go-multiaddr-net/utp"
11 -)
12 -
13 -type UtpTransport struct {
14 - sockLock sync.Mutex
15 - sockets map[string]*UtpSocket
16 -}
17 -
18 -func NewUtpTransport() *UtpTransport {
19 - return &UtpTransport{
20 - sockets: make(map[string]*UtpSocket),
21 - }
22 -}
23 -
24 -func (d *UtpTransport) Matches(a ma.Multiaddr) bool {
25 - p := a.Protocols()
26 - return len(p) == 3 && p[2].Name == "utp"
27 -}
28 -
29 -type UtpSocket struct {
30 - s *utp.Socket
31 - laddr ma.Multiaddr
32 - transport Transport
33 -}
34 -
35 -func (t *UtpTransport) Listen(laddr ma.Multiaddr) (Listener, error) {
36 - t.sockLock.Lock()
37 - defer t.sockLock.Unlock()
38 - s, ok := t.sockets[laddr.String()]
39 - if ok {
40 - return s, nil
41 - }
42 -
43 - ns, err := t.newConn(laddr)
44 - if err != nil {
45 - return nil, err
46 - }
47 -
48 - t.sockets[laddr.String()] = ns
49 - return ns, nil
50 -}
51 -
52 -func (t *UtpTransport) Dialer(laddr ma.Multiaddr, opts ...DialOpt) (Dialer, error) {
53 - t.sockLock.Lock()
54 - defer t.sockLock.Unlock()
55 - s, ok := t.sockets[laddr.String()]
56 - if ok {
57 - return s, nil
58 - }
59 -
60 - ns, err := t.newConn(laddr, opts...)
61 - if err != nil {
62 - return nil, err
63 - }
64 -
65 - t.sockets[laddr.String()] = ns
66 - return ns, nil
67 -}
68 -
69 -func (t *UtpTransport) newConn(addr ma.Multiaddr, opts ...DialOpt) (*UtpSocket, error) {
70 - network, netaddr, err := manet.DialArgs(addr)
71 - if err != nil {
72 - return nil, err
73 - }
74 -
75 - s, err := utp.NewSocket("udp"+network[3:], netaddr)
76 - if err != nil {
77 - return nil, err
78 - }
79 -
80 - laddr, err := manet.FromNetAddr(mautp.MakeAddr(s.LocalAddr()))
81 - if err != nil {
82 - return nil, err
83 - }
84 -
85 - return &UtpSocket{
86 - s: s,
87 - laddr: laddr,
88 - transport: t,
89 - }, nil
90 -}
91 -
92 -func (s *UtpSocket) Dial(raddr ma.Multiaddr) (Conn, error) {
93 - _, addr, err := manet.DialArgs(raddr)
94 - if err != nil {
95 - return nil, err
96 - }
97 -
98 - con, err := s.s.Dial(addr)
99 - if err != nil {
100 - return nil, err
101 - }
102 -
103 - mnc, err := manet.WrapNetConn(&mautp.Conn{Conn: con})
104 - if err != nil {
105 - return nil, err
106 - }
107 -
108 - return &connWrap{
109 - Conn: mnc,
110 - transport: s.transport,
111 - }, nil
112 -}
113 -
114 -func (s *UtpSocket) Accept() (Conn, error) {
115 - c, err := s.s.Accept()
116 - if err != nil {
117 - return nil, err
118 - }
119 -
120 - mnc, err := manet.WrapNetConn(&mautp.Conn{Conn: c})
121 - if err != nil {
122 - return nil, err
123 - }
124 -
125 - return &connWrap{
126 - Conn: mnc,
127 - transport: s.transport,
128 - }, nil
129 -}
130 -
131 -func (s *UtpSocket) Matches(a ma.Multiaddr) bool {
132 - p := a.Protocols()
133 - return len(p) == 3 && p[2].Name == "utp"
134 -}
135 -
136 -func (t *UtpSocket) Close() error {
137 - return t.s.Close()
138 -}
139 -
140 -func (t *UtpSocket) Addr() net.Addr {
141 - return t.s.Addr()
142 -}
143 -
144 -func (t *UtpSocket) Multiaddr() ma.Multiaddr {
145 - return t.laddr
146 -}
147 -
148 -var _ Transport = (*UtpTransport)(nil)
p2p/peer/addr/addrsrcs.go deleted
-70
@@ -1,70 +0,0 @@
1 -// Package addr provides utility functions to handle peer addresses.
2 -package addr
3 -
4 -import (
5 - ma "github.com/ipfs/go-ipfs/Godeps/_workspace/src/github.com/jbenet/go-multiaddr"
6 -)
7 -
8 -// AddrSource is a source of addresses. It allows clients to retrieve
9 -// a set of addresses at a last possible moment in time. It is used
10 -// to query a set of addresses that may change over time, as a result
11 -// of the network changing interfaces or mappings.
12 -type Source interface {
13 - Addrs() []ma.Multiaddr
14 -}
15 -
16 -// CombineSources returns a new AddrSource which is the
17 -// concatenation of all input AddrSources:
18 -//
19 -// combined := CombinedSources(a, b)
20 -// combined.Addrs() // append(a.Addrs(), b.Addrs()...)
21 -//
22 -func CombineSources(srcs ...Source) Source {
23 - return combinedAS(srcs)
24 -}
25 -
26 -type combinedAS []Source
27 -
28 -func (cas combinedAS) Addrs() []ma.Multiaddr {
29 - var addrs []ma.Multiaddr
30 - for _, s := range cas {
31 - addrs = append(addrs, s.Addrs()...)
32 - }
33 - return addrs
34 -}
35 -
36 -// UniqueSource returns a new AddrSource which omits duplicate
37 -// addresses from the inputs:
38 -//
39 -// unique := UniqueSource(a, b)
40 -// unique.Addrs() // append(a.Addrs(), b.Addrs()...)
41 -// // but only adds each addr once.
42 -//
43 -func UniqueSource(srcs ...Source) Source {
44 - return uniqueAS(srcs)
45 -}
46 -
47 -type uniqueAS []Source
48 -
49 -func (uas uniqueAS) Addrs() []ma.Multiaddr {
50 - seen := make(map[string]struct{})
51 - var addrs []ma.Multiaddr
52 - for _, s := range uas {
53 - for _, a := range s.Addrs() {
54 - s := a.String()
55 - if _, found := seen[s]; !found {
56 - addrs = append(addrs, a)
57 - seen[s] = struct{}{}
58 - }
59 - }
60 - }
61 - return addrs
62 -}
63 -
64 -// Slice is a simple slice of addresses that implements
65 -// the AddrSource interface.
66 -type Slice []ma.Multiaddr
67 -
68 -func (as Slice) Addrs() []ma.Multiaddr {
69 - return as
70 -}
p2p/peer/addr/addrsrcs_test.go deleted
-78
@@ -1,78 +0,0 @@
1 -package addr
2 -
3 -import (
4 - "fmt"
5 - "testing"
6 -
7 - ma "github.com/ipfs/go-ipfs/Godeps/_workspace/src/github.com/jbenet/go-multiaddr"
8 -)
9 -
10 -func newAddrOrFatal(t *testing.T, s string) ma.Multiaddr {
11 - a, err := ma.NewMultiaddr(s)
12 - if err != nil {
13 - t.Fatal("error parsing multiaddr", err)
14 - }
15 - return a
16 -}
17 -
18 -func newAddrs(t *testing.T, n int) []ma.Multiaddr {
19 - addrs := make([]ma.Multiaddr, n)
20 - for i := 0; i < n; i++ {
21 - s := fmt.Sprintf("/ip4/1.2.3.4/tcp/%d", i)
22 - addrs[i] = newAddrOrFatal(t, s)
23 - }
24 - return addrs
25 -}
26 -
27 -func addrSetsSame(a, b []ma.Multiaddr) bool {
28 - if len(a) != len(b) {
29 - return false
30 - }
31 - for i, aa := range a {
32 - bb := b[i]
33 - if !aa.Equal(bb) {
34 - return false
35 - }
36 - }
37 - return true
38 -}
39 -
40 -func addrSourcesSame(a, b Source) bool {
41 - return addrSetsSame(a.Addrs(), b.Addrs())
42 -}
43 -
44 -func TestAddrCombine(t *testing.T) {
45 - addrs := newAddrs(t, 30)
46 - a := Slice(addrs[:10])
47 - b := Slice(addrs[10:20])
48 - c := Slice(addrs[20:30])
49 - d := CombineSources(a, b, c)
50 - if !addrSetsSame(addrs, d.Addrs()) {
51 - t.Error("addrs differ")
52 - }
53 - if !addrSourcesSame(Slice(addrs), d) {
54 - t.Error("addrs differ")
55 - }
56 -}
57 -
58 -func TestAddrUnique(t *testing.T) {
59 -
60 - addrs := newAddrs(t, 40)
61 - a := Slice(addrs[:20])
62 - b := Slice(addrs[10:30])
63 - c := Slice(addrs[20:40])
64 - d := CombineSources(a, b, c)
65 - e := UniqueSource(a, b, c)
66 - if addrSetsSame(addrs, d.Addrs()) {
67 - t.Error("addrs same")
68 - }
69 - if addrSourcesSame(Slice(addrs), d) {
70 - t.Error("addrs same")
71 - }
72 - if !addrSetsSame(addrs, e.Addrs()) {
73 - t.Error("addrs differ", addrs, "\n\n", e.Addrs(), "\n\n")
74 - }
75 - if !addrSourcesSame(Slice(addrs), e) {
76 - t.Error("addrs differ", addrs, "\n\n", e.Addrs(), "\n\n")
77 - }
78 -}
p2p/peer/addr_manager.go deleted
-188
@@ -1,188 +0,0 @@
1 -package peer
2 -
3 -import (
4 - "sync"
5 - "time"
6 -
7 - ma "github.com/ipfs/go-ipfs/Godeps/_workspace/src/github.com/jbenet/go-multiaddr"
8 -)
9 -
10 -const (
11 -
12 - // TempAddrTTL is the ttl used for a short lived address
13 - TempAddrTTL = time.Second * 10
14 -
15 - // ProviderAddrTTL is the TTL of an address we've received from a provider.
16 - // This is also a temporary address, but lasts longer. After this expires,
17 - // the records we return will require an extra lookup.
18 - ProviderAddrTTL = time.Minute * 10
19 -
20 - // RecentlyConnectedAddrTTL is used when we recently connected to a peer.
21 - // It means that we are reasonably certain of the peer's address.
22 - RecentlyConnectedAddrTTL = time.Minute * 10
23 -
24 - // OwnObservedAddrTTL is used for our own external addresses observed by peers.
25 - OwnObservedAddrTTL = time.Minute * 10
26 -
27 - // PermanentAddrTTL is the ttl for a "permanent address" (e.g. bootstrap nodes)
28 - // if we haven't shipped you an update to ipfs in 356 days
29 - // we probably arent running the same bootstrap nodes...
30 - PermanentAddrTTL = time.Hour * 24 * 356
31 -
32 - // ConnectedAddrTTL is the ttl used for the addresses of a peer to whom
33 - // we're connected directly. This is basically permanent, as we will
34 - // clear them + re-add under a TempAddrTTL after disconnecting.
35 - ConnectedAddrTTL = PermanentAddrTTL
36 -)
37 -
38 -type expiringAddr struct {
39 - Addr ma.Multiaddr
40 - TTL time.Time
41 -}
42 -
43 -func (e *expiringAddr) ExpiredBy(t time.Time) bool {
44 - return t.After(e.TTL)
45 -}
46 -
47 -type addrSet map[string]expiringAddr
48 -
49 -// AddrManager manages addresses.
50 -// The zero-value is ready to be used.
51 -type AddrManager struct {
52 - addrmu sync.Mutex // guards addrs
53 - addrs map[ID]addrSet
54 -}
55 -
56 -// ensures the AddrManager is initialized.
57 -// So we can use the zero value.
58 -func (mgr *AddrManager) init() {
59 - if mgr.addrs == nil {
60 - mgr.addrs = make(map[ID]addrSet)
61 - }
62 -}
63 -
64 -func (mgr *AddrManager) Peers() []ID {
65 - mgr.addrmu.Lock()
66 - defer mgr.addrmu.Unlock()
67 - if mgr.addrs == nil {
68 - return nil
69 - }
70 -
71 - pids := make([]ID, 0, len(mgr.addrs))
72 - for pid := range mgr.addrs {
73 - pids = append(pids, pid)
74 - }
75 - return pids
76 -}
77 -
78 -// AddAddr calls AddAddrs(p, []ma.Multiaddr{addr}, ttl)
79 -func (mgr *AddrManager) AddAddr(p ID, addr ma.Multiaddr, ttl time.Duration) {
80 - mgr.AddAddrs(p, []ma.Multiaddr{addr}, ttl)
81 -}
82 -
83 -// AddAddrs gives AddrManager addresses to use, with a given ttl
84 -// (time-to-live), after which the address is no longer valid.
85 -// If the manager has a longer TTL, the operation is a no-op for that address
86 -func (mgr *AddrManager) AddAddrs(p ID, addrs []ma.Multiaddr, ttl time.Duration) {
87 - mgr.addrmu.Lock()
88 - defer mgr.addrmu.Unlock()
89 -
90 - // if ttl is zero, exit. nothing to do.
91 - if ttl <= 0 {
92 - return
93 - }
94 -
95 - // so zero value can be used
96 - mgr.init()
97 -
98 - amap, found := mgr.addrs[p]
99 - if !found {
100 - amap = make(addrSet)
101 - mgr.addrs[p] = amap
102 - }
103 -
104 - // only expand ttls
105 - exp := time.Now().Add(ttl)
106 - for _, addr := range addrs {
107 - addrstr := addr.String()
108 - a, found := amap[addrstr]
109 - if !found || exp.After(a.TTL) {
110 - amap[addrstr] = expiringAddr{Addr: addr, TTL: exp}
111 - }
112 - }
113 -}
114 -
115 -// SetAddr calls mgr.SetAddrs(p, addr, ttl)
116 -func (mgr *AddrManager) SetAddr(p ID, addr ma.Multiaddr, ttl time.Duration) {
117 - mgr.SetAddrs(p, []ma.Multiaddr{addr}, ttl)
118 -}
119 -
120 -// SetAddrs sets the ttl on addresses. This clears any TTL there previously.
121 -// This is used when we receive the best estimate of the validity of an address.
122 -func (mgr *AddrManager) SetAddrs(p ID, addrs []ma.Multiaddr, ttl time.Duration) {
123 - mgr.addrmu.Lock()
124 - defer mgr.addrmu.Unlock()
125 -
126 - // so zero value can be used
127 - mgr.init()
128 -
129 - amap, found := mgr.addrs[p]
130 - if !found {
131 - amap = make(addrSet)
132 - mgr.addrs[p] = amap
133 - }
134 -
135 - exp := time.Now().Add(ttl)
136 - for _, addr := range addrs {
137 - // re-set all of them for new ttl.
138 - addrs := addr.String()
139 -
140 - if ttl > 0 {
141 - amap[addrs] = expiringAddr{Addr: addr, TTL: exp}
142 - } else {
143 - delete(amap, addrs)
144 - }
145 - }
146 -}
147 -
148 -// Addresses returns all known (and valid) addresses for a given
149 -func (mgr *AddrManager) Addrs(p ID) []ma.Multiaddr {
150 - mgr.addrmu.Lock()
151 - defer mgr.addrmu.Unlock()
152 -
153 - // not initialized? nothing to give.
154 - if mgr.addrs == nil {
155 - return nil
156 - }
157 -
158 - maddrs, found := mgr.addrs[p]
159 - if !found {
160 - return nil
161 - }
162 -
163 - now := time.Now()
164 - good := make([]ma.Multiaddr, 0, len(maddrs))
165 - var expired []string
166 - for s, m := range maddrs {
167 - if m.ExpiredBy(now) {
168 - expired = append(expired, s)
169 - } else {
170 - good = append(good, m.Addr)
171 - }
172 - }
173 -
174 - // clean up the expired ones.
175 - for _, s := range expired {
176 - delete(maddrs, s)
177 - }
178 - return good
179 -}
180 -
181 -// ClearAddresses removes all previously stored addresses
182 -func (mgr *AddrManager) ClearAddrs(p ID) {
183 - mgr.addrmu.Lock()
184 - defer mgr.addrmu.Unlock()
185 - mgr.init()
186 -
187 - mgr.addrs[p] = make(addrSet) // clear what was there before
188 -}
p2p/peer/addr_manager_test.go deleted
-180
@@ -1,180 +0,0 @@
1 -package peer
2 -
3 -import (
4 - "testing"
5 - "time"
6 -
7 - ma "github.com/ipfs/go-ipfs/Godeps/_workspace/src/github.com/jbenet/go-multiaddr"
8 -)
9 -
10 -func IDS(t *testing.T, ids string) ID {
11 - id, err := IDB58Decode(ids)
12 - if err != nil {
13 - t.Fatal(err)
14 - }
15 - return id
16 -}
17 -
18 -func MA(t *testing.T, m string) ma.Multiaddr {
19 - maddr, err := ma.NewMultiaddr(m)
20 - if err != nil {
21 - t.Fatal(err)
22 - }
23 - return maddr
24 -}
25 -
26 -func testHas(t *testing.T, exp, act []ma.Multiaddr) {
27 - if len(exp) != len(act) {
28 - t.Fatal("lengths not the same")
29 - }
30 -
31 - for _, a := range exp {
32 - found := false
33 -
34 - for _, b := range act {
35 - if a.Equal(b) {
36 - found = true
37 - break
38 - }
39 - }
40 -
41 - if !found {
42 - t.Fatal("expected address %s not found", a)
43 - }
44 - }
45 -}
46 -
47 -func TestAddresses(t *testing.T) {
48 -
49 - id1 := IDS(t, "QmcNstKuwBBoVTpSCSDrwzjgrRcaYXK833Psuz2EMHwyQN")
50 - id2 := IDS(t, "QmRmPL3FDZKE3Qiwv1RosLdwdvbvg17b2hB39QPScgWKKZ")
51 - id3 := IDS(t, "QmPhi7vBsChP7sjRoZGgg7bcKqF6MmCcQwvRbDte8aJ6Kn")
52 - id4 := IDS(t, "QmPhi7vBsChP7sjRoZGgg7bcKqF6MmCcQwvRbDte8aJ5Kn")
53 - id5 := IDS(t, "QmPhi7vBsChP7sjRoZGgg7bcKqF6MmCcQwvRbDte8aJ5Km")
54 -
55 - ma11 := MA(t, "/ip4/1.2.3.1/tcp/1111")
56 - ma21 := MA(t, "/ip4/2.2.3.2/tcp/1111")
57 - ma22 := MA(t, "/ip4/2.2.3.2/tcp/2222")
58 - ma31 := MA(t, "/ip4/3.2.3.3/tcp/1111")
59 - ma32 := MA(t, "/ip4/3.2.3.3/tcp/2222")
60 - ma33 := MA(t, "/ip4/3.2.3.3/tcp/3333")
61 - ma41 := MA(t, "/ip4/4.2.3.3/tcp/1111")
62 - ma42 := MA(t, "/ip4/4.2.3.3/tcp/2222")
63 - ma43 := MA(t, "/ip4/4.2.3.3/tcp/3333")
64 - ma44 := MA(t, "/ip4/4.2.3.3/tcp/4444")
65 - ma51 := MA(t, "/ip4/5.2.3.3/tcp/1111")
66 - ma52 := MA(t, "/ip4/5.2.3.3/tcp/2222")
67 - ma53 := MA(t, "/ip4/5.2.3.3/tcp/3333")
68 - ma54 := MA(t, "/ip4/5.2.3.3/tcp/4444")
69 - ma55 := MA(t, "/ip4/5.2.3.3/tcp/5555")
70 -
71 - ttl := time.Hour
72 - m := AddrManager{}
73 - m.AddAddr(id1, ma11, ttl)
74 -
75 - m.AddAddrs(id2, []ma.Multiaddr{ma21, ma22}, ttl)
76 - m.AddAddrs(id2, []ma.Multiaddr{ma21, ma22}, ttl) // idempotency
77 -
78 - m.AddAddr(id3, ma31, ttl)
79 - m.AddAddr(id3, ma32, ttl)
80 - m.AddAddr(id3, ma33, ttl)
81 - m.AddAddr(id3, ma33, ttl) // idempotency
82 - m.AddAddr(id3, ma33, ttl)
83 -
84 - m.AddAddrs(id4, []ma.Multiaddr{ma41, ma42, ma43, ma44}, ttl) // multiple
85 -
86 - m.AddAddrs(id5, []ma.Multiaddr{ma21, ma22}, ttl) // clearing
87 - m.AddAddrs(id5, []ma.Multiaddr{ma41, ma42, ma43, ma44}, ttl) // clearing
88 - m.ClearAddrs(id5)
89 - m.AddAddrs(id5, []ma.Multiaddr{ma51, ma52, ma53, ma54, ma55}, ttl) // clearing
90 -
91 - // test the Addresses return value
92 - testHas(t, []ma.Multiaddr{ma11}, m.Addrs(id1))
93 - testHas(t, []ma.Multiaddr{ma21, ma22}, m.Addrs(id2))
94 - testHas(t, []ma.Multiaddr{ma31, ma32, ma33}, m.Addrs(id3))
95 - testHas(t, []ma.Multiaddr{ma41, ma42, ma43, ma44}, m.Addrs(id4))
96 - testHas(t, []ma.Multiaddr{ma51, ma52, ma53, ma54, ma55}, m.Addrs(id5))
97 -
98 -}
99 -
100 -func TestAddressesExpire(t *testing.T) {
101 -
102 - id1 := IDS(t, "QmcNstKuwBBoVTpSCSDrwzjgrRcaYXK833Psuz2EMHwyQN")
103 - id2 := IDS(t, "QmcNstKuwBBoVTpSCSDrwzjgrRcaYXK833Psuz2EMHwyQM")
104 - ma11 := MA(t, "/ip4/1.2.3.1/tcp/1111")
105 - ma12 := MA(t, "/ip4/2.2.3.2/tcp/2222")
106 - ma13 := MA(t, "/ip4/3.2.3.3/tcp/3333")
107 - ma24 := MA(t, "/ip4/4.2.3.3/tcp/4444")
108 - ma25 := MA(t, "/ip4/5.2.3.3/tcp/5555")
109 -
110 - m := AddrManager{}
111 - m.AddAddr(id1, ma11, time.Hour)
112 - m.AddAddr(id1, ma12, time.Hour)
113 - m.AddAddr(id1, ma13, time.Hour)
114 - m.AddAddr(id2, ma24, time.Hour)
115 - m.AddAddr(id2, ma25, time.Hour)
116 -
117 - testHas(t, []ma.Multiaddr{ma11, ma12, ma13}, m.Addrs(id1))
118 - testHas(t, []ma.Multiaddr{ma24, ma25}, m.Addrs(id2))
119 -
120 - m.SetAddr(id1, ma11, 2*time.Hour)
121 - m.SetAddr(id1, ma12, 2*time.Hour)
122 - m.SetAddr(id1, ma13, 2*time.Hour)
123 - m.SetAddr(id2, ma24, 2*time.Hour)
124 - m.SetAddr(id2, ma25, 2*time.Hour)
125 -
126 - testHas(t, []ma.Multiaddr{ma11, ma12, ma13}, m.Addrs(id1))
127 - testHas(t, []ma.Multiaddr{ma24, ma25}, m.Addrs(id2))
128 -
129 - m.SetAddr(id1, ma11, time.Millisecond)
130 - <-time.After(time.Millisecond)
131 - testHas(t, []ma.Multiaddr{ma12, ma13}, m.Addrs(id1))
132 - testHas(t, []ma.Multiaddr{ma24, ma25}, m.Addrs(id2))
133 -
134 - m.SetAddr(id1, ma13, time.Millisecond)
135 - <-time.After(time.Millisecond)
136 - testHas(t, []ma.Multiaddr{ma12}, m.Addrs(id1))
137 - testHas(t, []ma.Multiaddr{ma24, ma25}, m.Addrs(id2))
138 -
139 - m.SetAddr(id2, ma24, time.Millisecond)
140 - <-time.After(time.Millisecond)
141 - testHas(t, []ma.Multiaddr{ma12}, m.Addrs(id1))
142 - testHas(t, []ma.Multiaddr{ma25}, m.Addrs(id2))
143 -
144 - m.SetAddr(id2, ma25, time.Millisecond)
145 - <-time.After(time.Millisecond)
146 - testHas(t, []ma.Multiaddr{ma12}, m.Addrs(id1))
147 - testHas(t, nil, m.Addrs(id2))
148 -
149 - m.SetAddr(id1, ma12, time.Millisecond)
150 - <-time.After(time.Millisecond)
151 - testHas(t, nil, m.Addrs(id1))
152 - testHas(t, nil, m.Addrs(id2))
153 -}
154 -
155 -func TestClearWorks(t *testing.T) {
156 -
157 - id1 := IDS(t, "QmcNstKuwBBoVTpSCSDrwzjgrRcaYXK833Psuz2EMHwyQN")
158 - id2 := IDS(t, "QmcNstKuwBBoVTpSCSDrwzjgrRcaYXK833Psuz2EMHwyQM")
159 - ma11 := MA(t, "/ip4/1.2.3.1/tcp/1111")
160 - ma12 := MA(t, "/ip4/2.2.3.2/tcp/2222")
161 - ma13 := MA(t, "/ip4/3.2.3.3/tcp/3333")
162 - ma24 := MA(t, "/ip4/4.2.3.3/tcp/4444")
163 - ma25 := MA(t, "/ip4/5.2.3.3/tcp/5555")
164 -
165 - m := AddrManager{}
166 - m.AddAddr(id1, ma11, time.Hour)
167 - m.AddAddr(id1, ma12, time.Hour)
168 - m.AddAddr(id1, ma13, time.Hour)
169 - m.AddAddr(id2, ma24, time.Hour)
170 - m.AddAddr(id2, ma25, time.Hour)
171 -
172 - testHas(t, []ma.Multiaddr{ma11, ma12, ma13}, m.Addrs(id1))
173 - testHas(t, []ma.Multiaddr{ma24, ma25}, m.Addrs(id2))
174 -
175 - m.ClearAddrs(id1)
176 - m.ClearAddrs(id2)
177 -
178 - testHas(t, nil, m.Addrs(id1))
179 - testHas(t, nil, m.Addrs(id2))
180 -}
p2p/peer/metrics.go deleted
-63
@@ -1,63 +0,0 @@
1 -package peer
2 -
3 -import (
4 - "sync"
5 - "time"
6 -)
7 -
8 -// LatencyEWMASmooting governs the decay of the EWMA (the speed
9 -// at which it changes). This must be a normalized (0-1) value.
10 -// 1 is 100% change, 0 is no change.
11 -var LatencyEWMASmoothing = 0.1
12 -
13 -// Metrics is just an object that tracks metrics
14 -// across a set of peers.
15 -type Metrics interface {
16 -
17 - // RecordLatency records a new latency measurement
18 - RecordLatency(ID, time.Duration)
19 -
20 - // LatencyEWMA returns an exponentially-weighted moving avg.
21 - // of all measurements of a peer's latency.
22 - LatencyEWMA(ID) time.Duration
23 -}
24 -
25 -type metrics struct {
26 - latmap map[ID]time.Duration
27 - latmu sync.RWMutex
28 -}
29 -
30 -func NewMetrics() Metrics {
31 - return &metrics{
32 - latmap: make(map[ID]time.Duration),
33 - }
34 -}
35 -
36 -// RecordLatency records a new latency measurement
37 -func (m *metrics) RecordLatency(p ID, next time.Duration) {
38 - nextf := float64(next)
39 - s := LatencyEWMASmoothing
40 - if s > 1 || s < 0 {
41 - s = 0.1 // ignore the knob. it's broken. look, it jiggles.
42 - }
43 -
44 - m.latmu.Lock()
45 - ewma, found := m.latmap[p]
46 - ewmaf := float64(ewma)
47 - if !found {
48 - m.latmap[p] = next // when no data, just take it as the mean.
49 - } else {
50 - nextf = ((1.0 - s) * ewmaf) + (s * nextf)
51 - m.latmap[p] = time.Duration(nextf)
52 - }
53 - m.latmu.Unlock()
54 -}
55 -
56 -// LatencyEWMA returns an exponentially-weighted moving avg.
57 -// of all measurements of a peer's latency.
58 -func (m *metrics) LatencyEWMA(p ID) time.Duration {
59 - m.latmu.RLock()
60 - lat := m.latmap[p]
61 - m.latmu.RUnlock()
62 - return time.Duration(lat)
63 -}
p2p/peer/metrics_test.go deleted
-40
@@ -1,40 +0,0 @@
1 -package peer_test
2 -
3 -import (
4 - "fmt"
5 - "math/rand"
6 - "testing"
7 - "time"
8 -
9 - peer "github.com/ipfs/go-ipfs/p2p/peer"
10 - testutil "github.com/ipfs/go-ipfs/util/testutil"
11 -)
12 -
13 -func TestLatencyEWMAFun(t *testing.T) {
14 - t.Skip("run it for fun")
15 -
16 - m := peer.NewMetrics()
17 - id, err := testutil.RandPeerID()
18 - if err != nil {
19 - t.Fatal(err)
20 - }
21 -
22 - mu := 100.0
23 - sig := 10.0
24 - next := func() time.Duration {
25 - mu = (rand.NormFloat64() * sig) + mu
26 - return time.Duration(mu)
27 - }
28 -
29 - print := func() {
30 - fmt.Printf("%3.f %3.f --> %d\n", sig, mu, m.LatencyEWMA(id))
31 - }
32 -
33 - for {
34 - select {
35 - case <-time.After(200 * time.Millisecond):
36 - m.RecordLatency(id, next())
37 - print()
38 - }
39 - }
40 -}
p2p/peer/peer.go deleted
-180
@@ -1,180 +0,0 @@
1 -// package peer implements an object used to represent peers in the ipfs network.
2 -package peer
3 -
4 -import (
5 - "encoding/hex"
6 - "encoding/json"
7 - "fmt"
8 - "strings"
9 -
10 - b58 "github.com/ipfs/go-ipfs/Godeps/_workspace/src/github.com/jbenet/go-base58"
11 - ma "github.com/ipfs/go-ipfs/Godeps/_workspace/src/github.com/jbenet/go-multiaddr"
12 - mh "github.com/ipfs/go-ipfs/Godeps/_workspace/src/github.com/jbenet/go-multihash"
13 -
14 - ic "github.com/ipfs/go-ipfs/p2p/crypto"
15 - u "github.com/ipfs/go-ipfs/util"
16 - logging "github.com/ipfs/go-ipfs/vendor/QmQg1J6vikuXF9oDvm4wpdeAUvvkVEKW1EYDw9HhTMnP2b/go-log"
17 -)
18 -
19 -var log = logging.Logger("peer")
20 -
21 -// ID represents the identity of a peer.
22 -type ID string
23 -
24 -// Pretty returns a b58-encoded string of the ID
25 -func (id ID) Pretty() string {
26 - return IDB58Encode(id)
27 -}
28 -
29 -func (id ID) Loggable() map[string]interface{} {
30 - return map[string]interface{}{
31 - "peerID": id.Pretty(),
32 - }
33 -}
34 -
35 -// String prints out the peer.
36 -//
37 -// TODO(brian): ensure correctness at ID generation and
38 -// enforce this by only exposing functions that generate
39 -// IDs safely. Then any peer.ID type found in the
40 -// codebase is known to be correct.
41 -func (id ID) String() string {
42 - pid := id.Pretty()
43 -
44 - //All sha256 nodes start with Qm
45 - //We can skip the Qm to make the peer.ID more useful
46 - if strings.HasPrefix(pid, "Qm") {
47 - pid = pid[2:]
48 - }
49 -
50 - maxRunes := 6
51 - if len(pid) < maxRunes {
52 - maxRunes = len(pid)
53 - }
54 - return fmt.Sprintf("<peer.ID %s>", pid[:maxRunes])
55 -}
56 -
57 -// MatchesPrivateKey tests whether this ID was derived from sk
58 -func (id ID) MatchesPrivateKey(sk ic.PrivKey) bool {
59 - return id.MatchesPublicKey(sk.GetPublic())
60 -}
61 -
62 -// MatchesPublicKey tests whether this ID was derived from pk
63 -func (id ID) MatchesPublicKey(pk ic.PubKey) bool {
64 - oid, err := IDFromPublicKey(pk)
65 - if err != nil {
66 - return false
67 - }
68 - return oid == id
69 -}
70 -
71 -// IDFromString cast a string to ID type, and validate
72 -// the id to make sure it is a multihash.
73 -func IDFromString(s string) (ID, error) {
74 - if _, err := mh.Cast([]byte(s)); err != nil {
75 - return ID(""), err
76 - }
77 - return ID(s), nil
78 -}
79 -
80 -// IDFromBytes cast a string to ID type, and validate
81 -// the id to make sure it is a multihash.
82 -func IDFromBytes(b []byte) (ID, error) {
83 - if _, err := mh.Cast(b); err != nil {
84 - return ID(""), err
85 - }
86 - return ID(b), nil
87 -}
88 -
89 -// IDB58Decode returns a b58-decoded Peer
90 -func IDB58Decode(s string) (ID, error) {
91 - m, err := mh.FromB58String(s)
92 - if err != nil {
93 - return "", err
94 - }
95 - return ID(m), err
96 -}
97 -
98 -// IDB58Encode returns b58-encoded string
99 -func IDB58Encode(id ID) string {
100 - return b58.Encode([]byte(id))
101 -}
102 -
103 -// IDHexDecode returns a b58-decoded Peer
104 -func IDHexDecode(s string) (ID, error) {
105 - m, err := mh.FromHexString(s)
106 - if err != nil {
107 - return "", err
108 - }
109 - return ID(m), err
110 -}
111 -
112 -// IDHexEncode returns b58-encoded string
113 -func IDHexEncode(id ID) string {
114 - return hex.EncodeToString([]byte(id))
115 -}
116 -
117 -// IDFromPublicKey returns the Peer ID corresponding to pk
118 -func IDFromPublicKey(pk ic.PubKey) (ID, error) {
119 - b, err := pk.Bytes()
120 - if err != nil {
121 - return "", err
122 - }
123 - hash := u.Hash(b)
124 - return ID(hash), nil
125 -}
126 -
127 -// IDFromPrivateKey returns the Peer ID corresponding to sk
128 -func IDFromPrivateKey(sk ic.PrivKey) (ID, error) {
129 - return IDFromPublicKey(sk.GetPublic())
130 -}
131 -
132 -// Map maps a Peer ID to a struct.
133 -type Set map[ID]struct{}
134 -
135 -// PeerInfo is a small struct used to pass around a peer with
136 -// a set of addresses (and later, keys?). This is not meant to be
137 -// a complete view of the system, but rather to model updates to
138 -// the peerstore. It is used by things like the routing system.
139 -type PeerInfo struct {
140 - ID ID
141 - Addrs []ma.Multiaddr
142 -}
143 -
144 -func (pi *PeerInfo) MarshalJSON() ([]byte, error) {
145 - out := make(map[string]interface{})
146 - out["ID"] = IDB58Encode(pi.ID)
147 - var addrs []string
148 - for _, a := range pi.Addrs {
149 - addrs = append(addrs, a.String())
150 - }
151 - out["Addrs"] = addrs
152 - return json.Marshal(out)
153 -}
154 -
155 -func (pi *PeerInfo) UnmarshalJSON(b []byte) error {
156 - var data map[string]interface{}
157 - err := json.Unmarshal(b, &data)
158 - if err != nil {
159 - return err
160 - }
161 - pid, err := IDB58Decode(data["ID"].(string))
162 - if err != nil {
163 - return err
164 - }
165 - pi.ID = pid
166 - addrs, ok := data["Addrs"].([]interface{})
167 - if ok {
168 - for _, a := range addrs {
169 - pi.Addrs = append(pi.Addrs, ma.StringCast(a.(string)))
170 - }
171 - }
172 - return nil
173 -}
174 -
175 -// IDSlice for sorting peers
176 -type IDSlice []ID
177 -
178 -func (es IDSlice) Len() int { return len(es) }
179 -func (es IDSlice) Swap(i, j int) { es[i], es[j] = es[j], es[i] }
180 -func (es IDSlice) Less(i, j int) bool { return string(es[i]) < string(es[j]) }
p2p/peer/peer_test.go deleted
-163
@@ -1,163 +0,0 @@
1 -package peer_test
2 -
3 -import (
4 - "encoding/base64"
5 - "fmt"
6 - "strings"
7 - "testing"
8 -
9 - ic "github.com/ipfs/go-ipfs/p2p/crypto"
10 - . "github.com/ipfs/go-ipfs/p2p/peer"
11 - u "github.com/ipfs/go-ipfs/util"
12 - tu "github.com/ipfs/go-ipfs/util/testutil"
13 -
14 - b58 "github.com/ipfs/go-ipfs/Godeps/_workspace/src/github.com/jbenet/go-base58"
15 -)
16 -
17 -var gen1 keyset // generated
18 -var gen2 keyset // generated
19 -var man keyset // manual
20 -
21 -func init() {
22 - if err := gen1.generate(); err != nil {
23 - panic(err)
24 - }
25 - if err := gen2.generate(); err != nil {
26 - panic(err)
27 - }
28 -
29 - skManBytes = strings.Replace(skManBytes, "\n", "", -1)
30 - if err := man.load(hpkpMan, skManBytes); err != nil {
31 - panic(err)
32 - }
33 -}
34 -
35 -type keyset struct {
36 - sk ic.PrivKey
37 - pk ic.PubKey
38 - hpk string
39 - hpkp string
40 -}
41 -
42 -func (ks *keyset) generate() error {
43 - var err error
44 - ks.sk, ks.pk, err = tu.RandTestKeyPair(512)
45 - if err != nil {
46 - return err
47 - }
48 -
49 - bpk, err := ks.pk.Bytes()
50 - if err != nil {
51 - return err
52 - }
53 -
54 - ks.hpk = string(u.Hash(bpk))
55 - ks.hpkp = b58.Encode([]byte(ks.hpk))
56 - return nil
57 -}
58 -
59 -func (ks *keyset) load(hpkp, skBytesStr string) error {
60 - skBytes, err := base64.StdEncoding.DecodeString(skBytesStr)
61 - if err != nil {
62 - return err
63 - }
64 -
65 - ks.sk, err = ic.UnmarshalPrivateKey(skBytes)
66 - if err != nil {
67 - return err
68 - }
69 -
70 - ks.pk = ks.sk.GetPublic()
71 - bpk, err := ks.pk.Bytes()
72 - if err != nil {
73 - return err
74 - }
75 -
76 - ks.hpk = string(u.Hash(bpk))
77 - ks.hpkp = b58.Encode([]byte(ks.hpk))
78 - if ks.hpkp != hpkp {
79 - return fmt.Errorf("hpkp doesn't match key. %s", hpkp)
80 - }
81 - return nil
82 -}
83 -
84 -func TestIDMatchesPublicKey(t *testing.T) {
85 -
86 - test := func(ks keyset) {
87 - p1, err := IDB58Decode(ks.hpkp)
88 - if err != nil {
89 - t.Fatal(err)
90 - }
91 -
92 - if ks.hpk != string(p1) {
93 - t.Error("p1 and hpk differ")
94 - }
95 -
96 - if !p1.MatchesPublicKey(ks.pk) {
97 - t.Fatal("p1 does not match pk")
98 - }
99 -
100 - p2, err := IDFromPublicKey(ks.pk)
101 - if err != nil {
102 - t.Fatal(err)
103 - }
104 -
105 - if p1 != p2 {
106 - t.Error("p1 and p2 differ", p1.Pretty(), p2.Pretty())
107 - }
108 -
109 - if p2.Pretty() != ks.hpkp {
110 - t.Error("hpkp and p2.Pretty differ", ks.hpkp, p2.Pretty())
111 - }
112 - }
113 -
114 - test(gen1)
115 - test(gen2)
116 - test(man)
117 -}
118 -
119 -func TestIDMatchesPrivateKey(t *testing.T) {
120 -
121 - test := func(ks keyset) {
122 - p1, err := IDB58Decode(ks.hpkp)
123 - if err != nil {
124 - t.Fatal(err)
125 - }
126 -
127 - if ks.hpk != string(p1) {
128 - t.Error("p1 and hpk differ")
129 - }
130 -
131 - if !p1.MatchesPrivateKey(ks.sk) {
132 - t.Fatal("p1 does not match sk")
133 - }
134 -
135 - p2, err := IDFromPrivateKey(ks.sk)
136 - if err != nil {
137 - t.Fatal(err)
138 - }
139 -
140 - if p1 != p2 {
141 - t.Error("p1 and p2 differ", p1.Pretty(), p2.Pretty())
142 - }
143 - }
144 -
145 - test(gen1)
146 - test(gen2)
147 - test(man)
148 -}
149 -
150 -var hpkpMan = `QmRK3JgmVEGiewxWbhpXLJyjWuGuLeSTMTndA1coMHEy5o`
151 -var skManBytes = `
152 -CAAS4AQwggJcAgEAAoGBAL7w+Wc4VhZhCdM/+Hccg5Nrf4q9NXWwJylbSrXz/unFS24wyk6pEk0zi3W
153 -7li+vSNVO+NtJQw9qGNAMtQKjVTP+3Vt/jfQRnQM3s6awojtjueEWuLYVt62z7mofOhCtj+VwIdZNBo
154 -/EkLZ0ETfcvN5LVtLYa8JkXybnOPsLvK+PAgMBAAECgYBdk09HDM7zzL657uHfzfOVrdslrTCj6p5mo
155 -DzvCxLkkjIzYGnlPuqfNyGjozkpSWgSUc+X+EGLLl3WqEOVdWJtbM61fewEHlRTM5JzScvwrJ39t7o6
156 -CCAjKA0cBWBd6UWgbN/t53RoWvh9HrA2AW5YrT0ZiAgKe9y7EMUaENVJ8QJBAPhpdmb4ZL4Fkm4OKia
157 -NEcjzn6mGTlZtef7K/0oRC9+2JkQnCuf6HBpaRhJoCJYg7DW8ZY+AV6xClKrgjBOfERMCQQDExhnzu2
158 -dsQ9k8QChBlpHO0TRbZBiQfC70oU31kM1AeLseZRmrxv9Yxzdl8D693NNWS2JbKOXl0kMHHcuGQLMVA
159 -kBZ7WvkmPV3aPL6jnwp2pXepntdVnaTiSxJ1dkXShZ/VSSDNZMYKY306EtHrIu3NZHtXhdyHKcggDXr
160 -qkBrdgErAkAlpGPojUwemOggr4FD8sLX1ot2hDJyyV7OK2FXfajWEYJyMRL1Gm9Uk1+Un53RAkJneqp
161 -JGAzKpyttXBTIDO51AkEA98KTiROMnnU8Y6Mgcvr68/SMIsvCYMt9/mtwSBGgl80VaTQ5Hpaktl6Xbh
162 -VUt5Wv0tRxlXZiViCGCD1EtrrwTw==
163 -`
p2p/peer/peerstore.go deleted
-216
@@ -1,216 +0,0 @@
1 -package peer
2 -
3 -import (
4 - "errors"
5 - "sync"
6 - "time"
7 -
8 - ic "github.com/ipfs/go-ipfs/p2p/crypto"
9 -
10 - ds "github.com/ipfs/go-ipfs/Godeps/_workspace/src/github.com/ipfs/go-datastore"
11 - dssync "github.com/ipfs/go-ipfs/Godeps/_workspace/src/github.com/ipfs/go-datastore/sync"
12 - ma "github.com/ipfs/go-ipfs/Godeps/_workspace/src/github.com/jbenet/go-multiaddr"
13 -)
14 -
15 -const (
16 - // AddressTTL is the expiration time of addresses.
17 - AddressTTL = time.Hour
18 -)
19 -
20 -// Peerstore provides a threadsafe store of Peer related
21 -// information.
22 -type Peerstore interface {
23 - AddrBook
24 - KeyBook
25 - Metrics
26 -
27 - // Peers returns a list of all peer.IDs in this Peerstore
28 - Peers() []ID
29 -
30 - // PeerInfo returns a peer.PeerInfo struct for given peer.ID.
31 - // This is a small slice of the information Peerstore has on
32 - // that peer, useful to other services.
33 - PeerInfo(ID) PeerInfo
34 -
35 - // Get/Put is a simple registry for other peer-related key/value pairs.
36 - // if we find something we use often, it should become its own set of
37 - // methods. this is a last resort.
38 - Get(id ID, key string) (interface{}, error)
39 - Put(id ID, key string, val interface{}) error
40 -}
41 -
42 -// AddrBook is an interface that fits the new AddrManager. I'm patching
43 -// it up in here to avoid changing a ton of the codebase.
44 -type AddrBook interface {
45 -
46 - // AddAddr calls AddAddrs(p, []ma.Multiaddr{addr}, ttl)
47 - AddAddr(p ID, addr ma.Multiaddr, ttl time.Duration)
48 -
49 - // AddAddrs gives AddrManager addresses to use, with a given ttl
50 - // (time-to-live), after which the address is no longer valid.
51 - // If the manager has a longer TTL, the operation is a no-op for that address
52 - AddAddrs(p ID, addrs []ma.Multiaddr, ttl time.Duration)
53 -
54 - // SetAddr calls mgr.SetAddrs(p, addr, ttl)
55 - SetAddr(p ID, addr ma.Multiaddr, ttl time.Duration)
56 -
57 - // SetAddrs sets the ttl on addresses. This clears any TTL there previously.
58 - // This is used when we receive the best estimate of the validity of an address.
59 - SetAddrs(p ID, addrs []ma.Multiaddr, ttl time.Duration)
60 -
61 - // Addresses returns all known (and valid) addresses for a given
62 - Addrs(p ID) []ma.Multiaddr
63 -
64 - // ClearAddresses removes all previously stored addresses
65 - ClearAddrs(p ID)
66 -}
67 -
68 -// KeyBook tracks the Public keys of Peers.
69 -type KeyBook interface {
70 - PubKey(ID) ic.PubKey
71 - AddPubKey(ID, ic.PubKey) error
72 -
73 - PrivKey(ID) ic.PrivKey
74 - AddPrivKey(ID, ic.PrivKey) error
75 -}
76 -
77 -type keybook struct {
78 - pks map[ID]ic.PubKey
79 - sks map[ID]ic.PrivKey
80 -
81 - sync.RWMutex // same lock. wont happen a ton.
82 -}
83 -
84 -func newKeybook() *keybook {
85 - return &keybook{
86 - pks: map[ID]ic.PubKey{},
87 - sks: map[ID]ic.PrivKey{},
88 - }
89 -}
90 -
91 -func (kb *keybook) Peers() []ID {
92 - kb.RLock()
93 - ps := make([]ID, 0, len(kb.pks)+len(kb.sks))
94 - for p := range kb.pks {
95 - ps = append(ps, p)
96 - }
97 - for p := range kb.sks {
98 - if _, found := kb.pks[p]; !found {
99 - ps = append(ps, p)
100 - }
101 - }
102 - kb.RUnlock()
103 - return ps
104 -}
105 -
106 -func (kb *keybook) PubKey(p ID) ic.PubKey {
107 - kb.RLock()
108 - pk := kb.pks[p]
109 - kb.RUnlock()
110 - return pk
111 -}
112 -
113 -func (kb *keybook) AddPubKey(p ID, pk ic.PubKey) error {
114 -
115 - // check it's correct first
116 - if !p.MatchesPublicKey(pk) {
117 - return errors.New("ID does not match PublicKey")
118 - }
119 -
120 - kb.Lock()
121 - kb.pks[p] = pk
122 - kb.Unlock()
123 - return nil
124 -}
125 -
126 -func (kb *keybook) PrivKey(p ID) ic.PrivKey {
127 - kb.RLock()
128 - sk := kb.sks[p]
129 - kb.RUnlock()
130 - return sk
131 -}
132 -
133 -func (kb *keybook) AddPrivKey(p ID, sk ic.PrivKey) error {
134 -
135 - if sk == nil {
136 - return errors.New("sk is nil (PrivKey)")
137 - }
138 -
139 - // check it's correct first
140 - if !p.MatchesPrivateKey(sk) {
141 - return errors.New("ID does not match PrivateKey")
142 - }
143 -
144 - kb.Lock()
145 - kb.sks[p] = sk
146 - kb.Unlock()
147 - return nil
148 -}
149 -
150 -type peerstore struct {
151 - keybook
152 - metrics
153 - AddrManager
154 -
155 - // store other data, like versions
156 - ds ds.ThreadSafeDatastore
157 -}
158 -
159 -// NewPeerstore creates a threadsafe collection of peers.
160 -func NewPeerstore() Peerstore {
161 - return &peerstore{
162 - keybook: *newKeybook(),
163 - metrics: *(NewMetrics()).(*metrics),
164 - AddrManager: AddrManager{},
165 - ds: dssync.MutexWrap(ds.NewMapDatastore()),
166 - }
167 -}
168 -
169 -func (ps *peerstore) Put(p ID, key string, val interface{}) error {
170 - dsk := ds.NewKey(string(p) + "/" + key)
171 - return ps.ds.Put(dsk, val)
172 -}
173 -
174 -func (ps *peerstore) Get(p ID, key string) (interface{}, error) {
175 - dsk := ds.NewKey(string(p) + "/" + key)
176 - return ps.ds.Get(dsk)
177 -}
178 -
179 -func (ps *peerstore) Peers() []ID {
180 - set := map[ID]struct{}{}
181 - for _, p := range ps.keybook.Peers() {
182 - set[p] = struct{}{}
183 - }
184 - for _, p := range ps.AddrManager.Peers() {
185 - set[p] = struct{}{}
186 - }
187 -
188 - pps := make([]ID, 0, len(set))
189 - for p := range set {
190 - pps = append(pps, p)
191 - }
192 - return pps
193 -}
194 -
195 -func (ps *peerstore) PeerInfo(p ID) PeerInfo {
196 - return PeerInfo{
197 - ID: p,
198 - Addrs: ps.AddrManager.Addrs(p),
199 - }
200 -}
201 -
202 -func PeerInfos(ps Peerstore, peers []ID) []PeerInfo {
203 - pi := make([]PeerInfo, len(peers))
204 - for i, p := range peers {
205 - pi[i] = ps.PeerInfo(p)
206 - }
207 - return pi
208 -}
209 -
210 -func PeerInfoIDs(pis []PeerInfo) []ID {
211 - ps := make([]ID, len(pis))
212 - for i, pi := range pis {
213 - ps[i] = pi.ID
214 - }
215 - return ps
216 -}
p2p/peer/queue/distance.go deleted
-101
@@ -1,101 +0,0 @@
1 -package queue
2 -
3 -import (
4 - "container/heap"
5 - "math/big"
6 - "sync"
7 -
8 - key "github.com/ipfs/go-ipfs/blocks/key"
9 - peer "github.com/ipfs/go-ipfs/p2p/peer"
10 - ks "github.com/ipfs/go-ipfs/routing/keyspace"
11 -)
12 -
13 -// peerMetric tracks a peer and its distance to something else.
14 -type peerMetric struct {
15 - // the peer
16 - peer peer.ID
17 -
18 - // big.Int for XOR metric
19 - metric *big.Int
20 -}
21 -
22 -// peerMetricHeap implements a heap of peerDistances
23 -type peerMetricHeap []*peerMetric
24 -
25 -func (ph peerMetricHeap) Len() int {
26 - return len(ph)
27 -}
28 -
29 -func (ph peerMetricHeap) Less(i, j int) bool {
30 - return -1 == ph[i].metric.Cmp(ph[j].metric)
31 -}
32 -
33 -func (ph peerMetricHeap) Swap(i, j int) {
34 - ph[i], ph[j] = ph[j], ph[i]
35 -}
36 -
37 -func (ph *peerMetricHeap) Push(x interface{}) {
38 - item := x.(*peerMetric)
39 - *ph = append(*ph, item)
40 -}
41 -
42 -func (ph *peerMetricHeap) Pop() interface{} {
43 - old := *ph
44 - n := len(old)
45 - item := old[n-1]
46 - *ph = old[0 : n-1]
47 - return item
48 -}
49 -
50 -// distancePQ implements heap.Interface and PeerQueue
51 -type distancePQ struct {
52 - // from is the Key this PQ measures against
53 - from ks.Key
54 -
55 - // heap is a heap of peerDistance items
56 - heap peerMetricHeap
57 -
58 - sync.RWMutex
59 -}
60 -
61 -func (pq *distancePQ) Len() int {
62 - pq.Lock()
63 - defer pq.Unlock()
64 - return len(pq.heap)
65 -}
66 -
67 -func (pq *distancePQ) Enqueue(p peer.ID) {
68 - pq.Lock()
69 - defer pq.Unlock()
70 -
71 - distance := ks.XORKeySpace.Key([]byte(p)).Distance(pq.from)
72 -
73 - heap.Push(&pq.heap, &peerMetric{
74 - peer: p,
75 - metric: distance,
76 - })
77 -}
78 -
79 -func (pq *distancePQ) Dequeue() peer.ID {
80 - pq.Lock()
81 - defer pq.Unlock()
82 -
83 - if len(pq.heap) < 1 {
84 - panic("called Dequeue on an empty PeerQueue")
85 - // will panic internally anyway, but we can help debug here
86 - }
87 -
88 - o := heap.Pop(&pq.heap)
89 - p := o.(*peerMetric)
90 - return p.peer
91 -}
92 -
93 -// NewXORDistancePQ returns a PeerQueue which maintains its peers sorted
94 -// in terms of their distances to each other in an XORKeySpace (i.e. using
95 -// XOR as a metric of distance).
96 -func NewXORDistancePQ(fromKey key.Key) PeerQueue {
97 - return &distancePQ{
98 - from: ks.XORKeySpace.Key([]byte(fromKey)),
99 - heap: peerMetricHeap{},
100 - }
101 -}
p2p/peer/queue/interface.go deleted
-18
@@ -1,18 +0,0 @@
1 -package queue
2 -
3 -import peer "github.com/ipfs/go-ipfs/p2p/peer"
4 -
5 -// PeerQueue maintains a set of peers ordered according to a metric.
6 -// Implementations of PeerQueue could order peers based on distances along
7 -// a KeySpace, latency measurements, trustworthiness, reputation, etc.
8 -type PeerQueue interface {
9 -
10 - // Len returns the number of items in PeerQueue
11 - Len() int
12 -
13 - // Enqueue adds this node to the queue.
14 - Enqueue(peer.ID)
15 -
16 - // Dequeue retrieves the highest (smallest int) priority node
17 - Dequeue() peer.ID
18 -}
p2p/peer/queue/queue_test.go deleted
-141
@@ -1,141 +0,0 @@
1 -package queue
2 -
3 -import (
4 - "fmt"
5 - "sync"
6 - "testing"
7 - "time"
8 -
9 - key "github.com/ipfs/go-ipfs/blocks/key"
10 - peer "github.com/ipfs/go-ipfs/p2p/peer"
11 - u "github.com/ipfs/go-ipfs/util"
12 -
13 - context "github.com/ipfs/go-ipfs/Godeps/_workspace/src/golang.org/x/net/context"
14 -)
15 -
16 -func TestQueue(t *testing.T) {
17 -
18 - p1 := peer.ID("11140beec7b5ea3f0fdbc95d0dd47f3c5bc275da8a31") // these aren't valid, because need to hex-decode.
19 - p2 := peer.ID("11140beec7b5ea3f0fdbc95d0dd47f3c5bc275da8a32") // these aren't valid, because need to hex-decode.
20 - p3 := peer.ID("11140beec7b5ea3f0fdbc95d0dd47f3c5bc275da8a33") // these aren't valid, because need to hex-decode.
21 - p4 := peer.ID("11140beec7b5ea3f0fdbc95d0dd47f3c5bc275da8a34") // these aren't valid, because need to hex-decode.
22 - p5 := peer.ID("11140beec7b5ea3f0fdbc95d0dd47f3c5bc275da8a31") // these aren't valid, because need to hex-decode.
23 - // but they work.
24 -
25 - // these are the peer.IDs' XORKeySpace Key values:
26 - // [228 47 151 130 156 102 222 232 218 31 132 94 170 208 80 253 120 103 55 35 91 237 48 157 81 245 57 247 66 150 9 40]
27 - // [26 249 85 75 54 49 25 30 21 86 117 62 85 145 48 175 155 194 210 216 58 14 241 143 28 209 129 144 122 28 163 6]
28 - // [78 135 26 216 178 181 224 181 234 117 2 248 152 115 255 103 244 34 4 152 193 88 9 225 8 127 216 158 226 8 236 246]
29 - // [125 135 124 6 226 160 101 94 192 57 39 12 18 79 121 140 190 154 147 55 44 83 101 151 63 255 94 179 51 203 241 51]
30 -
31 - pq := NewXORDistancePQ(key.Key("11140beec7b5ea3f0fdbc95d0dd47f3c5bc275da8a31"))
32 - pq.Enqueue(p3)
33 - pq.Enqueue(p1)
34 - pq.Enqueue(p2)
35 - pq.Enqueue(p4)
36 - pq.Enqueue(p5)
37 - pq.Enqueue(p1)
38 -
39 - // should come out as: p1, p4, p3, p2
40 -
41 - if d := pq.Dequeue(); d != p1 && d != p5 {
42 - t.Error("ordering failed")
43 - }
44 -
45 - if d := pq.Dequeue(); d != p1 && d != p5 {
46 - t.Error("ordering failed")
47 - }
48 -
49 - if d := pq.Dequeue(); d != p1 && d != p5 {
50 - t.Error("ordering failed")
51 - }
52 -
53 - if pq.Dequeue() != p4 {
54 - t.Error("ordering failed")
55 - }
56 -
57 - if pq.Dequeue() != p3 {
58 - t.Error("ordering failed")
59 - }
60 -
61 - if pq.Dequeue() != p2 {
62 - t.Error("ordering failed")
63 - }
64 -
65 -}
66 -
67 -func newPeerTime(t time.Time) peer.ID {
68 - s := fmt.Sprintf("hmmm time: %v", t)
69 - h := u.Hash([]byte(s))
70 - return peer.ID(h)
71 -}
72 -
73 -func TestSyncQueue(t *testing.T) {
74 - tickT := time.Microsecond * 50
75 - max := 5000
76 - consumerN := 10
77 - countsIn := make([]int, consumerN*2)
78 - countsOut := make([]int, consumerN)
79 -
80 - if testing.Short() {
81 - max = 1000
82 - }
83 -
84 - ctx := context.Background()
85 - pq := NewXORDistancePQ(key.Key("11140beec7b5ea3f0fdbc95d0dd47f3c5bc275da8a31"))
86 - cq := NewChanQueue(ctx, pq)
87 - wg := sync.WaitGroup{}
88 -
89 - produce := func(p int) {
90 - defer wg.Done()
91 -
92 - tick := time.Tick(tickT)
93 - for i := 0; i < max; i++ {
94 - select {
95 - case tim := <-tick:
96 - countsIn[p]++
97 - cq.EnqChan <- newPeerTime(tim)
98 - case <-ctx.Done():
99 - return
100 - }
101 - }
102 - }
103 -
104 - consume := func(c int) {
105 - defer wg.Done()
106 -
107 - for {
108 - select {
109 - case <-cq.DeqChan:
110 - countsOut[c]++
111 - if countsOut[c] >= max*2 {
112 - return
113 - }
114 - case <-ctx.Done():
115 - return
116 - }
117 - }
118 - }
119 -
120 - // make n * 2 producers and n consumers
121 - for i := 0; i < consumerN; i++ {
122 - wg.Add(3)
123 - go produce(i)
124 - go produce(consumerN + i)
125 - go consume(i)
126 - }
127 -
128 - wg.Wait()
129 -
130 - sum := func(ns []int) int {
131 - total := 0
132 - for _, n := range ns {
133 - total += n
134 - }
135 - return total
136 - }
137 -
138 - if sum(countsIn) != sum(countsOut) {
139 - t.Errorf("didnt get all of them out: %d/%d", sum(countsOut), sum(countsIn))
140 - }
141 -}
p2p/peer/queue/sync.go deleted
-84
@@ -1,84 +0,0 @@
1 -package queue
2 -
3 -import (
4 - context "github.com/ipfs/go-ipfs/Godeps/_workspace/src/golang.org/x/net/context"
5 - peer "github.com/ipfs/go-ipfs/p2p/peer"
6 - logging "github.com/ipfs/go-ipfs/vendor/QmQg1J6vikuXF9oDvm4wpdeAUvvkVEKW1EYDw9HhTMnP2b/go-log"
7 -)
8 -
9 -var log = logging.Logger("peerqueue")
10 -
11 -// ChanQueue makes any PeerQueue synchronizable through channels.
12 -type ChanQueue struct {
13 - Queue PeerQueue
14 - EnqChan chan<- peer.ID
15 - DeqChan <-chan peer.ID
16 -}
17 -
18 -// NewChanQueue creates a ChanQueue by wrapping pq.
19 -func NewChanQueue(ctx context.Context, pq PeerQueue) *ChanQueue {
20 - cq := &ChanQueue{Queue: pq}
21 - cq.process(ctx)
22 - return cq
23 -}
24 -
25 -func (cq *ChanQueue) process(ctx context.Context) {
26 - // construct the channels here to be able to use them bidirectionally
27 - enqChan := make(chan peer.ID)
28 - deqChan := make(chan peer.ID)
29 -
30 - cq.EnqChan = enqChan
31 - cq.DeqChan = deqChan
32 -
33 - go func() {
34 - log.Debug("processing")
35 - defer log.Debug("closed")
36 - defer close(deqChan)
37 -
38 - var next peer.ID
39 - var item peer.ID
40 - var more bool
41 -
42 - for {
43 - if cq.Queue.Len() == 0 {
44 - // log.Debug("wait for enqueue")
45 - select {
46 - case next, more = <-enqChan:
47 - if !more {
48 - return
49 - }
50 - // log.Debug("got", next)
51 -
52 - case <-ctx.Done():
53 - return
54 - }
55 -
56 - } else {
57 - next = cq.Queue.Dequeue()
58 - // log.Debug("peek", next)
59 - }
60 -
61 - select {
62 - case item, more = <-enqChan:
63 - if !more {
64 - if cq.Queue.Len() > 0 {
65 - return // we're done done.
66 - }
67 - enqChan = nil // closed, so no use.
68 - }
69 - // log.Debug("got", item)
70 - cq.Queue.Enqueue(item)
71 - cq.Queue.Enqueue(next) // order may have changed.
72 - next = ""
73 -
74 - case deqChan <- next:
75 - // log.Debug("dequeued", next)
76 - next = ""
77 -
78 - case <-ctx.Done():
79 - return
80 - }
81 - }
82 -
83 - }()
84 -}
p2p/protocol/identify/id.go deleted
-334
@@ -1,334 +0,0 @@
1 -package identify
2 -
3 -import (
4 - "strings"
5 - "sync"
6 -
7 - semver "github.com/ipfs/go-ipfs/Godeps/_workspace/src/github.com/coreos/go-semver/semver"
8 - ggio "github.com/ipfs/go-ipfs/Godeps/_workspace/src/github.com/gogo/protobuf/io"
9 - ma "github.com/ipfs/go-ipfs/Godeps/_workspace/src/github.com/jbenet/go-multiaddr"
10 - msmux "github.com/ipfs/go-ipfs/Godeps/_workspace/src/github.com/whyrusleeping/go-multistream"
11 - context "github.com/ipfs/go-ipfs/Godeps/_workspace/src/golang.org/x/net/context"
12 -
13 - mstream "github.com/ipfs/go-ipfs/metrics/stream"
14 - host "github.com/ipfs/go-ipfs/p2p/host"
15 - inet "github.com/ipfs/go-ipfs/p2p/net"
16 - peer "github.com/ipfs/go-ipfs/p2p/peer"
17 - pb "github.com/ipfs/go-ipfs/p2p/protocol/identify/pb"
18 - config "github.com/ipfs/go-ipfs/repo/config"
19 - lgbl "github.com/ipfs/go-ipfs/util/eventlog/loggables"
20 - logging "github.com/ipfs/go-ipfs/vendor/QmQg1J6vikuXF9oDvm4wpdeAUvvkVEKW1EYDw9HhTMnP2b/go-log"
21 -)
22 -
23 -var log = logging.Logger("net/identify")
24 -
25 -// ID is the protocol.ID of the Identify Service.
26 -const ID = "/ipfs/identify"
27 -
28 -// IpfsVersion holds the current protocol version for a client running this code
29 -// TODO(jbenet): fix the versioning mess.
30 -const IpfsVersion = "ipfs/0.1.0"
31 -const ClientVersion = "go-ipfs/" + config.CurrentVersionNumber
32 -
33 -// IDService is a structure that implements ProtocolIdentify.
34 -// It is a trivial service that gives the other peer some
35 -// useful information about the local peer. A sort of hello.
36 -//
37 -// The IDService sends:
38 -// * Our IPFS Protocol Version
39 -// * Our IPFS Agent Version
40 -// * Our public Listen Addresses
41 -type IDService struct {
42 - Host host.Host
43 -
44 - // connections undergoing identification
45 - // for wait purposes
46 - currid map[inet.Conn]chan struct{}
47 - currmu sync.RWMutex
48 -
49 - // our own observed addresses.
50 - // TODO: instead of expiring, remove these when we disconnect
51 - observedAddrs ObservedAddrSet
52 -}
53 -
54 -func NewIDService(h host.Host) *IDService {
55 - s := &IDService{
56 - Host: h,
57 - currid: make(map[inet.Conn]chan struct{}),
58 - }
59 - h.SetStreamHandler(ID, s.RequestHandler)
60 - return s
61 -}
62 -
63 -// OwnObservedAddrs returns the addresses peers have reported we've dialed from
64 -func (ids *IDService) OwnObservedAddrs() []ma.Multiaddr {
65 - return ids.observedAddrs.Addrs()
66 -}
67 -
68 -func (ids *IDService) IdentifyConn(c inet.Conn) {
69 - ids.currmu.Lock()
70 - if wait, found := ids.currid[c]; found {
71 - ids.currmu.Unlock()
72 - log.Debugf("IdentifyConn called twice on: %s", c)
73 - <-wait // already identifying it. wait for it.
74 - return
75 - }
76 - ids.currid[c] = make(chan struct{})
77 - ids.currmu.Unlock()
78 -
79 - s, err := c.NewStream()
80 - if err != nil {
81 - log.Debugf("error opening initial stream for %s", ID)
82 - log.Event(context.TODO(), "IdentifyOpenFailed", c.RemotePeer())
83 - c.Close()
84 - return
85 - } else {
86 - bwc := ids.Host.GetBandwidthReporter()
87 - s = mstream.WrapStream(s, ID, bwc)
88 -
89 - // ok give the response to our handler.
90 - if err := msmux.SelectProtoOrFail(ID, s); err != nil {
91 - log.Debugf("error writing stream header for %s", ID)
92 - log.Event(context.TODO(), "IdentifyOpenFailed", c.RemotePeer())
93 - s.Close()
94 - return
95 - } else {
96 - ids.ResponseHandler(s)
97 - }
98 - }
99 -
100 - ids.currmu.Lock()
101 - ch, found := ids.currid[c]
102 - delete(ids.currid, c)
103 - ids.currmu.Unlock()
104 -
105 - if !found {
106 - log.Debugf("IdentifyConn failed to find channel (programmer error) for %s", c)
107 - return
108 - }
109 -
110 - close(ch) // release everyone waiting.
111 -}
112 -
113 -func (ids *IDService) RequestHandler(s inet.Stream) {
114 - defer s.Close()
115 - c := s.Conn()
116 -
117 - bwc := ids.Host.GetBandwidthReporter()
118 - s = mstream.WrapStream(s, ID, bwc)
119 -
120 - w := ggio.NewDelimitedWriter(s)
121 - mes := pb.Identify{}
122 - ids.populateMessage(&mes, s.Conn())
123 - w.WriteMsg(&mes)
124 -
125 - log.Debugf("%s sent message to %s %s", ID,
126 - c.RemotePeer(), c.RemoteMultiaddr())
127 -}
128 -
129 -func (ids *IDService) ResponseHandler(s inet.Stream) {
130 - defer s.Close()
131 - c := s.Conn()
132 -
133 - r := ggio.NewDelimitedReader(s, 2048)
134 - mes := pb.Identify{}
135 - if err := r.ReadMsg(&mes); err != nil {
136 - return
137 - }
138 - ids.consumeMessage(&mes, c)
139 -
140 - log.Debugf("%s received message from %s %s", ID,
141 - c.RemotePeer(), c.RemoteMultiaddr())
142 -}
143 -
144 -func (ids *IDService) populateMessage(mes *pb.Identify, c inet.Conn) {
145 -
146 - // set protocols this node is currently handling
147 - protos := ids.Host.Mux().Protocols()
148 - mes.Protocols = make([]string, len(protos))
149 - for i, p := range protos {
150 - mes.Protocols[i] = string(p)
151 - }
152 -
153 - // observed address so other side is informed of their
154 - // "public" address, at least in relation to us.
155 - mes.ObservedAddr = c.RemoteMultiaddr().Bytes()
156 -
157 - // set listen addrs, get our latest addrs from Host.
158 - laddrs := ids.Host.Addrs()
159 - mes.ListenAddrs = make([][]byte, len(laddrs))
160 - for i, addr := range laddrs {
161 - mes.ListenAddrs[i] = addr.Bytes()
162 - }
163 - log.Debugf("%s sent listen addrs to %s: %s", c.LocalPeer(), c.RemotePeer(), laddrs)
164 -
165 - // set protocol versions
166 - pv := IpfsVersion
167 - av := ClientVersion
168 - mes.ProtocolVersion = &pv
169 - mes.AgentVersion = &av
170 -}
171 -
172 -func (ids *IDService) consumeMessage(mes *pb.Identify, c inet.Conn) {
173 - p := c.RemotePeer()
174 -
175 - // mes.Protocols
176 -
177 - // mes.ObservedAddr
178 - ids.consumeObservedAddress(mes.GetObservedAddr(), c)
179 -
180 - // mes.ListenAddrs
181 - laddrs := mes.GetListenAddrs()
182 - lmaddrs := make([]ma.Multiaddr, 0, len(laddrs))
183 - for _, addr := range laddrs {
184 - maddr, err := ma.NewMultiaddrBytes(addr)
185 - if err != nil {
186 - log.Debugf("%s failed to parse multiaddr from %s %s", ID,
187 - p, c.RemoteMultiaddr())
188 - continue
189 - }
190 - lmaddrs = append(lmaddrs, maddr)
191 - }
192 -
193 - // update our peerstore with the addresses. here, we SET the addresses, clearing old ones.
194 - // We are receiving from the peer itself. this is current address ground truth.
195 - ids.Host.Peerstore().SetAddrs(p, lmaddrs, peer.ConnectedAddrTTL)
196 - log.Debugf("%s received listen addrs for %s: %s", c.LocalPeer(), c.RemotePeer(), lmaddrs)
197 -
198 - // get protocol versions
199 - pv := mes.GetProtocolVersion()
200 - av := mes.GetAgentVersion()
201 -
202 - // version check. if we shouldn't talk, bail.
203 - // TODO: at this point, we've already exchanged information.
204 - // move this into a first handshake before the connection can open streams.
205 - if !protocolVersionsAreCompatible(pv, IpfsVersion) {
206 - logProtocolMismatchDisconnect(c, pv, av)
207 - c.Close()
208 - return
209 - }
210 -
211 - ids.Host.Peerstore().Put(p, "ProtocolVersion", pv)
212 - ids.Host.Peerstore().Put(p, "AgentVersion", av)
213 -}
214 -
215 -// IdentifyWait returns a channel which will be closed once
216 -// "ProtocolIdentify" (handshake3) finishes on given conn.
217 -// This happens async so the connection can start to be used
218 -// even if handshake3 knowledge is not necesary.
219 -// Users **MUST** call IdentifyWait _after_ IdentifyConn
220 -func (ids *IDService) IdentifyWait(c inet.Conn) <-chan struct{} {
221 - ids.currmu.Lock()
222 - ch, found := ids.currid[c]
223 - ids.currmu.Unlock()
224 - if found {
225 - return ch
226 - }
227 -
228 - // if not found, it means we are already done identifying it, or
229 - // haven't even started. either way, return a new channel closed.
230 - ch = make(chan struct{})
231 - close(ch)
232 - return ch
233 -}
234 -
235 -func (ids *IDService) consumeObservedAddress(observed []byte, c inet.Conn) {
236 - if observed == nil {
237 - return
238 - }
239 -
240 - maddr, err := ma.NewMultiaddrBytes(observed)
241 - if err != nil {
242 - log.Debugf("error parsing received observed addr for %s: %s", c, err)
243 - return
244 - }
245 -
246 - // we should only use ObservedAddr when our connection's LocalAddr is one
247 - // of our ListenAddrs. If we Dial out using an ephemeral addr, knowing that
248 - // address's external mapping is not very useful because the port will not be
249 - // the same as the listen addr.
250 - ifaceaddrs, err := ids.Host.Network().InterfaceListenAddresses()
251 - if err != nil {
252 - log.Infof("failed to get interface listen addrs", err)
253 - return
254 - }
255 -
256 - log.Debugf("identify identifying observed multiaddr: %s %s", c.LocalMultiaddr(), ifaceaddrs)
257 - if !addrInAddrs(c.LocalMultiaddr(), ifaceaddrs) {
258 - // not in our list
259 - return
260 - }
261 -
262 - // ok! we have the observed version of one of our ListenAddresses!
263 - log.Debugf("added own observed listen addr: %s --> %s", c.LocalMultiaddr(), maddr)
264 - ids.observedAddrs.Add(maddr, c.RemoteMultiaddr())
265 -}
266 -
267 -func addrInAddrs(a ma.Multiaddr, as []ma.Multiaddr) bool {
268 - for _, b := range as {
269 - if a.Equal(b) {
270 - return true
271 - }
272 - }
273 - return false
274 -}
275 -
276 -// protocolVersionsAreCompatible checks that the two implementations
277 -// can talk to each other. It will use semver, but for now while
278 -// we're in tight development, we will return false for minor version
279 -// changes too.
280 -func protocolVersionsAreCompatible(v1, v2 string) bool {
281 - if strings.HasPrefix(v1, "ipfs/") {
282 - v1 = v1[5:]
283 - }
284 - if strings.HasPrefix(v2, "ipfs/") {
285 - v2 = v2[5:]
286 - }
287 -
288 - v1s, err := semver.NewVersion(v1)
289 - if err != nil {
290 - return false
291 - }
292 -
293 - v2s, err := semver.NewVersion(v2)
294 - if err != nil {
295 - return false
296 - }
297 -
298 - return v1s.Major == v2s.Major && v1s.Minor == v2s.Minor
299 -}
300 -
301 -// netNotifiee defines methods to be used with the IpfsDHT
302 -type netNotifiee IDService
303 -
304 -func (nn *netNotifiee) IDService() *IDService {
305 - return (*IDService)(nn)
306 -}
307 -
308 -func (nn *netNotifiee) Connected(n inet.Network, v inet.Conn) {
309 - // TODO: deprecate the setConnHandler hook, and kick off
310 - // identification here.
311 -}
312 -
313 -func (nn *netNotifiee) Disconnected(n inet.Network, v inet.Conn) {
314 - // undo the setting of addresses to peer.ConnectedAddrTTL we did
315 - ids := nn.IDService()
316 - ps := ids.Host.Peerstore()
317 - addrs := ps.Addrs(v.RemotePeer())
318 - ps.SetAddrs(v.RemotePeer(), addrs, peer.RecentlyConnectedAddrTTL)
319 -}
320 -
321 -func (nn *netNotifiee) OpenedStream(n inet.Network, v inet.Stream) {}
322 -func (nn *netNotifiee) ClosedStream(n inet.Network, v inet.Stream) {}
323 -func (nn *netNotifiee) Listen(n inet.Network, a ma.Multiaddr) {}
324 -func (nn *netNotifiee) ListenClose(n inet.Network, a ma.Multiaddr) {}
325 -
326 -func logProtocolMismatchDisconnect(c inet.Conn, protocol, agent string) {
327 - lm := make(lgbl.DeferredMap)
328 - lm["remotePeer"] = func() interface{} { return c.RemotePeer().Pretty() }
329 - lm["remoteAddr"] = func() interface{} { return c.RemoteMultiaddr().String() }
330 - lm["protocolVersion"] = protocol
331 - lm["agentVersion"] = agent
332 - log.Event(context.TODO(), "IdentifyProtocolMismatch", lm)
333 - log.Debug("IdentifyProtocolMismatch %s %s %s (disconnected)", c.RemotePeer(), protocol, agent)
334 -}
p2p/protocol/identify/id_test.go deleted
-106
@@ -1,106 +0,0 @@
1 -package identify_test
2 -
3 -import (
4 - "testing"
5 - "time"
6 -
7 - host "github.com/ipfs/go-ipfs/p2p/host"
8 - peer "github.com/ipfs/go-ipfs/p2p/peer"
9 - identify "github.com/ipfs/go-ipfs/p2p/protocol/identify"
10 - testutil "github.com/ipfs/go-ipfs/p2p/test/util"
11 -
12 - ma "github.com/ipfs/go-ipfs/Godeps/_workspace/src/github.com/jbenet/go-multiaddr"
13 - context "github.com/ipfs/go-ipfs/Godeps/_workspace/src/golang.org/x/net/context"
14 -)
15 -
16 -func subtestIDService(t *testing.T, postDialWait time.Duration) {
17 -
18 - // the generated networks should have the id service wired in.
19 - ctx := context.Background()
20 - h1 := testutil.GenHostSwarm(t, ctx)
21 - h2 := testutil.GenHostSwarm(t, ctx)
22 -
23 - h1p := h1.ID()
24 - h2p := h2.ID()
25 -
26 - testKnowsAddrs(t, h1, h2p, []ma.Multiaddr{}) // nothing
27 - testKnowsAddrs(t, h2, h1p, []ma.Multiaddr{}) // nothing
28 -
29 - h2pi := h2.Peerstore().PeerInfo(h2p)
30 - if err := h1.Connect(ctx, h2pi); err != nil {
31 - t.Fatal(err)
32 - }
33 -
34 - // we need to wait here if Dial returns before ID service is finished.
35 - if postDialWait > 0 {
36 - <-time.After(postDialWait)
37 - }
38 -
39 - // the IDService should be opened automatically, by the network.
40 - // what we should see now is that both peers know about each others listen addresses.
41 - testKnowsAddrs(t, h1, h2p, h2.Peerstore().Addrs(h2p)) // has them
42 - testHasProtocolVersions(t, h1, h2p)
43 -
44 - // now, this wait we do have to do. it's the wait for the Listening side
45 - // to be done identifying the connection.
46 - c := h2.Network().ConnsToPeer(h1.ID())
47 - if len(c) < 1 {
48 - t.Fatal("should have connection by now at least.")
49 - }
50 - <-h2.IDService().IdentifyWait(c[0])
51 -
52 - // and the protocol versions.
53 - testKnowsAddrs(t, h2, h1p, h1.Peerstore().Addrs(h1p)) // has them
54 - testHasProtocolVersions(t, h2, h1p)
55 -}
56 -
57 -func testKnowsAddrs(t *testing.T, h host.Host, p peer.ID, expected []ma.Multiaddr) {
58 - actual := h.Peerstore().Addrs(p)
59 -
60 - if len(actual) != len(expected) {
61 - t.Error("dont have the same addresses")
62 - }
63 -
64 - have := map[string]struct{}{}
65 - for _, addr := range actual {
66 - have[addr.String()] = struct{}{}
67 - }
68 - for _, addr := range expected {
69 - if _, found := have[addr.String()]; !found {
70 - t.Errorf("%s did not have addr for %s: %s", h.ID(), p, addr)
71 - // panic("ahhhhhhh")
72 - }
73 - }
74 -}
75 -
76 -func testHasProtocolVersions(t *testing.T, h host.Host, p peer.ID) {
77 - v, err := h.Peerstore().Get(p, "ProtocolVersion")
78 - if v == nil {
79 - t.Error("no protocol version")
80 - return
81 - }
82 - if v.(string) != identify.IpfsVersion {
83 - t.Error("protocol mismatch", err)
84 - }
85 - v, err = h.Peerstore().Get(p, "AgentVersion")
86 - if v.(string) != identify.ClientVersion {
87 - t.Error("agent version mismatch", err)
88 - }
89 -}
90 -
91 -// TestIDServiceWait gives the ID service 100ms to finish after dialing
92 -// this is becasue it used to be concurrent. Now, Dial wait till the
93 -// id service is done.
94 -func TestIDServiceWait(t *testing.T) {
95 - N := 3
96 - for i := 0; i < N; i++ {
97 - subtestIDService(t, 100*time.Millisecond)
98 - }
99 -}
100 -
101 -func TestIDServiceNoWait(t *testing.T) {
102 - N := 3
103 - for i := 0; i < N; i++ {
104 - subtestIDService(t, 0)
105 - }
106 -}
p2p/protocol/identify/obsaddr.go deleted
-121
@@ -1,121 +0,0 @@
1 -package identify
2 -
3 -import (
4 - "sync"
5 - "time"
6 -
7 - peer "github.com/ipfs/go-ipfs/p2p/peer"
8 -
9 - ma "github.com/ipfs/go-ipfs/Godeps/_workspace/src/github.com/jbenet/go-multiaddr"
10 -)
11 -
12 -// ObservedAddr is an entry for an address reported by our peers.
13 -// We only use addresses that:
14 -// - have been observed more than once. (counter symmetric nats)
15 -// - have been observed recently (10min), because our position in the
16 -// network, or network port mapppings, may have changed.
17 -type ObservedAddr struct {
18 - Addr ma.Multiaddr
19 - SeenBy map[string]struct{}
20 - LastSeen time.Time
21 -}
22 -
23 -// ObservedAddrSet keeps track of a set of ObservedAddrs
24 -// the zero-value is ready to be used.
25 -type ObservedAddrSet struct {
26 - sync.Mutex // guards whole datastruct.
27 -
28 - addrs map[string]*ObservedAddr
29 - ttl time.Duration
30 -}
31 -
32 -func (oas *ObservedAddrSet) Addrs() []ma.Multiaddr {
33 - oas.Lock()
34 - defer oas.Unlock()
35 -
36 - // for zero-value.
37 - if oas.addrs == nil {
38 - return nil
39 - }
40 -
41 - now := time.Now()
42 - addrs := make([]ma.Multiaddr, 0, len(oas.addrs))
43 - for s, a := range oas.addrs {
44 - // remove timed out addresses.
45 - if now.Sub(a.LastSeen) > oas.ttl {
46 - delete(oas.addrs, s)
47 - continue
48 - }
49 -
50 - // we only use an address if we've seen it more than once
51 - // because symmetric nats may cause all our peers to see
52 - // different port numbers and thus report always different
53 - // addresses (different ports) for us. These wouldn't be
54 - // very useful. We make the assumption that if we've
55 - // connected to two different peers, and they both have
56 - // reported seeing the same address, it is probably useful.
57 - //
58 - // Note: make sure not to double count observers.
59 - if len(a.SeenBy) > 1 {
60 - addrs = append(addrs, a.Addr)
61 - }
62 - }
63 - return addrs
64 -}
65 -
66 -func (oas *ObservedAddrSet) Add(addr ma.Multiaddr, observer ma.Multiaddr) {
67 - oas.Lock()
68 - defer oas.Unlock()
69 -
70 - // for zero-value.
71 - if oas.addrs == nil {
72 - oas.addrs = make(map[string]*ObservedAddr)
73 - oas.ttl = peer.OwnObservedAddrTTL
74 - }
75 -
76 - s := addr.String()
77 - oa, found := oas.addrs[s]
78 -
79 - // first time seeing address.
80 - if !found {
81 - oa = &ObservedAddr{
82 - Addr: addr,
83 - SeenBy: make(map[string]struct{}),
84 - }
85 - oas.addrs[s] = oa
86 - }
87 -
88 - // mark the observer
89 - oa.SeenBy[observerGroup(observer)] = struct{}{}
90 - oa.LastSeen = time.Now()
91 -}
92 -
93 -// observerGroup is a function that determines what part of
94 -// a multiaddr counts as a different observer. for example,
95 -// two ipfs nodes at the same IP/TCP transport would get
96 -// the exact same NAT mapping; they would count as the
97 -// same observer. This may protect against NATs who assign
98 -// different ports to addresses at different IP hosts, but
99 -// not TCP ports.
100 -//
101 -// Here, we use the root multiaddr address. This is mostly
102 -// IP addresses. In practice, this is what we want.
103 -func observerGroup(m ma.Multiaddr) string {
104 - return ma.Split(m)[0].String()
105 -}
106 -
107 -func (oas *ObservedAddrSet) SetTTL(ttl time.Duration) {
108 - oas.Lock()
109 - defer oas.Unlock()
110 - oas.ttl = ttl
111 -}
112 -
113 -func (oas *ObservedAddrSet) TTL() time.Duration {
114 - oas.Lock()
115 - defer oas.Unlock()
116 - // for zero-value.
117 - if oas.addrs == nil {
118 - oas.ttl = peer.OwnObservedAddrTTL
119 - }
120 - return oas.ttl
121 -}
p2p/protocol/identify/obsaddr_test.go deleted
-99
@@ -1,99 +0,0 @@
1 -package identify
2 -
3 -import (
4 - "testing"
5 - "time"
6 -
7 - ma "github.com/ipfs/go-ipfs/Godeps/_workspace/src/github.com/jbenet/go-multiaddr"
8 -)
9 -
10 -// TestObsAddrSet
11 -func TestObsAddrSet(t *testing.T) {
12 - m := func(s string) ma.Multiaddr {
13 - m, err := ma.NewMultiaddr(s)
14 - if err != nil {
15 - t.Error(err)
16 - }
17 - return m
18 - }
19 -
20 - addrsMarch := func(a, b []ma.Multiaddr) bool {
21 - for _, aa := range a {
22 - found := false
23 - for _, bb := range b {
24 - if aa.Equal(bb) {
25 - found = true
26 - break
27 - }
28 - }
29 - if !found {
30 - return false
31 - }
32 - }
33 - return true
34 - }
35 -
36 - a1 := m("/ip4/1.2.3.4/tcp/1231")
37 - a2 := m("/ip4/1.2.3.4/tcp/1232")
38 - a3 := m("/ip4/1.2.3.4/tcp/1233")
39 - a4 := m("/ip4/1.2.3.4/tcp/1234")
40 - a5 := m("/ip4/1.2.3.4/tcp/1235")
41 - a6 := m("/ip4/1.2.3.6/tcp/1236")
42 - a7 := m("/ip4/1.2.3.7/tcp/1237")
43 -
44 - oas := ObservedAddrSet{}
45 -
46 - if !addrsMarch(oas.Addrs(), nil) {
47 - t.Error("addrs should be empty")
48 - }
49 -
50 - oas.Add(a1, a4)
51 - oas.Add(a2, a4)
52 - oas.Add(a3, a4)
53 -
54 - // these are all different so we should not yet get them.
55 - if !addrsMarch(oas.Addrs(), nil) {
56 - t.Error("addrs should _still_ be empty (once)")
57 - }
58 -
59 - // same observer, so should not yet get them.
60 - oas.Add(a1, a4)
61 - oas.Add(a2, a4)
62 - oas.Add(a3, a4)
63 - if !addrsMarch(oas.Addrs(), nil) {
64 - t.Error("addrs should _still_ be empty (same obs)")
65 - }
66 -
67 - // different observer, but same observer group.
68 - oas.Add(a1, a5)
69 - oas.Add(a2, a5)
70 - oas.Add(a3, a5)
71 - if !addrsMarch(oas.Addrs(), nil) {
72 - t.Error("addrs should _still_ be empty (same obs group)")
73 - }
74 -
75 - oas.Add(a1, a6)
76 - if !addrsMarch(oas.Addrs(), []ma.Multiaddr{a1}) {
77 - t.Error("addrs should only have a1")
78 - }
79 -
80 - oas.Add(a2, a5)
81 - oas.Add(a1, a5)
82 - oas.Add(a1, a5)
83 - oas.Add(a2, a6)
84 - oas.Add(a1, a6)
85 - oas.Add(a1, a6)
86 - oas.Add(a2, a7)
87 - oas.Add(a1, a7)
88 - oas.Add(a1, a7)
89 - if !addrsMarch(oas.Addrs(), []ma.Multiaddr{a1, a2}) {
90 - t.Error("addrs should only have a1, a2")
91 - }
92 -
93 - // change the timeout constant so we can time it out.
94 - oas.SetTTL(time.Millisecond * 200)
95 - <-time.After(time.Millisecond * 210)
96 - if !addrsMarch(oas.Addrs(), []ma.Multiaddr{nil}) {
97 - t.Error("addrs should have timed out")
98 - }
99 -}
p2p/protocol/identify/pb/Makefile deleted
-11
@@ -1,11 +0,0 @@
1 -
2 -PB = $(wildcard *.proto)
3 -GO = $(PB:.proto=.pb.go)
4 -
5 -all: $(GO)
6 -
7 -%.pb.go: %.proto
8 - protoc --gogo_out=. --proto_path=../../../../../../:/usr/local/opt/protobuf/include:. $<
9 -
10 -clean:
11 - rm *.pb.go
p2p/protocol/identify/pb/identify.pb.go deleted
-91
@@ -1,91 +0,0 @@
1 -// Code generated by protoc-gen-gogo.
2 -// source: identify.proto
3 -// DO NOT EDIT!
4 -
5 -/*
6 -Package identify_pb is a generated protocol buffer package.
7 -
8 -It is generated from these files:
9 - identify.proto
10 -
11 -It has these top-level messages:
12 - Identify
13 -*/
14 -package identify_pb
15 -
16 -import proto "github.com/ipfs/go-ipfs/Godeps/_workspace/src/github.com/gogo/protobuf/proto"
17 -import math "math"
18 -
19 -// Reference imports to suppress errors if they are not otherwise used.
20 -var _ = proto.Marshal
21 -var _ = math.Inf
22 -
23 -type Identify struct {
24 - // protocolVersion determines compatibility between peers
25 - ProtocolVersion *string `protobuf:"bytes,5,opt,name=protocolVersion" json:"protocolVersion,omitempty"`
26 - // agentVersion is like a UserAgent string in browsers, or client version in bittorrent
27 - // includes the client name and client.
28 - AgentVersion *string `protobuf:"bytes,6,opt,name=agentVersion" json:"agentVersion,omitempty"`
29 - // publicKey is this node's public key (which also gives its node.ID)
30 - // - may not need to be sent, as secure channel implies it has been sent.
31 - // - then again, if we change / disable secure channel, may still want it.
32 - PublicKey []byte `protobuf:"bytes,1,opt,name=publicKey" json:"publicKey,omitempty"`
33 - // listenAddrs are the multiaddrs the sender node listens for open connections on
34 - ListenAddrs [][]byte `protobuf:"bytes,2,rep,name=listenAddrs" json:"listenAddrs,omitempty"`
35 - // oservedAddr is the multiaddr of the remote endpoint that the sender node perceives
36 - // this is useful information to convey to the other side, as it helps the remote endpoint
37 - // determine whether its connection to the local peer goes through NAT.
38 - ObservedAddr []byte `protobuf:"bytes,4,opt,name=observedAddr" json:"observedAddr,omitempty"`
39 - // protocols are the services this node is running
40 - Protocols []string `protobuf:"bytes,3,rep,name=protocols" json:"protocols,omitempty"`
41 - XXX_unrecognized []byte `json:"-"`
42 -}
43 -
44 -func (m *Identify) Reset() { *m = Identify{} }
45 -func (m *Identify) String() string { return proto.CompactTextString(m) }
46 -func (*Identify) ProtoMessage() {}
47 -
48 -func (m *Identify) GetProtocolVersion() string {
49 - if m != nil && m.ProtocolVersion != nil {
50 - return *m.ProtocolVersion
51 - }
52 - return ""
53 -}
54 -
55 -func (m *Identify) GetAgentVersion() string {
56 - if m != nil && m.AgentVersion != nil {
57 - return *m.AgentVersion
58 - }
59 - return ""
60 -}
61 -
62 -func (m *Identify) GetPublicKey() []byte {
63 - if m != nil {
64 - return m.PublicKey
65 - }
66 - return nil
67 -}
68 -
69 -func (m *Identify) GetListenAddrs() [][]byte {
70 - if m != nil {
71 - return m.ListenAddrs
72 - }
73 - return nil
74 -}
75 -
76 -func (m *Identify) GetObservedAddr() []byte {
77 - if m != nil {
78 - return m.ObservedAddr
79 - }
80 - return nil
81 -}
82 -
83 -func (m *Identify) GetProtocols() []string {
84 - if m != nil {
85 - return m.Protocols
86 - }
87 - return nil
88 -}
89 -
90 -func init() {
91 -}
p2p/protocol/identify/pb/identify.proto deleted
-27
@@ -1,27 +0,0 @@
1 -package identify.pb;
2 -
3 -message Identify {
4 -
5 - // protocolVersion determines compatibility between peers
6 - optional string protocolVersion = 5; // e.g. ipfs/1.0.0
7 -
8 - // agentVersion is like a UserAgent string in browsers, or client version in bittorrent
9 - // includes the client name and client.
10 - optional string agentVersion = 6; // e.g. go-ipfs/0.1.0
11 -
12 - // publicKey is this node's public key (which also gives its node.ID)
13 - // - may not need to be sent, as secure channel implies it has been sent.
14 - // - then again, if we change / disable secure channel, may still want it.
15 - optional bytes publicKey = 1;
16 -
17 - // listenAddrs are the multiaddrs the sender node listens for open connections on
18 - repeated bytes listenAddrs = 2;
19 -
20 - // oservedAddr is the multiaddr of the remote endpoint that the sender node perceives
21 - // this is useful information to convey to the other side, as it helps the remote endpoint
22 - // determine whether its connection to the local peer goes through NAT.
23 - optional bytes observedAddr = 4;
24 -
25 - // protocols are the services this node is running
26 - repeated string protocols = 3;
27 -}
p2p/protocol/ping/ping.go deleted
-105
@@ -1,105 +0,0 @@
1 -package ping
2 -
3 -import (
4 - "bytes"
5 - "errors"
6 - "io"
7 - "time"
8 -
9 - context "github.com/ipfs/go-ipfs/Godeps/_workspace/src/golang.org/x/net/context"
10 -
11 - host "github.com/ipfs/go-ipfs/p2p/host"
12 - inet "github.com/ipfs/go-ipfs/p2p/net"
13 - peer "github.com/ipfs/go-ipfs/p2p/peer"
14 - u "github.com/ipfs/go-ipfs/util"
15 - logging "github.com/ipfs/go-ipfs/vendor/QmQg1J6vikuXF9oDvm4wpdeAUvvkVEKW1EYDw9HhTMnP2b/go-log"
16 -)
17 -
18 -var log = logging.Logger("ping")
19 -
20 -const PingSize = 32
21 -
22 -const ID = "/ipfs/ping"
23 -
24 -type PingService struct {
25 - Host host.Host
26 -}
27 -
28 -func NewPingService(h host.Host) *PingService {
29 - ps := &PingService{h}
30 - h.SetStreamHandler(ID, ps.PingHandler)
31 - return ps
32 -}
33 -
34 -func (p *PingService) PingHandler(s inet.Stream) {
35 - buf := make([]byte, PingSize)
36 -
37 - for {
38 - _, err := io.ReadFull(s, buf)
39 - if err != nil {
40 - log.Debug(err)
41 - return
42 - }
43 -
44 - _, err = s.Write(buf)
45 - if err != nil {
46 - log.Debug(err)
47 - return
48 - }
49 - }
50 -}
51 -
52 -func (ps *PingService) Ping(ctx context.Context, p peer.ID) (<-chan time.Duration, error) {
53 - s, err := ps.Host.NewStream(ID, p)
54 - if err != nil {
55 - return nil, err
56 - }
57 -
58 - out := make(chan time.Duration)
59 - go func() {
60 - defer close(out)
61 - for {
62 - select {
63 - case <-ctx.Done():
64 - return
65 - default:
66 - t, err := ping(s)
67 - if err != nil {
68 - log.Debugf("ping error: %s", err)
69 - return
70 - }
71 -
72 - select {
73 - case out <- t:
74 - case <-ctx.Done():
75 - return
76 - }
77 - }
78 - }
79 - }()
80 -
81 - return out, nil
82 -}
83 -
84 -func ping(s inet.Stream) (time.Duration, error) {
85 - buf := make([]byte, PingSize)
86 - u.NewTimeSeededRand().Read(buf)
87 -
88 - before := time.Now()
89 - _, err := s.Write(buf)
90 - if err != nil {
91 - return 0, err
92 - }
93 -
94 - rbuf := make([]byte, PingSize)
95 - _, err = io.ReadFull(s, rbuf)
96 - if err != nil {
97 - return 0, err
98 - }
99 -
100 - if !bytes.Equal(buf, rbuf) {
101 - return 0, errors.New("ping packet was incorrect!")
102 - }
103 -
104 - return time.Now().Sub(before), nil
105 -}
p2p/protocol/ping/ping_test.go deleted
-51
@@ -1,51 +0,0 @@
1 -package ping
2 -
3 -import (
4 - "testing"
5 - "time"
6 -
7 - context "github.com/ipfs/go-ipfs/Godeps/_workspace/src/golang.org/x/net/context"
8 - peer "github.com/ipfs/go-ipfs/p2p/peer"
9 - netutil "github.com/ipfs/go-ipfs/p2p/test/util"
10 -)
11 -
12 -func TestPing(t *testing.T) {
13 - ctx, cancel := context.WithCancel(context.Background())
14 - defer cancel()
15 - h1 := netutil.GenHostSwarm(t, ctx)
16 - h2 := netutil.GenHostSwarm(t, ctx)
17 -
18 - err := h1.Connect(ctx, peer.PeerInfo{
19 - ID: h2.ID(),
20 - Addrs: h2.Addrs(),
21 - })
22 -
23 - if err != nil {
24 - t.Fatal(err)
25 - }
26 -
27 - ps1 := NewPingService(h1)
28 - ps2 := NewPingService(h2)
29 -
30 - testPing(t, ps1, h2.ID())
31 - testPing(t, ps2, h1.ID())
32 -}
33 -
34 -func testPing(t *testing.T, ps *PingService, p peer.ID) {
35 - pctx, cancel := context.WithCancel(context.Background())
36 - defer cancel()
37 - ts, err := ps.Ping(pctx, p)
38 - if err != nil {
39 - t.Fatal(err)
40 - }
41 -
42 - for i := 0; i < 5; i++ {
43 - select {
44 - case took := <-ts:
45 - t.Log("ping took: ", took)
46 - case <-time.After(time.Second * 4):
47 - t.Fatal("failed to receive ping")
48 - }
49 - }
50 -
51 -}
p2p/protocol/protocol.go deleted
-9
@@ -1,9 +0,0 @@
1 -package protocol
2 -
3 -// ID is an identifier used to write protocol headers in streams.
4 -type ID string
5 -
6 -// These are reserved protocol.IDs.
7 -const (
8 - TestingID ID = "/p2p/_testing"
9 -)
p2p/protocol/relay/relay.go deleted
-156
@@ -1,156 +0,0 @@
1 -package relay
2 -
3 -import (
4 - "fmt"
5 - "io"
6 -
7 - mh "github.com/ipfs/go-ipfs/Godeps/_workspace/src/github.com/jbenet/go-multihash"
8 -
9 - host "github.com/ipfs/go-ipfs/p2p/host"
10 - inet "github.com/ipfs/go-ipfs/p2p/net"
11 - peer "github.com/ipfs/go-ipfs/p2p/peer"
12 - protocol "github.com/ipfs/go-ipfs/p2p/protocol"
13 - logging "github.com/ipfs/go-ipfs/vendor/QmQg1J6vikuXF9oDvm4wpdeAUvvkVEKW1EYDw9HhTMnP2b/go-log"
14 -)
15 -
16 -var log = logging.Logger("p2p/protocol/relay")
17 -
18 -// ID is the protocol.ID of the Relay Service.
19 -const ID protocol.ID = "/ipfs/relay"
20 -
21 -// Relay is a structure that implements ProtocolRelay.
22 -// It is a simple relay service which forwards traffic
23 -// between two directly connected peers.
24 -//
25 -// the protocol is very simple:
26 -//
27 -// /ipfs/relay\n
28 -// <multihash src id>
29 -// <multihash dst id>
30 -// <data stream>
31 -//
32 -type RelayService struct {
33 - host host.Host
34 - handler inet.StreamHandler // for streams sent to us locally.
35 -}
36 -
37 -func NewRelayService(h host.Host, sh inet.StreamHandler) *RelayService {
38 - s := &RelayService{
39 - host: h,
40 - handler: sh,
41 - }
42 - h.SetStreamHandler(ID, s.requestHandler)
43 - return s
44 -}
45 -
46 -// requestHandler is the function called by clients
47 -func (rs *RelayService) requestHandler(s inet.Stream) {
48 - if err := rs.handleStream(s); err != nil {
49 - log.Debugf("RelayService error:", err)
50 - }
51 -}
52 -
53 -// handleStream is our own handler, which returns an error for simplicity.
54 -func (rs *RelayService) handleStream(s inet.Stream) error {
55 - defer s.Close()
56 -
57 - // read the header (src and dst peer.IDs)
58 - src, dst, err := ReadHeader(s)
59 - if err != nil {
60 - return fmt.Errorf("stream with bad header: %s", err)
61 - }
62 -
63 - local := rs.host.ID()
64 -
65 - switch {
66 - case src == local:
67 - return fmt.Errorf("relaying from self")
68 - case dst == local: // it's for us! yaaay.
69 - log.Debugf("%s consuming stream from %s", local, src)
70 - return rs.consumeStream(s)
71 - default: // src and dst are not local. relay it.
72 - log.Debugf("%s relaying stream %s <--> %s", local, src, dst)
73 - return rs.pipeStream(src, dst, s)
74 - }
75 -}
76 -
77 -// consumeStream connects streams directed to the local peer
78 -// to our handler, with the header now stripped (read).
79 -func (rs *RelayService) consumeStream(s inet.Stream) error {
80 - rs.handler(s) // boom.
81 - return nil
82 -}
83 -
84 -// pipeStream relays over a stream to a remote peer. It's like `cat`
85 -func (rs *RelayService) pipeStream(src, dst peer.ID, s inet.Stream) error {
86 - s2, err := rs.openStreamToPeer(dst)
87 - if err != nil {
88 - return fmt.Errorf("failed to open stream to peer: %s -- %s", dst, err)
89 - }
90 -
91 - if err := WriteHeader(s2, src, dst); err != nil {
92 - return err
93 - }
94 -
95 - // connect the series of tubes.
96 - done := make(chan retio, 2)
97 - go func() {
98 - n, err := io.Copy(s2, s)
99 - done <- retio{n, err}
100 - }()
101 - go func() {
102 - n, err := io.Copy(s, s2)
103 - done <- retio{n, err}
104 - }()
105 -
106 - r1 := <-done
107 - r2 := <-done
108 - log.Infof("%s relayed %d/%d bytes between %s and %s", rs.host.ID(), r1.n, r2.n, src, dst)
109 -
110 - if r1.err != nil {
111 - return r1.err
112 - }
113 - return r2.err
114 -}
115 -
116 -// openStreamToPeer opens a pipe to a remote endpoint
117 -// for now, can only open streams to directly connected peers.
118 -// maybe we can do some routing later on.
119 -func (rs *RelayService) openStreamToPeer(p peer.ID) (inet.Stream, error) {
120 - return rs.host.NewStream(ID, p)
121 -}
122 -
123 -func ReadHeader(r io.Reader) (src, dst peer.ID, err error) {
124 -
125 - mhr := mh.NewReader(r)
126 -
127 - s, err := mhr.ReadMultihash()
128 - if err != nil {
129 - return "", "", err
130 - }
131 -
132 - d, err := mhr.ReadMultihash()
133 - if err != nil {
134 - return "", "", err
135 - }
136 -
137 - return peer.ID(s), peer.ID(d), nil
138 -}
139 -
140 -func WriteHeader(w io.Writer, src, dst peer.ID) error {
141 - // write header to w.
142 - mhw := mh.NewWriter(w)
143 - if err := mhw.WriteMultihash(mh.Multihash(src)); err != nil {
144 - return fmt.Errorf("failed to write relay header: %s -- %s", dst, err)
145 - }
146 - if err := mhw.WriteMultihash(mh.Multihash(dst)); err != nil {
147 - return fmt.Errorf("failed to write relay header: %s -- %s", dst, err)
148 - }
149 -
150 - return nil
151 -}
152 -
153 -type retio struct {
154 - n int64
155 - err error
156 -}
p2p/protocol/relay/relay_test.go deleted
-304
@@ -1,304 +0,0 @@
1 -package relay_test
2 -
3 -import (
4 - "io"
5 - "testing"
6 -
7 - inet "github.com/ipfs/go-ipfs/p2p/net"
8 - protocol "github.com/ipfs/go-ipfs/p2p/protocol"
9 - relay "github.com/ipfs/go-ipfs/p2p/protocol/relay"
10 - testutil "github.com/ipfs/go-ipfs/p2p/test/util"
11 - logging "github.com/ipfs/go-ipfs/vendor/QmQg1J6vikuXF9oDvm4wpdeAUvvkVEKW1EYDw9HhTMnP2b/go-log"
12 -
13 - msmux "github.com/ipfs/go-ipfs/Godeps/_workspace/src/github.com/whyrusleeping/go-multistream"
14 - context "github.com/ipfs/go-ipfs/Godeps/_workspace/src/golang.org/x/net/context"
15 -)
16 -
17 -var log = logging.Logger("relay_test")
18 -
19 -func TestRelaySimple(t *testing.T) {
20 -
21 - ctx := context.Background()
22 -
23 - // these networks have the relay service wired in already.
24 - n1 := testutil.GenHostSwarm(t, ctx)
25 - n2 := testutil.GenHostSwarm(t, ctx)
26 - n3 := testutil.GenHostSwarm(t, ctx)
27 -
28 - n1p := n1.ID()
29 - n2p := n2.ID()
30 - n3p := n3.ID()
31 -
32 - n2pi := n2.Peerstore().PeerInfo(n2p)
33 - if err := n1.Connect(ctx, n2pi); err != nil {
34 - t.Fatal("Failed to connect:", err)
35 - }
36 - if err := n3.Connect(ctx, n2pi); err != nil {
37 - t.Fatal("Failed to connect:", err)
38 - }
39 -
40 - // setup handler on n3 to copy everything over to the pipe.
41 - piper, pipew := io.Pipe()
42 - n3.SetStreamHandler(protocol.TestingID, func(s inet.Stream) {
43 - log.Debug("relay stream opened to n3!")
44 - log.Debug("piping and echoing everything")
45 - w := io.MultiWriter(s, pipew)
46 - io.Copy(w, s)
47 - log.Debug("closing stream")
48 - s.Close()
49 - })
50 -
51 - // ok, now we can try to relay n1--->n2--->n3.
52 - log.Debug("open relay stream")
53 - s, err := n1.NewStream(relay.ID, n2p)
54 - if err != nil {
55 - t.Fatal(err)
56 - }
57 -
58 - // ok first thing we write the relay header n1->n3
59 - log.Debug("write relay header")
60 - if err := relay.WriteHeader(s, n1p, n3p); err != nil {
61 - t.Fatal(err)
62 - }
63 -
64 - // ok now the header's there, we can write the next protocol header.
65 - log.Debug("write testing header")
66 - if err := msmux.SelectProtoOrFail(string(protocol.TestingID), s); err != nil {
67 - t.Fatal(err)
68 - }
69 -
70 - // okay, now we should be able to write text, and read it out.
71 - buf1 := []byte("abcdefghij")
72 - buf2 := make([]byte, 10)
73 - buf3 := make([]byte, 10)
74 - log.Debug("write in some text.")
75 - if _, err := s.Write(buf1); err != nil {
76 - t.Fatal(err)
77 - }
78 -
79 - // read it out from the pipe.
80 - log.Debug("read it out from the pipe.")
81 - if _, err := io.ReadFull(piper, buf2); err != nil {
82 - t.Fatal(err)
83 - }
84 - if string(buf1) != string(buf2) {
85 - t.Fatal("should've gotten that text out of the pipe")
86 - }
87 -
88 - // read it out from the stream (echoed)
89 - log.Debug("read it out from the stream (echoed).")
90 - if _, err := io.ReadFull(s, buf3); err != nil {
91 - t.Fatal(err)
92 - }
93 - if string(buf1) != string(buf3) {
94 - t.Fatal("should've gotten that text out of the stream")
95 - }
96 -
97 - // sweet. relay works.
98 - log.Debug("sweet, relay works.")
99 - s.Close()
100 -}
101 -
102 -func TestRelayAcrossFour(t *testing.T) {
103 -
104 - ctx := context.Background()
105 -
106 - // these networks have the relay service wired in already.
107 - n1 := testutil.GenHostSwarm(t, ctx)
108 - n2 := testutil.GenHostSwarm(t, ctx)
109 - n3 := testutil.GenHostSwarm(t, ctx)
110 - n4 := testutil.GenHostSwarm(t, ctx)
111 - n5 := testutil.GenHostSwarm(t, ctx)
112 -
113 - n1p := n1.ID()
114 - n2p := n2.ID()
115 - n3p := n3.ID()
116 - n4p := n4.ID()
117 - n5p := n5.ID()
118 -
119 - n2pi := n2.Peerstore().PeerInfo(n2p)
120 - n4pi := n4.Peerstore().PeerInfo(n4p)
121 -
122 - if err := n1.Connect(ctx, n2pi); err != nil {
123 - t.Fatalf("Failed to dial:", err)
124 - }
125 - if err := n3.Connect(ctx, n2pi); err != nil {
126 - t.Fatalf("Failed to dial:", err)
127 - }
128 - if err := n3.Connect(ctx, n4pi); err != nil {
129 - t.Fatalf("Failed to dial:", err)
130 - }
131 - if err := n5.Connect(ctx, n4pi); err != nil {
132 - t.Fatalf("Failed to dial:", err)
133 - }
134 -
135 - // setup handler on n5 to copy everything over to the pipe.
136 - piper, pipew := io.Pipe()
137 - n5.SetStreamHandler(protocol.TestingID, func(s inet.Stream) {
138 - log.Debug("relay stream opened to n5!")
139 - log.Debug("piping and echoing everything")
140 - w := io.MultiWriter(s, pipew)
141 - io.Copy(w, s)
142 - log.Debug("closing stream")
143 - s.Close()
144 - })
145 -
146 - // ok, now we can try to relay n1--->n2--->n3--->n4--->n5
147 - log.Debug("open relay stream")
148 - s, err := n1.NewStream(relay.ID, n2p)
149 - if err != nil {
150 - t.Fatal(err)
151 - }
152 -
153 - log.Debugf("write relay header n1->n3 (%s -> %s)", n1p, n3p)
154 - if err := relay.WriteHeader(s, n1p, n3p); err != nil {
155 - t.Fatal(err)
156 - }
157 -
158 - log.Debugf("write relay header n1->n4 (%s -> %s)", n1p, n4p)
159 - if err := msmux.SelectProtoOrFail(string(relay.ID), s); err != nil {
160 - t.Fatal(err)
161 - }
162 - if err := relay.WriteHeader(s, n1p, n4p); err != nil {
163 - t.Fatal(err)
164 - }
165 -
166 - log.Debugf("write relay header n1->n5 (%s -> %s)", n1p, n5p)
167 - if err := msmux.SelectProtoOrFail(string(relay.ID), s); err != nil {
168 - t.Fatal(err)
169 - }
170 - if err := relay.WriteHeader(s, n1p, n5p); err != nil {
171 - t.Fatal(err)
172 - }
173 -
174 - // ok now the header's there, we can write the next protocol header.
175 - log.Debug("write testing header")
176 - if err := msmux.SelectProtoOrFail(string(protocol.TestingID), s); err != nil {
177 - t.Fatal(err)
178 - }
179 -
180 - // okay, now we should be able to write text, and read it out.
181 - buf1 := []byte("abcdefghij")
182 - buf2 := make([]byte, 10)
183 - buf3 := make([]byte, 10)
184 - log.Debug("write in some text.")
185 - if _, err := s.Write(buf1); err != nil {
186 - t.Fatal(err)
187 - }
188 -
189 - // read it out from the pipe.
190 - log.Debug("read it out from the pipe.")
191 - if _, err := io.ReadFull(piper, buf2); err != nil {
192 - t.Fatal(err)
193 - }
194 - if string(buf1) != string(buf2) {
195 - t.Fatal("should've gotten that text out of the pipe")
196 - }
197 -
198 - // read it out from the stream (echoed)
199 - log.Debug("read it out from the stream (echoed).")
200 - if _, err := io.ReadFull(s, buf3); err != nil {
201 - t.Fatal(err)
202 - }
203 - if string(buf1) != string(buf3) {
204 - t.Fatal("should've gotten that text out of the stream")
205 - }
206 -
207 - // sweet. relay works.
208 - log.Debug("sweet, relaying across 4 works.")
209 - s.Close()
210 -}
211 -
212 -func TestRelayStress(t *testing.T) {
213 - buflen := 1 << 18
214 - iterations := 10
215 -
216 - ctx := context.Background()
217 -
218 - // these networks have the relay service wired in already.
219 - n1 := testutil.GenHostSwarm(t, ctx)
220 - n2 := testutil.GenHostSwarm(t, ctx)
221 - n3 := testutil.GenHostSwarm(t, ctx)
222 -
223 - n1p := n1.ID()
224 - n2p := n2.ID()
225 - n3p := n3.ID()
226 -
227 - n2pi := n2.Peerstore().PeerInfo(n2p)
228 - if err := n1.Connect(ctx, n2pi); err != nil {
229 - t.Fatalf("Failed to dial:", err)
230 - }
231 - if err := n3.Connect(ctx, n2pi); err != nil {
232 - t.Fatalf("Failed to dial:", err)
233 - }
234 -
235 - // setup handler on n3 to copy everything over to the pipe.
236 - piper, pipew := io.Pipe()
237 - n3.SetStreamHandler(protocol.TestingID, func(s inet.Stream) {
238 - log.Debug("relay stream opened to n3!")
239 - log.Debug("piping and echoing everything")
240 - w := io.MultiWriter(s, pipew)
241 - io.Copy(w, s)
242 - log.Debug("closing stream")
243 - s.Close()
244 - })
245 -
246 - // ok, now we can try to relay n1--->n2--->n3.
247 - log.Debug("open relay stream")
248 - s, err := n1.NewStream(relay.ID, n2p)
249 - if err != nil {
250 - t.Fatal(err)
251 - }
252 -
253 - // ok first thing we write the relay header n1->n3
254 - log.Debug("write relay header")
255 - if err := relay.WriteHeader(s, n1p, n3p); err != nil {
256 - t.Fatal(err)
257 - }
258 -
259 - // ok now the header's there, we can write the next protocol header.
260 - log.Debug("write testing header")
261 - if err := msmux.SelectProtoOrFail(string(protocol.TestingID), s); err != nil {
262 - t.Fatal(err)
263 - }
264 -
265 - // okay, now write lots of text and read it back out from both
266 - // the pipe and the stream.
267 - buf1 := make([]byte, buflen)
268 - buf2 := make([]byte, len(buf1))
269 - buf3 := make([]byte, len(buf1))
270 -
271 - fillbuf := func(buf []byte, b byte) {
272 - for i := range buf {
273 - buf[i] = b
274 - }
275 - }
276 -
277 - for i := 0; i < iterations; i++ {
278 - fillbuf(buf1, byte(int('a')+i))
279 - log.Debugf("writing %d bytes (%d/%d)", len(buf1), i, iterations)
280 - if _, err := s.Write(buf1); err != nil {
281 - t.Fatal(err)
282 - }
283 -
284 - log.Debug("read it out from the pipe.")
285 - if _, err := io.ReadFull(piper, buf2); err != nil {
286 - t.Fatal(err)
287 - }
288 - if string(buf1) != string(buf2) {
289 - t.Fatal("should've gotten that text out of the pipe")
290 - }
291 -
292 - // read it out from the stream (echoed)
293 - log.Debug("read it out from the stream (echoed).")
294 - if _, err := io.ReadFull(s, buf3); err != nil {
295 - t.Fatal(err)
296 - }
297 - if string(buf1) != string(buf3) {
298 - t.Fatal("should've gotten that text out of the stream")
299 - }
300 - }
301 -
302 - log.Debug("sweet, relay works under stress.")
303 - s.Close()
304 -}
p2p/test/backpressure/backpressure.go deleted
-1
@@ -1 +0,0 @@
1 -package backpressure_tests
p2p/test/backpressure/backpressure_test.go deleted
-380
@@ -1,380 +0,0 @@
1 -package backpressure_tests
2 -
3 -import (
4 - "io"
5 - "math/rand"
6 - "testing"
7 - "time"
8 -
9 - host "github.com/ipfs/go-ipfs/p2p/host"
10 - inet "github.com/ipfs/go-ipfs/p2p/net"
11 - peer "github.com/ipfs/go-ipfs/p2p/peer"
12 - protocol "github.com/ipfs/go-ipfs/p2p/protocol"
13 - testutil "github.com/ipfs/go-ipfs/p2p/test/util"
14 - logging "github.com/ipfs/go-ipfs/vendor/QmQg1J6vikuXF9oDvm4wpdeAUvvkVEKW1EYDw9HhTMnP2b/go-log"
15 -
16 - context "github.com/ipfs/go-ipfs/Godeps/_workspace/src/golang.org/x/net/context"
17 - u "github.com/ipfs/go-ipfs/util"
18 -)
19 -
20 -var log = logging.Logger("backpressure")
21 -
22 -// TestBackpressureStreamHandler tests whether mux handler
23 -// ratelimiting works. Meaning, since the handler is sequential
24 -// it should block senders.
25 -//
26 -// Important note: spdystream (which peerstream uses) has a set
27 -// of n workers (n=spdsystream.FRAME_WORKERS) which handle new
28 -// frames, including those starting new streams. So all of them
29 -// can be in the handler at one time. Also, the sending side
30 -// does not rate limit unless we call stream.Wait()
31 -//
32 -//
33 -// Note: right now, this happens muxer-wide. the muxer should
34 -// learn to flow control, so handlers cant block each other.
35 -func TestBackpressureStreamHandler(t *testing.T) {
36 - t.Skip(`Sadly, as cool as this test is, it doesn't work
37 -Because spdystream doesnt handle stream open backpressure
38 -well IMO. I'll see about rewriting that part when it becomes
39 -a problem.
40 -`)
41 -
42 - // a number of concurrent request handlers
43 - limit := 10
44 -
45 - // our way to signal that we're done with 1 request
46 - requestHandled := make(chan struct{})
47 -
48 - // handler rate limiting
49 - receiverRatelimit := make(chan struct{}, limit)
50 - for i := 0; i < limit; i++ {
51 - receiverRatelimit <- struct{}{}
52 - }
53 -
54 - // sender counter of successfully opened streams
55 - senderOpened := make(chan struct{}, limit*100)
56 -
57 - // sender signals it's done (errored out)
58 - senderDone := make(chan struct{})
59 -
60 - // the receiver handles requests with some rate limiting
61 - receiver := func(s inet.Stream) {
62 - log.Debug("receiver received a stream")
63 -
64 - <-receiverRatelimit // acquire
65 - go func() {
66 - // our request handler. can do stuff here. we
67 - // simulate something taking time by waiting
68 - // on requestHandled
69 - log.Debug("request worker handling...")
70 - <-requestHandled
71 - log.Debug("request worker done!")
72 - receiverRatelimit <- struct{}{} // release
73 - }()
74 - }
75 -
76 - // the sender opens streams as fast as possible
77 - sender := func(host host.Host, remote peer.ID) {
78 - var s inet.Stream
79 - var err error
80 - defer func() {
81 - t.Error(err)
82 - log.Debug("sender error. exiting.")
83 - senderDone <- struct{}{}
84 - }()
85 -
86 - for {
87 - s, err = host.NewStream(protocol.TestingID, remote)
88 - if err != nil {
89 - return
90 - }
91 -
92 - _ = s
93 - // if err = s.SwarmStream().Stream().Wait(); err != nil {
94 - // return
95 - // }
96 -
97 - // "count" another successfully opened stream
98 - // (large buffer so shouldn't block in normal operation)
99 - log.Debug("sender opened another stream!")
100 - senderOpened <- struct{}{}
101 - }
102 - }
103 -
104 - // count our senderOpened events
105 - countStreamsOpenedBySender := func(min int) int {
106 - opened := 0
107 - for opened < min {
108 - log.Debugf("countStreamsOpenedBySender got %d (min %d)", opened, min)
109 - select {
110 - case <-senderOpened:
111 - opened++
112 - case <-time.After(10 * time.Millisecond):
113 - }
114 - }
115 - return opened
116 - }
117 -
118 - // count our received events
119 - // waitForNReceivedStreams := func(n int) {
120 - // for n > 0 {
121 - // log.Debugf("waiting for %d received streams...", n)
122 - // select {
123 - // case <-receiverRatelimit:
124 - // n--
125 - // }
126 - // }
127 - // }
128 -
129 - testStreamsOpened := func(expected int) {
130 - log.Debugf("testing rate limited to %d streams", expected)
131 - if n := countStreamsOpenedBySender(expected); n != expected {
132 - t.Fatalf("rate limiting did not work :( -- %d != %d", expected, n)
133 - }
134 - }
135 -
136 - // ok that's enough setup. let's do it!
137 -
138 - ctx := context.Background()
139 - h1 := testutil.GenHostSwarm(t, ctx)
140 - h2 := testutil.GenHostSwarm(t, ctx)
141 -
142 - // setup receiver handler
143 - h1.SetStreamHandler(protocol.TestingID, receiver)
144 -
145 - h2pi := h2.Peerstore().PeerInfo(h2.ID())
146 - log.Debugf("dialing %s", h2pi.Addrs)
147 - if err := h1.Connect(ctx, h2pi); err != nil {
148 - t.Fatalf("Failed to connect:", err)
149 - }
150 -
151 - // launch sender!
152 - go sender(h2, h1.ID())
153 -
154 - // ok, what do we expect to happen? the receiver should
155 - // receive 10 requests and stop receiving, blocking the sender.
156 - // we can test this by counting 10x senderOpened requests
157 -
158 - <-senderOpened // wait for the sender to successfully open some.
159 - testStreamsOpened(limit - 1)
160 -
161 - // let's "handle" 3 requests.
162 - <-requestHandled
163 - <-requestHandled
164 - <-requestHandled
165 - // the sender should've now been able to open exactly 3 more.
166 -
167 - testStreamsOpened(3)
168 -
169 - // shouldn't have opened anything more
170 - testStreamsOpened(0)
171 -
172 - // let's "handle" 100 requests in batches of 5
173 - for i := 0; i < 20; i++ {
174 - <-requestHandled
175 - <-requestHandled
176 - <-requestHandled
177 - <-requestHandled
178 - <-requestHandled
179 - testStreamsOpened(5)
180 - }
181 -
182 - // success!
183 -
184 - // now for the sugar on top: let's tear down the receiver. it should
185 - // exit the sender.
186 - h1.Close()
187 -
188 - // shouldn't have opened anything more
189 - testStreamsOpened(0)
190 -
191 - select {
192 - case <-time.After(100 * time.Millisecond):
193 - t.Error("receiver shutdown failed to exit sender")
194 - case <-senderDone:
195 - log.Info("handler backpressure works!")
196 - }
197 -}
198 -
199 -// TestStBackpressureStreamWrite tests whether streams see proper
200 -// backpressure when writing data over the network streams.
201 -func TestStBackpressureStreamWrite(t *testing.T) {
202 -
203 - // senderWrote signals that the sender wrote bytes to remote.
204 - // the value is the count of bytes written.
205 - senderWrote := make(chan int, 10000)
206 -
207 - // sender signals it's done (errored out)
208 - senderDone := make(chan struct{})
209 -
210 - // writeStats lets us listen to all the writes and return
211 - // how many happened and how much was written
212 - writeStats := func() (int, int) {
213 - writes := 0
214 - bytes := 0
215 - for {
216 - select {
217 - case n := <-senderWrote:
218 - writes++
219 - bytes = bytes + n
220 - default:
221 - log.Debugf("stats: sender wrote %d bytes, %d writes", bytes, writes)
222 - return bytes, writes
223 - }
224 - }
225 - }
226 -
227 - // sender attempts to write as fast as possible, signaling on the
228 - // completion of every write. This makes it possible to see how
229 - // fast it's actually writing. We pair this with a receiver
230 - // that waits for a signal to read.
231 - sender := func(s inet.Stream) {
232 - defer func() {
233 - s.Close()
234 - senderDone <- struct{}{}
235 - }()
236 -
237 - // ready a buffer of random data
238 - buf := make([]byte, 65536)
239 - u.NewTimeSeededRand().Read(buf)
240 -
241 - for {
242 - // send a randomly sized subchunk
243 - from := rand.Intn(len(buf) / 2)
244 - to := rand.Intn(len(buf) / 2)
245 - sendbuf := buf[from : from+to]
246 -
247 - n, err := s.Write(sendbuf)
248 - if err != nil {
249 - log.Debug("sender error. exiting:", err)
250 - return
251 - }
252 -
253 - log.Debugf("sender wrote %d bytes", n)
254 - senderWrote <- n
255 - }
256 - }
257 -
258 - // receive a number of bytes from a stream.
259 - // returns the number of bytes written.
260 - receive := func(s inet.Stream, expect int) {
261 - log.Debugf("receiver to read %d bytes", expect)
262 - rbuf := make([]byte, expect)
263 - n, err := io.ReadFull(s, rbuf)
264 - if err != nil {
265 - t.Error("read failed:", err)
266 - }
267 - if expect != n {
268 - t.Error("read len differs: %d != %d", expect, n)
269 - }
270 - }
271 -
272 - // ok let's do it!
273 -
274 - // setup the networks
275 - ctx := context.Background()
276 - h1 := testutil.GenHostSwarm(t, ctx)
277 - h2 := testutil.GenHostSwarm(t, ctx)
278 -
279 - // setup sender handler on 1
280 - h1.SetStreamHandler(protocol.TestingID, sender)
281 -
282 - h2pi := h2.Peerstore().PeerInfo(h2.ID())
283 - log.Debugf("dialing %s", h2pi.Addrs)
284 - if err := h1.Connect(ctx, h2pi); err != nil {
285 - t.Fatalf("Failed to connect:", err)
286 - }
287 -
288 - // open a stream, from 2->1, this is our reader
289 - s, err := h2.NewStream(protocol.TestingID, h1.ID())
290 - if err != nil {
291 - t.Fatal(err)
292 - }
293 -
294 - // let's make sure r/w works.
295 - testSenderWrote := func(bytesE int) {
296 - bytesA, writesA := writeStats()
297 - if bytesA != bytesE {
298 - t.Errorf("numbers failed: %d =?= %d bytes, via %d writes", bytesA, bytesE, writesA)
299 - }
300 - }
301 -
302 - // trigger lazy connection handshaking
303 - _, err = s.Read(nil)
304 - if err != nil {
305 - t.Fatal(err)
306 - }
307 -
308 - // 500ms rounds of lockstep write + drain
309 - roundsStart := time.Now()
310 - roundsTotal := 0
311 - for roundsTotal < (2 << 20) {
312 - // let the sender fill its buffers, it will stop sending.
313 - <-time.After(300 * time.Millisecond)
314 - b, _ := writeStats()
315 - testSenderWrote(0)
316 - testSenderWrote(0)
317 -
318 - // drain it all, wait again
319 - receive(s, b)
320 - roundsTotal = roundsTotal + b
321 - }
322 - roundsTime := time.Now().Sub(roundsStart)
323 -
324 - // now read continously, while we measure stats.
325 - stop := make(chan struct{})
326 - contStart := time.Now()
327 -
328 - go func() {
329 - for {
330 - select {
331 - case <-stop:
332 - return
333 - default:
334 - receive(s, 2<<15)
335 - }
336 - }
337 - }()
338 -
339 - contTotal := 0
340 - for contTotal < (2 << 20) {
341 - n := <-senderWrote
342 - contTotal += n
343 - }
344 - stop <- struct{}{}
345 - contTime := time.Now().Sub(contStart)
346 -
347 - // now compare! continuous should've been faster AND larger
348 - if roundsTime < contTime {
349 - t.Error("continuous should have been faster")
350 - }
351 -
352 - if roundsTotal < contTotal {
353 - t.Error("continuous should have been larger, too!")
354 - }
355 -
356 - // and a couple rounds more for good measure ;)
357 - for i := 0; i < 3; i++ {
358 - // let the sender fill its buffers, it will stop sending.
359 - <-time.After(300 * time.Millisecond)
360 - b, _ := writeStats()
361 - testSenderWrote(0)
362 - testSenderWrote(0)
363 -
364 - // drain it all, wait again
365 - receive(s, b)
366 - }
367 -
368 - // this doesn't work :(:
369 - // // now for the sugar on top: let's tear down the receiver. it should
370 - // // exit the sender.
371 - // n1.Close()
372 - // testSenderWrote(0)
373 - // testSenderWrote(0)
374 - // select {
375 - // case <-time.After(2 * time.Second):
376 - // t.Error("receiver shutdown failed to exit sender")
377 - // case <-senderDone:
378 - // log.Info("handler backpressure works!")
379 - // }
380 -}
p2p/test/reconnects/reconnect.go deleted
-2
@@ -1,2 +0,0 @@
1 -// Package reconnect tests connect -> disconnect -> reconnect works
2 -package reconnect
p2p/test/reconnects/reconnect_test.go deleted
-234
@@ -1,234 +0,0 @@
1 -package reconnect
2 -
3 -import (
4 - "io"
5 - "math/rand"
6 - "sync"
7 - "testing"
8 - "time"
9 -
10 - host "github.com/ipfs/go-ipfs/p2p/host"
11 - inet "github.com/ipfs/go-ipfs/p2p/net"
12 - swarm "github.com/ipfs/go-ipfs/p2p/net/swarm"
13 - protocol "github.com/ipfs/go-ipfs/p2p/protocol"
14 - testutil "github.com/ipfs/go-ipfs/p2p/test/util"
15 - u "github.com/ipfs/go-ipfs/util"
16 - logging "github.com/ipfs/go-ipfs/vendor/QmQg1J6vikuXF9oDvm4wpdeAUvvkVEKW1EYDw9HhTMnP2b/go-log"
17 -
18 - ps "github.com/ipfs/go-ipfs/Godeps/_workspace/src/github.com/jbenet/go-peerstream"
19 - context "github.com/ipfs/go-ipfs/Godeps/_workspace/src/golang.org/x/net/context"
20 -)
21 -
22 -func init() {
23 - // change the garbage collect timeout for testing.
24 - ps.GarbageCollectTimeout = 10 * time.Millisecond
25 -}
26 -
27 -var log = logging.Logger("reconnect")
28 -
29 -func EchoStreamHandler(stream inet.Stream) {
30 - c := stream.Conn()
31 - log.Debugf("%s echoing %s", c.LocalPeer(), c.RemotePeer())
32 - go func() {
33 - defer stream.Close()
34 - io.Copy(stream, stream)
35 - }()
36 -}
37 -
38 -type sendChans struct {
39 - send chan struct{}
40 - sent chan struct{}
41 - read chan struct{}
42 - close_ chan struct{}
43 - closed chan struct{}
44 -}
45 -
46 -func newSendChans() sendChans {
47 - return sendChans{
48 - send: make(chan struct{}),
49 - sent: make(chan struct{}),
50 - read: make(chan struct{}),
51 - close_: make(chan struct{}),
52 - closed: make(chan struct{}),
53 - }
54 -}
55 -
56 -func newSender() (chan sendChans, func(s inet.Stream)) {
57 - scc := make(chan sendChans)
58 - return scc, func(s inet.Stream) {
59 - sc := newSendChans()
60 - scc <- sc
61 -
62 - defer func() {
63 - s.Close()
64 - sc.closed <- struct{}{}
65 - }()
66 -
67 - buf := make([]byte, 65536)
68 - buf2 := make([]byte, 65536)
69 - u.NewTimeSeededRand().Read(buf)
70 -
71 - for {
72 - select {
73 - case <-sc.close_:
74 - return
75 - case <-sc.send:
76 - }
77 -
78 - // send a randomly sized subchunk
79 - from := rand.Intn(len(buf) / 2)
80 - to := rand.Intn(len(buf) / 2)
81 - sendbuf := buf[from : from+to]
82 -
83 - log.Debugf("sender sending %d bytes", len(sendbuf))
84 - n, err := s.Write(sendbuf)
85 - if err != nil {
86 - log.Debug("sender error. exiting:", err)
87 - return
88 - }
89 -
90 - log.Debugf("sender wrote %d bytes", n)
91 - sc.sent <- struct{}{}
92 -
93 - if n, err = io.ReadFull(s, buf2[:len(sendbuf)]); err != nil {
94 - log.Debug("sender error. failed to read:", err)
95 - return
96 - }
97 -
98 - log.Debugf("sender read %d bytes", n)
99 - sc.read <- struct{}{}
100 - }
101 - }
102 -}
103 -
104 -// TestReconnect tests whether hosts are able to disconnect and reconnect.
105 -func TestReconnect2(t *testing.T) {
106 - ctx := context.Background()
107 - h1 := testutil.GenHostSwarm(t, ctx)
108 - h2 := testutil.GenHostSwarm(t, ctx)
109 - hosts := []host.Host{h1, h2}
110 -
111 - h1.SetStreamHandler(protocol.TestingID, EchoStreamHandler)
112 - h2.SetStreamHandler(protocol.TestingID, EchoStreamHandler)
113 -
114 - rounds := 8
115 - if testing.Short() {
116 - rounds = 4
117 - }
118 - for i := 0; i < rounds; i++ {
119 - log.Debugf("TestReconnect: %d/%d\n", i, rounds)
120 - SubtestConnSendDisc(t, hosts)
121 - }
122 -}
123 -
124 -// TestReconnect tests whether hosts are able to disconnect and reconnect.
125 -func TestReconnect5(t *testing.T) {
126 - ctx := context.Background()
127 - h1 := testutil.GenHostSwarm(t, ctx)
128 - h2 := testutil.GenHostSwarm(t, ctx)
129 - h3 := testutil.GenHostSwarm(t, ctx)
130 - h4 := testutil.GenHostSwarm(t, ctx)
131 - h5 := testutil.GenHostSwarm(t, ctx)
132 - hosts := []host.Host{h1, h2, h3, h4, h5}
133 -
134 - h1.SetStreamHandler(protocol.TestingID, EchoStreamHandler)
135 - h2.SetStreamHandler(protocol.TestingID, EchoStreamHandler)
136 - h3.SetStreamHandler(protocol.TestingID, EchoStreamHandler)
137 - h4.SetStreamHandler(protocol.TestingID, EchoStreamHandler)
138 - h5.SetStreamHandler(protocol.TestingID, EchoStreamHandler)
139 -
140 - rounds := 4
141 - if testing.Short() {
142 - rounds = 2
143 - }
144 - for i := 0; i < rounds; i++ {
145 - log.Debugf("TestReconnect: %d/%d\n", i, rounds)
146 - SubtestConnSendDisc(t, hosts)
147 - }
148 -}
149 -
150 -func SubtestConnSendDisc(t *testing.T, hosts []host.Host) {
151 -
152 - ctx := context.Background()
153 - numStreams := 3 * len(hosts)
154 - numMsgs := 10
155 -
156 - if testing.Short() {
157 - numStreams = 5 * len(hosts)
158 - numMsgs = 4
159 - }
160 -
161 - ss, sF := newSender()
162 -
163 - for _, h1 := range hosts {
164 - for _, h2 := range hosts {
165 - if h1.ID() >= h2.ID() {
166 - continue
167 - }
168 -
169 - h2pi := h2.Peerstore().PeerInfo(h2.ID())
170 - log.Debugf("dialing %s", h2pi.Addrs)
171 - if err := h1.Connect(ctx, h2pi); err != nil {
172 - t.Fatalf("Failed to connect:", err)
173 - }
174 - }
175 - }
176 -
177 - var wg sync.WaitGroup
178 - for i := 0; i < numStreams; i++ {
179 - h1 := hosts[i%len(hosts)]
180 - h2 := hosts[(i+1)%len(hosts)]
181 - s, err := h1.NewStream(protocol.TestingID, h2.ID())
182 - if err != nil {
183 - t.Error(err)
184 - }
185 -
186 - wg.Add(1)
187 - go func(j int) {
188 - defer wg.Done()
189 -
190 - go sF(s)
191 - log.Debugf("getting handle %d", j)
192 - sc := <-ss // wait to get handle.
193 - log.Debugf("spawning worker %d", j)
194 -
195 - for k := 0; k < numMsgs; k++ {
196 - sc.send <- struct{}{}
197 - <-sc.sent
198 - log.Debugf("%d sent %d", j, k)
199 - <-sc.read
200 - log.Debugf("%d read %d", j, k)
201 - }
202 - sc.close_ <- struct{}{}
203 - <-sc.closed
204 - log.Debugf("closed %d", j)
205 - }(i)
206 - }
207 - wg.Wait()
208 -
209 - for i, h1 := range hosts {
210 - log.Debugf("host %d has %d conns", i, len(h1.Network().Conns()))
211 - }
212 -
213 - for _, h1 := range hosts {
214 - // close connection
215 - cs := h1.Network().Conns()
216 - for _, c := range cs {
217 - sc := c.(*swarm.Conn)
218 - if sc.LocalPeer() > sc.RemotePeer() {
219 - continue // only close it on one side.
220 - }
221 -
222 - log.Debugf("closing: %s", sc.RawConn())
223 - sc.Close()
224 - }
225 - }
226 -
227 - <-time.After(20 * time.Millisecond)
228 -
229 - for i, h := range hosts {
230 - if len(h.Network().Conns()) > 0 {
231 - t.Fatalf("host %d %s has %d conns! not zero.", i, h.ID(), len(h.Network().Conns()))
232 - }
233 - }
234 -}
p2p/test/util/key.go deleted
-165
@@ -1,165 +0,0 @@
1 -package testutil
2 -
3 -import (
4 - "bytes"
5 - "io"
6 - "testing"
7 -
8 - u "github.com/ipfs/go-ipfs/util"
9 - testutil "github.com/ipfs/go-ipfs/util/testutil"
10 - logging "github.com/ipfs/go-ipfs/vendor/QmQg1J6vikuXF9oDvm4wpdeAUvvkVEKW1EYDw9HhTMnP2b/go-log"
11 -
12 - ic "github.com/ipfs/go-ipfs/p2p/crypto"
13 - peer "github.com/ipfs/go-ipfs/p2p/peer"
14 -
15 - ma "github.com/ipfs/go-ipfs/Godeps/_workspace/src/github.com/jbenet/go-multiaddr"
16 -)
17 -
18 -var log = logging.Logger("boguskey")
19 -
20 -// TestBogusPrivateKey is a key used for testing (to avoid expensive keygen)
21 -type TestBogusPrivateKey []byte
22 -
23 -// TestBogusPublicKey is a key used for testing (to avoid expensive keygen)
24 -type TestBogusPublicKey []byte
25 -
26 -func (pk TestBogusPublicKey) Verify(data, sig []byte) (bool, error) {
27 - log.Errorf("TestBogusPublicKey.Verify -- this better be a test!")
28 - return bytes.Equal(data, reverse(sig)), nil
29 -}
30 -
31 -func (pk TestBogusPublicKey) Bytes() ([]byte, error) {
32 - return []byte(pk), nil
33 -}
34 -
35 -func (pk TestBogusPublicKey) Encrypt(b []byte) ([]byte, error) {
36 - log.Errorf("TestBogusPublicKey.Encrypt -- this better be a test!")
37 - return reverse(b), nil
38 -}
39 -
40 -// Equals checks whether this key is equal to another
41 -func (pk TestBogusPublicKey) Equals(k ic.Key) bool {
42 - return ic.KeyEqual(pk, k)
43 -}
44 -
45 -func (pk TestBogusPublicKey) Hash() ([]byte, error) {
46 - return ic.KeyHash(pk)
47 -}
48 -
49 -func (sk TestBogusPrivateKey) GenSecret() []byte {
50 - return []byte(sk)
51 -}
52 -
53 -func (sk TestBogusPrivateKey) Sign(message []byte) ([]byte, error) {
54 - log.Errorf("TestBogusPrivateKey.Sign -- this better be a test!")
55 - return reverse(message), nil
56 -}
57 -
58 -func (sk TestBogusPrivateKey) GetPublic() ic.PubKey {
59 - return TestBogusPublicKey(sk)
60 -}
61 -
62 -func (sk TestBogusPrivateKey) Decrypt(b []byte) ([]byte, error) {
63 - log.Errorf("TestBogusPrivateKey.Decrypt -- this better be a test!")
64 - return reverse(b), nil
65 -}
66 -
67 -func (sk TestBogusPrivateKey) Bytes() ([]byte, error) {
68 - return []byte(sk), nil
69 -}
70 -
71 -// Equals checks whether this key is equal to another
72 -func (sk TestBogusPrivateKey) Equals(k ic.Key) bool {
73 - return ic.KeyEqual(sk, k)
74 -}
75 -
76 -func (sk TestBogusPrivateKey) Hash() ([]byte, error) {
77 - return ic.KeyHash(sk)
78 -}
79 -
80 -func RandTestBogusPrivateKey() (TestBogusPrivateKey, error) {
81 - r := u.NewTimeSeededRand()
82 - k := make([]byte, 5)
83 - if _, err := io.ReadFull(r, k); err != nil {
84 - return nil, err
85 - }
86 - return TestBogusPrivateKey(k), nil
87 -}
88 -
89 -func RandTestBogusPublicKey() (TestBogusPublicKey, error) {
90 - k, err := RandTestBogusPrivateKey()
91 - return TestBogusPublicKey(k), err
92 -}
93 -
94 -func RandTestBogusPrivateKeyOrFatal(t *testing.T) TestBogusPrivateKey {
95 - k, err := RandTestBogusPrivateKey()
96 - if err != nil {
97 - t.Fatal(err)
98 - }
99 - return k
100 -}
101 -
102 -func RandTestBogusPublicKeyOrFatal(t *testing.T) TestBogusPublicKey {
103 - k, err := RandTestBogusPublicKey()
104 - if err != nil {
105 - t.Fatal(err)
106 - }
107 - return k
108 -}
109 -
110 -func RandTestBogusIdentity() (testutil.Identity, error) {
111 - k, err := RandTestBogusPrivateKey()
112 - if err != nil {
113 - return nil, err
114 - }
115 -
116 - id, err := peer.IDFromPrivateKey(k)
117 - if err != nil {
118 - return nil, err
119 - }
120 -
121 - return &identity{
122 - k: k,
123 - id: id,
124 - a: testutil.RandLocalTCPAddress(),
125 - }, nil
126 -}
127 -
128 -func RandTestBogusIdentityOrFatal(t *testing.T) testutil.Identity {
129 - k, err := RandTestBogusIdentity()
130 - if err != nil {
131 - t.Fatal(err)
132 - }
133 - return k
134 -}
135 -
136 -// identity is a temporary shim to delay binding of PeerNetParams.
137 -type identity struct {
138 - k TestBogusPrivateKey
139 - id peer.ID
140 - a ma.Multiaddr
141 -}
142 -
143 -func (p *identity) ID() peer.ID {
144 - return p.id
145 -}
146 -
147 -func (p *identity) Address() ma.Multiaddr {
148 - return p.a
149 -}
150 -
151 -func (p *identity) PrivateKey() ic.PrivKey {
152 - return p.k
153 -}
154 -
155 -func (p *identity) PublicKey() ic.PubKey {
156 - return p.k.GetPublic()
157 -}
158 -
159 -func reverse(a []byte) []byte {
160 - b := make([]byte, len(a))
161 - for i := 0; i < len(a); i++ {
162 - b[i] = a[len(a)-1-i]
163 - }
164 - return b
165 -}
p2p/test/util/util.go deleted
-41
@@ -1,41 +0,0 @@
1 -package testutil
2 -
3 -import (
4 - "testing"
5 -
6 - metrics "github.com/ipfs/go-ipfs/metrics"
7 - bhost "github.com/ipfs/go-ipfs/p2p/host/basic"
8 - inet "github.com/ipfs/go-ipfs/p2p/net"
9 - swarm "github.com/ipfs/go-ipfs/p2p/net/swarm"
10 - peer "github.com/ipfs/go-ipfs/p2p/peer"
11 - tu "github.com/ipfs/go-ipfs/util/testutil"
12 -
13 - ma "github.com/ipfs/go-ipfs/Godeps/_workspace/src/github.com/jbenet/go-multiaddr"
14 - context "github.com/ipfs/go-ipfs/Godeps/_workspace/src/golang.org/x/net/context"
15 -)
16 -
17 -func GenSwarmNetwork(t *testing.T, ctx context.Context) *swarm.Network {
18 - p := tu.RandPeerNetParamsOrFatal(t)
19 - ps := peer.NewPeerstore()
20 - ps.AddPubKey(p.ID, p.PubKey)
21 - ps.AddPrivKey(p.ID, p.PrivKey)
22 - n, err := swarm.NewNetwork(ctx, []ma.Multiaddr{p.Addr}, p.ID, ps, metrics.NewBandwidthCounter())
23 - if err != nil {
24 - t.Fatal(err)
25 - }
26 - ps.AddAddrs(p.ID, n.ListenAddresses(), peer.PermanentAddrTTL)
27 - return n
28 -}
29 -
30 -func DivulgeAddresses(a, b inet.Network) {
31 - id := a.LocalPeer()
32 - addrs := a.Peerstore().Addrs(id)
33 - b.Peerstore().AddAddrs(id, addrs, peer.PermanentAddrTTL)
34 -}
35 -
36 -func GenHostSwarm(t *testing.T, ctx context.Context) *bhost.BasicHost {
37 - n := GenSwarmNetwork(t, ctx)
38 - return bhost.New(n)
39 -}
40 -
41 -var RandPeerID = tu.RandPeerID
package.json
+7 -7
@@ -4,15 +4,15 @@
4 "gxDependencies": [
5 {
6 "name": "go-log",
7 - "hash": "QmQg1J6vikuXF9oDvm4wpdeAUvvkVEKW1EYDw9HhTMnP2b",
7 + "hash": "QmaPaGNE2GqnfJjRRpQuQuFHuJn4FZvsrGxdik4kgxCkBi",
8 "version": "1.0.0"
9 },
10 {
11 - "name": "dir-index-html",
12 - "hash": "QmdDfkqDWheE4gsCXNrhixwTwSHnZMPT2cGLcNbiBNcMyU",
13 - "version": "1.0.0",
14 - "linkname": "dir-index-html-v1.0.0"
11 + "name": "go-libp2p",
12 + "hash": "QmY3NAw959vbE1oJooP9HchcRdBsbxhgQsEZTRhKgvoSuC",
13 + "version": "1.0.0"
14 }
15 ],
17 - "language": "go"
18 -}
\ No newline at end of file
16 + "language": "go",
17 + "issues_url": ""
18 +}
path/resolver.go
+2 -2
@@ -7,11 +7,11 @@ import (
7 "time"
8
9 mh "github.com/ipfs/go-ipfs/Godeps/_workspace/src/github.com/jbenet/go-multihash"
10 - "github.com/ipfs/go-ipfs/Godeps/_workspace/src/golang.org/x/net/context"
10 + "gx/ipfs/QmZy2y8t9zQH2a1b8q2ZSLKp17ATuJoCNxxyMFG5qFExpt/go-net/context"
11
12 key "github.com/ipfs/go-ipfs/blocks/key"
13 merkledag "github.com/ipfs/go-ipfs/merkledag"
14 - logging "github.com/ipfs/go-ipfs/vendor/QmQg1J6vikuXF9oDvm4wpdeAUvvkVEKW1EYDw9HhTMnP2b/go-log"
14 + logging "gx/ipfs/QmaPaGNE2GqnfJjRRpQuQuFHuJn4FZvsrGxdik4kgxCkBi/go-log"
15 )
16
17 var log = logging.Logger("path")
path/resolver_test.go
+1 -1
@@ -4,7 +4,7 @@ import (
4 "fmt"
5 "testing"
6
7 - context "github.com/ipfs/go-ipfs/Godeps/_workspace/src/golang.org/x/net/context"
7 + context "gx/ipfs/QmZy2y8t9zQH2a1b8q2ZSLKp17ATuJoCNxxyMFG5qFExpt/go-net/context"
8
9 key "github.com/ipfs/go-ipfs/blocks/key"
10 merkledag "github.com/ipfs/go-ipfs/merkledag"
pin/gc/gc.go
+2 -2
@@ -8,8 +8,8 @@ import (
8 dag "github.com/ipfs/go-ipfs/merkledag"
9 pin "github.com/ipfs/go-ipfs/pin"
10
11 - context "github.com/ipfs/go-ipfs/Godeps/_workspace/src/golang.org/x/net/context"
12 - logging "github.com/ipfs/go-ipfs/vendor/QmQg1J6vikuXF9oDvm4wpdeAUvvkVEKW1EYDw9HhTMnP2b/go-log"
11 + context "gx/ipfs/QmZy2y8t9zQH2a1b8q2ZSLKp17ATuJoCNxxyMFG5qFExpt/go-net/context"
12 + logging "gx/ipfs/QmaPaGNE2GqnfJjRRpQuQuFHuJn4FZvsrGxdik4kgxCkBi/go-log"
13 )
14
15 var log = logging.Logger("gc")
pin/pin.go
+2 -2
@@ -8,11 +8,11 @@ import (
8 "time"
9
10 ds "github.com/ipfs/go-ipfs/Godeps/_workspace/src/github.com/ipfs/go-datastore"
11 - context "github.com/ipfs/go-ipfs/Godeps/_workspace/src/golang.org/x/net/context"
11 + context "gx/ipfs/QmZy2y8t9zQH2a1b8q2ZSLKp17ATuJoCNxxyMFG5qFExpt/go-net/context"
12 key "github.com/ipfs/go-ipfs/blocks/key"
13 "github.com/ipfs/go-ipfs/blocks/set"
14 mdag "github.com/ipfs/go-ipfs/merkledag"
15 - logging "github.com/ipfs/go-ipfs/vendor/QmQg1J6vikuXF9oDvm4wpdeAUvvkVEKW1EYDw9HhTMnP2b/go-log"
15 + logging "gx/ipfs/QmaPaGNE2GqnfJjRRpQuQuFHuJn4FZvsrGxdik4kgxCkBi/go-log"
16 )
17
18 var log = logging.Logger("pin")
pin/pin_test.go
+1 -1
@@ -4,7 +4,7 @@ import (
4 "testing"
5 "time"
6
7 - context "github.com/ipfs/go-ipfs/Godeps/_workspace/src/golang.org/x/net/context"
7 + context "gx/ipfs/QmZy2y8t9zQH2a1b8q2ZSLKp17ATuJoCNxxyMFG5qFExpt/go-net/context"
8
9 ds "github.com/ipfs/go-ipfs/Godeps/_workspace/src/github.com/ipfs/go-datastore"
10 dssync "github.com/ipfs/go-ipfs/Godeps/_workspace/src/github.com/ipfs/go-datastore/sync"
pin/set.go
+1 -1
@@ -12,7 +12,7 @@ import (
12 "unsafe"
13
14 "github.com/ipfs/go-ipfs/Godeps/_workspace/src/github.com/gogo/protobuf/proto"
15 - "github.com/ipfs/go-ipfs/Godeps/_workspace/src/golang.org/x/net/context"
15 + "gx/ipfs/QmZy2y8t9zQH2a1b8q2ZSLKp17ATuJoCNxxyMFG5qFExpt/go-net/context"
16 "github.com/ipfs/go-ipfs/blocks/key"
17 "github.com/ipfs/go-ipfs/merkledag"
18 "github.com/ipfs/go-ipfs/pin/internal/pb"
pin/set_test.go
+1 -1
@@ -6,7 +6,7 @@ import (
6
7 "github.com/ipfs/go-ipfs/Godeps/_workspace/src/github.com/ipfs/go-datastore"
8 dssync "github.com/ipfs/go-ipfs/Godeps/_workspace/src/github.com/ipfs/go-datastore/sync"
9 - "github.com/ipfs/go-ipfs/Godeps/_workspace/src/golang.org/x/net/context"
9 + "gx/ipfs/QmZy2y8t9zQH2a1b8q2ZSLKp17ATuJoCNxxyMFG5qFExpt/go-net/context"
10 "github.com/ipfs/go-ipfs/blocks/blockstore"
11 "github.com/ipfs/go-ipfs/blocks/key"
12 "github.com/ipfs/go-ipfs/blockservice"
repo/config/config.go
+1 -1
@@ -10,7 +10,7 @@ import (
10 "strings"
11
12 u "github.com/ipfs/go-ipfs/util"
13 - logging "github.com/ipfs/go-ipfs/vendor/QmQg1J6vikuXF9oDvm4wpdeAUvvkVEKW1EYDw9HhTMnP2b/go-log"
13 + logging "gx/ipfs/QmaPaGNE2GqnfJjRRpQuQuFHuJn4FZvsrGxdik4kgxCkBi/go-log"
14 )
15
16 var log = logging.Logger("config")
repo/config/identity.go
+1 -1
@@ -2,7 +2,7 @@ package config
2
3 import (
4 "encoding/base64"
5 - ic "github.com/ipfs/go-ipfs/p2p/crypto"
5 + ic "gx/ipfs/QmY3NAw959vbE1oJooP9HchcRdBsbxhgQsEZTRhKgvoSuC/go-libp2p/p2p/crypto"
6 )
7
8 // Identity tracks the configuration of the local node's identity.
repo/config/init.go
+2 -2
@@ -6,8 +6,8 @@ import (
6 "fmt"
7 "io"
8
9 - ci "github.com/ipfs/go-ipfs/p2p/crypto"
10 - peer "github.com/ipfs/go-ipfs/p2p/peer"
9 + ci "gx/ipfs/QmY3NAw959vbE1oJooP9HchcRdBsbxhgQsEZTRhKgvoSuC/go-libp2p/p2p/crypto"
10 + peer "gx/ipfs/QmY3NAw959vbE1oJooP9HchcRdBsbxhgQsEZTRhKgvoSuC/go-libp2p/p2p/peer"
11 )
12
13 func Init(out io.Writer, nBitsForKeypair int) (*Config, error) {
repo/fsrepo/fsrepo.go
+1 -1
@@ -20,7 +20,7 @@ import (
20 serialize "github.com/ipfs/go-ipfs/repo/fsrepo/serialize"
21 dir "github.com/ipfs/go-ipfs/thirdparty/dir"
22 util "github.com/ipfs/go-ipfs/util"
23 - logging "github.com/ipfs/go-ipfs/vendor/QmQg1J6vikuXF9oDvm4wpdeAUvvkVEKW1EYDw9HhTMnP2b/go-log"
23 + logging "gx/ipfs/QmaPaGNE2GqnfJjRRpQuQuFHuJn4FZvsrGxdik4kgxCkBi/go-log"
24 )
25
26 var log = logging.Logger("fsrepo")
repo/fsrepo/serialize/serialize.go
+1 -1
@@ -11,7 +11,7 @@ import (
11 "github.com/ipfs/go-ipfs/Godeps/_workspace/src/github.com/facebookgo/atomicfile"
12 "github.com/ipfs/go-ipfs/repo/config"
13 "github.com/ipfs/go-ipfs/util"
14 - logging "github.com/ipfs/go-ipfs/vendor/QmQg1J6vikuXF9oDvm4wpdeAUvvkVEKW1EYDw9HhTMnP2b/go-log"
14 + logging "gx/ipfs/QmaPaGNE2GqnfJjRRpQuQuFHuJn4FZvsrGxdik4kgxCkBi/go-log"
15 )
16
17 var log = logging.Logger("fsrepo")
routing/dht/dht.go
+6 -6
@@ -10,21 +10,21 @@ import (
10 "time"
11
12 key "github.com/ipfs/go-ipfs/blocks/key"
13 - ci "github.com/ipfs/go-ipfs/p2p/crypto"
14 - host "github.com/ipfs/go-ipfs/p2p/host"
15 - peer "github.com/ipfs/go-ipfs/p2p/peer"
16 - protocol "github.com/ipfs/go-ipfs/p2p/protocol"
13 routing "github.com/ipfs/go-ipfs/routing"
14 pb "github.com/ipfs/go-ipfs/routing/dht/pb"
15 kb "github.com/ipfs/go-ipfs/routing/kbucket"
16 record "github.com/ipfs/go-ipfs/routing/record"
21 - logging "github.com/ipfs/go-ipfs/vendor/QmQg1J6vikuXF9oDvm4wpdeAUvvkVEKW1EYDw9HhTMnP2b/go-log"
17 + logging "gx/ipfs/QmaPaGNE2GqnfJjRRpQuQuFHuJn4FZvsrGxdik4kgxCkBi/go-log"
18 + ci "gx/ipfs/QmY3NAw959vbE1oJooP9HchcRdBsbxhgQsEZTRhKgvoSuC/go-libp2p/p2p/crypto"
19 + host "gx/ipfs/QmY3NAw959vbE1oJooP9HchcRdBsbxhgQsEZTRhKgvoSuC/go-libp2p/p2p/host"
20 + peer "gx/ipfs/QmY3NAw959vbE1oJooP9HchcRdBsbxhgQsEZTRhKgvoSuC/go-libp2p/p2p/peer"
21 + protocol "gx/ipfs/QmY3NAw959vbE1oJooP9HchcRdBsbxhgQsEZTRhKgvoSuC/go-libp2p/p2p/protocol"
22
23 proto "github.com/ipfs/go-ipfs/Godeps/_workspace/src/github.com/gogo/protobuf/proto"
24 ds "github.com/ipfs/go-ipfs/Godeps/_workspace/src/github.com/ipfs/go-datastore"
25 goprocess "github.com/ipfs/go-ipfs/Godeps/_workspace/src/github.com/jbenet/goprocess"
26 goprocessctx "github.com/ipfs/go-ipfs/Godeps/_workspace/src/github.com/jbenet/goprocess/context"
27 - context "github.com/ipfs/go-ipfs/Godeps/_workspace/src/golang.org/x/net/context"
27 + context "gx/ipfs/QmZy2y8t9zQH2a1b8q2ZSLKp17ATuJoCNxxyMFG5qFExpt/go-net/context"
28 )
29
30 var log = logging.Logger("dht")
routing/dht/dht_bootstrap.go
+2 -2
@@ -8,13 +8,13 @@ import (
8 "sync"
9 "time"
10
11 - peer "github.com/ipfs/go-ipfs/p2p/peer"
11 routing "github.com/ipfs/go-ipfs/routing"
12 u "github.com/ipfs/go-ipfs/util"
13 + peer "gx/ipfs/QmY3NAw959vbE1oJooP9HchcRdBsbxhgQsEZTRhKgvoSuC/go-libp2p/p2p/peer"
14
15 goprocess "github.com/ipfs/go-ipfs/Godeps/_workspace/src/github.com/jbenet/goprocess"
16 periodicproc "github.com/ipfs/go-ipfs/Godeps/_workspace/src/github.com/jbenet/goprocess/periodic"
17 - context "github.com/ipfs/go-ipfs/Godeps/_workspace/src/golang.org/x/net/context"
17 + context "gx/ipfs/QmZy2y8t9zQH2a1b8q2ZSLKp17ATuJoCNxxyMFG5qFExpt/go-net/context"
18 )
19
20 // BootstrapConfig specifies parameters used bootstrapping the DHT.
routing/dht/dht_net.go
+5 -5
@@ -6,10 +6,10 @@ import (
6
7 ggio "github.com/ipfs/go-ipfs/Godeps/_workspace/src/github.com/gogo/protobuf/io"
8 ctxio "github.com/ipfs/go-ipfs/Godeps/_workspace/src/github.com/jbenet/go-context/io"
9 - context "github.com/ipfs/go-ipfs/Godeps/_workspace/src/golang.org/x/net/context"
10 - inet "github.com/ipfs/go-ipfs/p2p/net"
11 - peer "github.com/ipfs/go-ipfs/p2p/peer"
9 + context "gx/ipfs/QmZy2y8t9zQH2a1b8q2ZSLKp17ATuJoCNxxyMFG5qFExpt/go-net/context"
10 pb "github.com/ipfs/go-ipfs/routing/dht/pb"
11 + inet "gx/ipfs/QmY3NAw959vbE1oJooP9HchcRdBsbxhgQsEZTRhKgvoSuC/go-libp2p/p2p/net"
12 + peer "gx/ipfs/QmY3NAw959vbE1oJooP9HchcRdBsbxhgQsEZTRhKgvoSuC/go-libp2p/p2p/peer"
13 )
14
15 // handleNewStream implements the inet.StreamHandler
@@ -71,7 +71,7 @@ func (dht *IpfsDHT) handleNewMessage(s inet.Stream) {
71 func (dht *IpfsDHT) sendRequest(ctx context.Context, p peer.ID, pmes *pb.Message) (*pb.Message, error) {
72
73 log.Debugf("%s dht starting stream", dht.self)
74 - s, err := dht.host.NewStream(ProtocolDHT, p)
74 + s, err := dht.host.NewStream(ctx, ProtocolDHT, p)
75 if err != nil {
76 return nil, err
77 }
@@ -109,7 +109,7 @@ func (dht *IpfsDHT) sendRequest(ctx context.Context, p peer.ID, pmes *pb.Message
109 func (dht *IpfsDHT) sendMessage(ctx context.Context, p peer.ID, pmes *pb.Message) error {
110
111 log.Debugf("%s dht starting stream", dht.self)
112 - s, err := dht.host.NewStream(ProtocolDHT, p)
112 + s, err := dht.host.NewStream(ctx, ProtocolDHT, p)
113 if err != nil {
114 return err
115 }
routing/dht/dht_test.go
+4 -4
@@ -11,15 +11,15 @@ import (
11
12 ds "github.com/ipfs/go-ipfs/Godeps/_workspace/src/github.com/ipfs/go-datastore"
13 dssync "github.com/ipfs/go-ipfs/Godeps/_workspace/src/github.com/ipfs/go-datastore/sync"
14 - ma "github.com/ipfs/go-ipfs/Godeps/_workspace/src/github.com/jbenet/go-multiaddr"
15 - context "github.com/ipfs/go-ipfs/Godeps/_workspace/src/golang.org/x/net/context"
14 + context "gx/ipfs/QmZy2y8t9zQH2a1b8q2ZSLKp17ATuJoCNxxyMFG5qFExpt/go-net/context"
15 + ma "gx/ipfs/QmR3JkmZBKYXgNMNsNZawm914455Qof3PEopwuVSeXG7aV/go-multiaddr"
16
17 key "github.com/ipfs/go-ipfs/blocks/key"
18 - peer "github.com/ipfs/go-ipfs/p2p/peer"
19 - netutil "github.com/ipfs/go-ipfs/p2p/test/util"
18 routing "github.com/ipfs/go-ipfs/routing"
19 record "github.com/ipfs/go-ipfs/routing/record"
20 u "github.com/ipfs/go-ipfs/util"
21 + peer "gx/ipfs/QmY3NAw959vbE1oJooP9HchcRdBsbxhgQsEZTRhKgvoSuC/go-libp2p/p2p/peer"
22 + netutil "gx/ipfs/QmY3NAw959vbE1oJooP9HchcRdBsbxhgQsEZTRhKgvoSuC/go-libp2p/p2p/test/util"
23
24 ci "github.com/ipfs/go-ipfs/util/testutil/ci"
25 travisci "github.com/ipfs/go-ipfs/util/testutil/ci/travis"
routing/dht/diag.go
+1 -1
@@ -4,7 +4,7 @@ import (
4 "encoding/json"
5 "time"
6
7 - peer "github.com/ipfs/go-ipfs/p2p/peer"
7 + peer "gx/ipfs/QmY3NAw959vbE1oJooP9HchcRdBsbxhgQsEZTRhKgvoSuC/go-libp2p/p2p/peer"
8 )
9
10 type connDiagInfo struct {
routing/dht/ext_test.go
+5 -5
@@ -10,16 +10,16 @@ import (
10 ggio "github.com/ipfs/go-ipfs/Godeps/_workspace/src/github.com/gogo/protobuf/io"
11 ds "github.com/ipfs/go-ipfs/Godeps/_workspace/src/github.com/ipfs/go-datastore"
12 dssync "github.com/ipfs/go-ipfs/Godeps/_workspace/src/github.com/ipfs/go-datastore/sync"
13 - context "github.com/ipfs/go-ipfs/Godeps/_workspace/src/golang.org/x/net/context"
13 + context "gx/ipfs/QmZy2y8t9zQH2a1b8q2ZSLKp17ATuJoCNxxyMFG5qFExpt/go-net/context"
14
15 key "github.com/ipfs/go-ipfs/blocks/key"
16 - inet "github.com/ipfs/go-ipfs/p2p/net"
17 - mocknet "github.com/ipfs/go-ipfs/p2p/net/mock"
18 - peer "github.com/ipfs/go-ipfs/p2p/peer"
16 routing "github.com/ipfs/go-ipfs/routing"
17 pb "github.com/ipfs/go-ipfs/routing/dht/pb"
18 record "github.com/ipfs/go-ipfs/routing/record"
19 u "github.com/ipfs/go-ipfs/util"
20 + inet "gx/ipfs/QmY3NAw959vbE1oJooP9HchcRdBsbxhgQsEZTRhKgvoSuC/go-libp2p/p2p/net"
21 + mocknet "gx/ipfs/QmY3NAw959vbE1oJooP9HchcRdBsbxhgQsEZTRhKgvoSuC/go-libp2p/p2p/net/mock"
22 + peer "gx/ipfs/QmY3NAw959vbE1oJooP9HchcRdBsbxhgQsEZTRhKgvoSuC/go-libp2p/p2p/peer"
23 )
24
25 func TestGetFailures(t *testing.T) {
@@ -120,7 +120,7 @@ func TestGetFailures(t *testing.T) {
120 Record: rec,
121 }
122
123 - s, err := hosts[1].NewStream(ProtocolDHT, hosts[0].ID())
123 + s, err := hosts[1].NewStream(context.Background(), ProtocolDHT, hosts[0].ID())
124 if err != nil {
125 t.Fatal(err)
126 }
routing/dht/handlers.go
+2 -2
@@ -7,12 +7,12 @@ import (
7
8 proto "github.com/ipfs/go-ipfs/Godeps/_workspace/src/github.com/gogo/protobuf/proto"
9 ds "github.com/ipfs/go-ipfs/Godeps/_workspace/src/github.com/ipfs/go-datastore"
10 - context "github.com/ipfs/go-ipfs/Godeps/_workspace/src/golang.org/x/net/context"
10 + context "gx/ipfs/QmZy2y8t9zQH2a1b8q2ZSLKp17ATuJoCNxxyMFG5qFExpt/go-net/context"
11 key "github.com/ipfs/go-ipfs/blocks/key"
12 - peer "github.com/ipfs/go-ipfs/p2p/peer"
12 pb "github.com/ipfs/go-ipfs/routing/dht/pb"
13 u "github.com/ipfs/go-ipfs/util"
14 lgbl "github.com/ipfs/go-ipfs/util/eventlog/loggables"
15 + peer "gx/ipfs/QmY3NAw959vbE1oJooP9HchcRdBsbxhgQsEZTRhKgvoSuC/go-libp2p/p2p/peer"
16 )
17
18 // The number of closer peers to send on requests.
routing/dht/lookup.go
+2 -2
@@ -1,12 +1,12 @@
1 package dht
2
3 import (
4 - context "github.com/ipfs/go-ipfs/Godeps/_workspace/src/golang.org/x/net/context"
4 + context "gx/ipfs/QmZy2y8t9zQH2a1b8q2ZSLKp17ATuJoCNxxyMFG5qFExpt/go-net/context"
5 key "github.com/ipfs/go-ipfs/blocks/key"
6 notif "github.com/ipfs/go-ipfs/notifications"
7 - peer "github.com/ipfs/go-ipfs/p2p/peer"
7 kb "github.com/ipfs/go-ipfs/routing/kbucket"
8 pset "github.com/ipfs/go-ipfs/util/peerset"
9 + peer "gx/ipfs/QmY3NAw959vbE1oJooP9HchcRdBsbxhgQsEZTRhKgvoSuC/go-libp2p/p2p/peer"
10 )
11
12 // Required in order for proper JSON marshaling
routing/dht/notif.go
+2 -2
@@ -1,9 +1,9 @@
1 package dht
2
3 import (
4 - ma "github.com/ipfs/go-ipfs/Godeps/_workspace/src/github.com/jbenet/go-multiaddr"
4 + ma "gx/ipfs/QmR3JkmZBKYXgNMNsNZawm914455Qof3PEopwuVSeXG7aV/go-multiaddr"
5
6 - inet "github.com/ipfs/go-ipfs/p2p/net"
6 + inet "gx/ipfs/QmY3NAw959vbE1oJooP9HchcRdBsbxhgQsEZTRhKgvoSuC/go-libp2p/p2p/net"
7 )
8
9 // netNotifiee defines methods to be used with the IpfsDHT
routing/dht/pb/message.go
+4 -4
@@ -1,12 +1,12 @@
1 package dht_pb
2
3 import (
4 - ma "github.com/ipfs/go-ipfs/Godeps/_workspace/src/github.com/jbenet/go-multiaddr"
4 + ma "gx/ipfs/QmR3JkmZBKYXgNMNsNZawm914455Qof3PEopwuVSeXG7aV/go-multiaddr"
5
6 key "github.com/ipfs/go-ipfs/blocks/key"
7 - inet "github.com/ipfs/go-ipfs/p2p/net"
8 - peer "github.com/ipfs/go-ipfs/p2p/peer"
9 - logging "github.com/ipfs/go-ipfs/vendor/QmQg1J6vikuXF9oDvm4wpdeAUvvkVEKW1EYDw9HhTMnP2b/go-log"
7 + logging "gx/ipfs/QmaPaGNE2GqnfJjRRpQuQuFHuJn4FZvsrGxdik4kgxCkBi/go-log"
8 + inet "gx/ipfs/QmY3NAw959vbE1oJooP9HchcRdBsbxhgQsEZTRhKgvoSuC/go-libp2p/p2p/net"
9 + peer "gx/ipfs/QmY3NAw959vbE1oJooP9HchcRdBsbxhgQsEZTRhKgvoSuC/go-libp2p/p2p/peer"
10 )
11
12 var log = logging.Logger("dht.pb")
routing/dht/providers.go
+2 -2
@@ -6,9 +6,9 @@ import (
6 "github.com/ipfs/go-ipfs/Godeps/_workspace/src/github.com/jbenet/goprocess"
7 goprocessctx "github.com/ipfs/go-ipfs/Godeps/_workspace/src/github.com/jbenet/goprocess/context"
8 key "github.com/ipfs/go-ipfs/blocks/key"
9 - peer "github.com/ipfs/go-ipfs/p2p/peer"
9 + peer "gx/ipfs/QmY3NAw959vbE1oJooP9HchcRdBsbxhgQsEZTRhKgvoSuC/go-libp2p/p2p/peer"
10
11 - context "github.com/ipfs/go-ipfs/Godeps/_workspace/src/golang.org/x/net/context"
11 + context "gx/ipfs/QmZy2y8t9zQH2a1b8q2ZSLKp17ATuJoCNxxyMFG5qFExpt/go-net/context"
12 )
13
14 type ProviderManager struct {
routing/dht/providers_test.go
+2 -2
@@ -4,9 +4,9 @@ import (
4 "testing"
5
6 key "github.com/ipfs/go-ipfs/blocks/key"
7 - peer "github.com/ipfs/go-ipfs/p2p/peer"
7 + peer "gx/ipfs/QmY3NAw959vbE1oJooP9HchcRdBsbxhgQsEZTRhKgvoSuC/go-libp2p/p2p/peer"
8
9 - context "github.com/ipfs/go-ipfs/Godeps/_workspace/src/golang.org/x/net/context"
9 + context "gx/ipfs/QmZy2y8t9zQH2a1b8q2ZSLKp17ATuJoCNxxyMFG5qFExpt/go-net/context"
10 )
11
12 func TestProviderManager(t *testing.T) {
routing/dht/query.go
+5 -5
@@ -5,17 +5,17 @@ import (
5
6 key "github.com/ipfs/go-ipfs/blocks/key"
7 notif "github.com/ipfs/go-ipfs/notifications"
8 - peer "github.com/ipfs/go-ipfs/p2p/peer"
9 - queue "github.com/ipfs/go-ipfs/p2p/peer/queue"
8 "github.com/ipfs/go-ipfs/routing"
9 u "github.com/ipfs/go-ipfs/util"
10 pset "github.com/ipfs/go-ipfs/util/peerset"
11 todoctr "github.com/ipfs/go-ipfs/util/todocounter"
14 - logging "github.com/ipfs/go-ipfs/vendor/QmQg1J6vikuXF9oDvm4wpdeAUvvkVEKW1EYDw9HhTMnP2b/go-log"
12 + logging "gx/ipfs/QmaPaGNE2GqnfJjRRpQuQuFHuJn4FZvsrGxdik4kgxCkBi/go-log"
13 + peer "gx/ipfs/QmY3NAw959vbE1oJooP9HchcRdBsbxhgQsEZTRhKgvoSuC/go-libp2p/p2p/peer"
14 + queue "gx/ipfs/QmY3NAw959vbE1oJooP9HchcRdBsbxhgQsEZTRhKgvoSuC/go-libp2p/p2p/peer/queue"
15
16 process "github.com/ipfs/go-ipfs/Godeps/_workspace/src/github.com/jbenet/goprocess"
17 ctxproc "github.com/ipfs/go-ipfs/Godeps/_workspace/src/github.com/jbenet/goprocess/context"
18 - context "github.com/ipfs/go-ipfs/Godeps/_workspace/src/golang.org/x/net/context"
18 + context "gx/ipfs/QmZy2y8t9zQH2a1b8q2ZSLKp17ATuJoCNxxyMFG5qFExpt/go-net/context"
19 )
20
21 var maxQueryConcurrency = AlphaValue
@@ -90,7 +90,7 @@ func newQueryRunner(q *dhtQuery) *dhtQueryRunner {
90 ctx := ctxproc.OnClosingContext(proc)
91 return &dhtQueryRunner{
92 query: q,
93 - peersToQuery: queue.NewChanQueue(ctx, queue.NewXORDistancePQ(q.key)),
93 + peersToQuery: queue.NewChanQueue(ctx, queue.NewXORDistancePQ(string(q.key))),
94 peersRemaining: todoctr.NewSyncCounter(),
95 peersSeen: pset.New(),
96 rateLimit: make(chan struct{}, q.concurrency),
routing/dht/records.go
+3 -3
@@ -5,12 +5,12 @@ import (
5 "time"
6
7 ctxfrac "github.com/ipfs/go-ipfs/Godeps/_workspace/src/github.com/jbenet/go-context/frac"
8 - "github.com/ipfs/go-ipfs/Godeps/_workspace/src/golang.org/x/net/context"
9 - ci "github.com/ipfs/go-ipfs/p2p/crypto"
10 - peer "github.com/ipfs/go-ipfs/p2p/peer"
8 + "gx/ipfs/QmZy2y8t9zQH2a1b8q2ZSLKp17ATuJoCNxxyMFG5qFExpt/go-net/context"
9 routing "github.com/ipfs/go-ipfs/routing"
10 pb "github.com/ipfs/go-ipfs/routing/dht/pb"
11 record "github.com/ipfs/go-ipfs/routing/record"
12 + ci "gx/ipfs/QmY3NAw959vbE1oJooP9HchcRdBsbxhgQsEZTRhKgvoSuC/go-libp2p/p2p/crypto"
13 + peer "gx/ipfs/QmY3NAw959vbE1oJooP9HchcRdBsbxhgQsEZTRhKgvoSuC/go-libp2p/p2p/peer"
14 )
15
16 // MaxRecordAge specifies the maximum time that any node will hold onto a record
routing/dht/routing.go
+3 -3
@@ -5,16 +5,16 @@ import (
5 "sync"
6 "time"
7
8 - context "github.com/ipfs/go-ipfs/Godeps/_workspace/src/golang.org/x/net/context"
8 + context "gx/ipfs/QmZy2y8t9zQH2a1b8q2ZSLKp17ATuJoCNxxyMFG5qFExpt/go-net/context"
9 key "github.com/ipfs/go-ipfs/blocks/key"
10 notif "github.com/ipfs/go-ipfs/notifications"
11 - inet "github.com/ipfs/go-ipfs/p2p/net"
12 - peer "github.com/ipfs/go-ipfs/p2p/peer"
11 "github.com/ipfs/go-ipfs/routing"
12 pb "github.com/ipfs/go-ipfs/routing/dht/pb"
13 kb "github.com/ipfs/go-ipfs/routing/kbucket"
14 record "github.com/ipfs/go-ipfs/routing/record"
15 pset "github.com/ipfs/go-ipfs/util/peerset"
16 + inet "gx/ipfs/QmY3NAw959vbE1oJooP9HchcRdBsbxhgQsEZTRhKgvoSuC/go-libp2p/p2p/net"
17 + peer "gx/ipfs/QmY3NAw959vbE1oJooP9HchcRdBsbxhgQsEZTRhKgvoSuC/go-libp2p/p2p/peer"
18 )
19
20 // asyncQueryBuffer is the size of buffered channels in async queries. This
routing/kbucket/bucket.go
+1 -1
@@ -4,7 +4,7 @@ import (
4 "container/list"
5 "sync"
6
7 - peer "github.com/ipfs/go-ipfs/p2p/peer"
7 + peer "gx/ipfs/QmY3NAw959vbE1oJooP9HchcRdBsbxhgQsEZTRhKgvoSuC/go-libp2p/p2p/peer"
8 )
9
10 // Bucket holds a list of peers.
routing/kbucket/sorting.go
+1 -1
@@ -2,7 +2,7 @@ package kbucket
2
3 import (
4 "container/list"
5 - peer "github.com/ipfs/go-ipfs/p2p/peer"
5 + peer "gx/ipfs/QmY3NAw959vbE1oJooP9HchcRdBsbxhgQsEZTRhKgvoSuC/go-libp2p/p2p/peer"
6 "sort"
7 )
8
routing/kbucket/table.go
+2 -2
@@ -7,8 +7,8 @@ import (
7 "sync"
8 "time"
9
10 - peer "github.com/ipfs/go-ipfs/p2p/peer"
11 - logging "github.com/ipfs/go-ipfs/vendor/QmQg1J6vikuXF9oDvm4wpdeAUvvkVEKW1EYDw9HhTMnP2b/go-log"
10 + logging "gx/ipfs/QmaPaGNE2GqnfJjRRpQuQuFHuJn4FZvsrGxdik4kgxCkBi/go-log"
11 + peer "gx/ipfs/QmY3NAw959vbE1oJooP9HchcRdBsbxhgQsEZTRhKgvoSuC/go-libp2p/p2p/peer"
12 )
13
14 var log = logging.Logger("table")
routing/kbucket/table_test.go
+1 -1
@@ -7,7 +7,7 @@ import (
7
8 tu "github.com/ipfs/go-ipfs/util/testutil"
9
10 - peer "github.com/ipfs/go-ipfs/p2p/peer"
10 + peer "gx/ipfs/QmY3NAw959vbE1oJooP9HchcRdBsbxhgQsEZTRhKgvoSuC/go-libp2p/p2p/peer"
11 )
12
13 // Test basic features of the bucket struct
routing/kbucket/util.go
+1 -1
@@ -6,9 +6,9 @@ import (
6 "errors"
7
8 key "github.com/ipfs/go-ipfs/blocks/key"
9 - peer "github.com/ipfs/go-ipfs/p2p/peer"
9 ks "github.com/ipfs/go-ipfs/routing/keyspace"
10 u "github.com/ipfs/go-ipfs/util"
11 + peer "gx/ipfs/QmY3NAw959vbE1oJooP9HchcRdBsbxhgQsEZTRhKgvoSuC/go-libp2p/p2p/peer"
12 )
13
14 // Returned if a routing table query returns no results. This is NOT expected
routing/mock/centralized_client.go
+4 -4
@@ -6,15 +6,15 @@ import (
6
7 proto "github.com/ipfs/go-ipfs/Godeps/_workspace/src/github.com/gogo/protobuf/proto"
8 ds "github.com/ipfs/go-ipfs/Godeps/_workspace/src/github.com/ipfs/go-datastore"
9 - ma "github.com/ipfs/go-ipfs/Godeps/_workspace/src/github.com/jbenet/go-multiaddr"
10 - context "github.com/ipfs/go-ipfs/Godeps/_workspace/src/golang.org/x/net/context"
9 + context "gx/ipfs/QmZy2y8t9zQH2a1b8q2ZSLKp17ATuJoCNxxyMFG5qFExpt/go-net/context"
10 key "github.com/ipfs/go-ipfs/blocks/key"
12 - peer "github.com/ipfs/go-ipfs/p2p/peer"
11 routing "github.com/ipfs/go-ipfs/routing"
12 dhtpb "github.com/ipfs/go-ipfs/routing/dht/pb"
13 u "github.com/ipfs/go-ipfs/util"
14 "github.com/ipfs/go-ipfs/util/testutil"
17 - logging "github.com/ipfs/go-ipfs/vendor/QmQg1J6vikuXF9oDvm4wpdeAUvvkVEKW1EYDw9HhTMnP2b/go-log"
15 + logging "gx/ipfs/QmaPaGNE2GqnfJjRRpQuQuFHuJn4FZvsrGxdik4kgxCkBi/go-log"
16 + ma "gx/ipfs/QmR3JkmZBKYXgNMNsNZawm914455Qof3PEopwuVSeXG7aV/go-multiaddr"
17 + peer "gx/ipfs/QmY3NAw959vbE1oJooP9HchcRdBsbxhgQsEZTRhKgvoSuC/go-libp2p/p2p/peer"
18 )
19
20 var log = logging.Logger("mockrouter")
routing/mock/centralized_server.go
+2 -2
@@ -6,10 +6,10 @@ import (
6 "time"
7
8 ds "github.com/ipfs/go-ipfs/Godeps/_workspace/src/github.com/ipfs/go-datastore"
9 - context "github.com/ipfs/go-ipfs/Godeps/_workspace/src/golang.org/x/net/context"
9 + context "gx/ipfs/QmZy2y8t9zQH2a1b8q2ZSLKp17ATuJoCNxxyMFG5qFExpt/go-net/context"
10 key "github.com/ipfs/go-ipfs/blocks/key"
11 - peer "github.com/ipfs/go-ipfs/p2p/peer"
11 "github.com/ipfs/go-ipfs/util/testutil"
12 + peer "gx/ipfs/QmY3NAw959vbE1oJooP9HchcRdBsbxhgQsEZTRhKgvoSuC/go-libp2p/p2p/peer"
13 )
14
15 // server is the mockrouting.Client's private interface to the routing server
routing/mock/centralized_test.go
+2 -2
@@ -4,11 +4,11 @@ import (
4 "testing"
5 "time"
6
7 - context "github.com/ipfs/go-ipfs/Godeps/_workspace/src/golang.org/x/net/context"
7 + context "gx/ipfs/QmZy2y8t9zQH2a1b8q2ZSLKp17ATuJoCNxxyMFG5qFExpt/go-net/context"
8 key "github.com/ipfs/go-ipfs/blocks/key"
9 - peer "github.com/ipfs/go-ipfs/p2p/peer"
9 delay "github.com/ipfs/go-ipfs/thirdparty/delay"
10 "github.com/ipfs/go-ipfs/util/testutil"
11 + peer "gx/ipfs/QmY3NAw959vbE1oJooP9HchcRdBsbxhgQsEZTRhKgvoSuC/go-libp2p/p2p/peer"
12 )
13
14 func TestKeyNotFound(t *testing.T) {
routing/mock/dht.go
+2 -2
@@ -3,10 +3,10 @@ package mockrouting
3 import (
4 ds "github.com/ipfs/go-ipfs/Godeps/_workspace/src/github.com/ipfs/go-datastore"
5 sync "github.com/ipfs/go-ipfs/Godeps/_workspace/src/github.com/ipfs/go-datastore/sync"
6 - context "github.com/ipfs/go-ipfs/Godeps/_workspace/src/golang.org/x/net/context"
7 - mocknet "github.com/ipfs/go-ipfs/p2p/net/mock"
6 + context "gx/ipfs/QmZy2y8t9zQH2a1b8q2ZSLKp17ATuJoCNxxyMFG5qFExpt/go-net/context"
7 dht "github.com/ipfs/go-ipfs/routing/dht"
8 "github.com/ipfs/go-ipfs/util/testutil"
9 + mocknet "gx/ipfs/QmY3NAw959vbE1oJooP9HchcRdBsbxhgQsEZTRhKgvoSuC/go-libp2p/p2p/net/mock"
10 )
11
12 type mocknetserver struct {
routing/mock/interface.go
+2 -2
@@ -6,12 +6,12 @@ package mockrouting
6
7 import (
8 ds "github.com/ipfs/go-ipfs/Godeps/_workspace/src/github.com/ipfs/go-datastore"
9 - context "github.com/ipfs/go-ipfs/Godeps/_workspace/src/golang.org/x/net/context"
9 + context "gx/ipfs/QmZy2y8t9zQH2a1b8q2ZSLKp17ATuJoCNxxyMFG5qFExpt/go-net/context"
10 key "github.com/ipfs/go-ipfs/blocks/key"
11 - peer "github.com/ipfs/go-ipfs/p2p/peer"
11 routing "github.com/ipfs/go-ipfs/routing"
12 delay "github.com/ipfs/go-ipfs/thirdparty/delay"
13 "github.com/ipfs/go-ipfs/util/testutil"
14 + peer "gx/ipfs/QmY3NAw959vbE1oJooP9HchcRdBsbxhgQsEZTRhKgvoSuC/go-libp2p/p2p/peer"
15 )
16
17 // Server provides mockrouting Clients
routing/none/none_client.go
+4 -4
@@ -3,13 +3,13 @@ package nilrouting
3 import (
4 "errors"
5
6 - context "github.com/ipfs/go-ipfs/Godeps/_workspace/src/golang.org/x/net/context"
6 + context "gx/ipfs/QmZy2y8t9zQH2a1b8q2ZSLKp17ATuJoCNxxyMFG5qFExpt/go-net/context"
7 key "github.com/ipfs/go-ipfs/blocks/key"
8 - p2phost "github.com/ipfs/go-ipfs/p2p/host"
9 - peer "github.com/ipfs/go-ipfs/p2p/peer"
8 repo "github.com/ipfs/go-ipfs/repo"
9 routing "github.com/ipfs/go-ipfs/routing"
12 - logging "github.com/ipfs/go-ipfs/vendor/QmQg1J6vikuXF9oDvm4wpdeAUvvkVEKW1EYDw9HhTMnP2b/go-log"
10 + logging "gx/ipfs/QmaPaGNE2GqnfJjRRpQuQuFHuJn4FZvsrGxdik4kgxCkBi/go-log"
11 + p2phost "gx/ipfs/QmY3NAw959vbE1oJooP9HchcRdBsbxhgQsEZTRhKgvoSuC/go-libp2p/p2p/host"
12 + peer "gx/ipfs/QmY3NAw959vbE1oJooP9HchcRdBsbxhgQsEZTRhKgvoSuC/go-libp2p/p2p/peer"
13 )
14
15 var log = logging.Logger("mockrouter")
routing/offline/offline.go
+4 -4
@@ -6,14 +6,14 @@ import (
6
7 proto "github.com/ipfs/go-ipfs/Godeps/_workspace/src/github.com/gogo/protobuf/proto"
8 ds "github.com/ipfs/go-ipfs/Godeps/_workspace/src/github.com/ipfs/go-datastore"
9 - context "github.com/ipfs/go-ipfs/Godeps/_workspace/src/golang.org/x/net/context"
9 + context "gx/ipfs/QmZy2y8t9zQH2a1b8q2ZSLKp17ATuJoCNxxyMFG5qFExpt/go-net/context"
10 key "github.com/ipfs/go-ipfs/blocks/key"
11 - ci "github.com/ipfs/go-ipfs/p2p/crypto"
12 - "github.com/ipfs/go-ipfs/p2p/peer"
11 routing "github.com/ipfs/go-ipfs/routing"
12 pb "github.com/ipfs/go-ipfs/routing/dht/pb"
13 record "github.com/ipfs/go-ipfs/routing/record"
16 - logging "github.com/ipfs/go-ipfs/vendor/QmQg1J6vikuXF9oDvm4wpdeAUvvkVEKW1EYDw9HhTMnP2b/go-log"
14 + logging "gx/ipfs/QmaPaGNE2GqnfJjRRpQuQuFHuJn4FZvsrGxdik4kgxCkBi/go-log"
15 + ci "gx/ipfs/QmY3NAw959vbE1oJooP9HchcRdBsbxhgQsEZTRhKgvoSuC/go-libp2p/p2p/crypto"
16 + "gx/ipfs/QmY3NAw959vbE1oJooP9HchcRdBsbxhgQsEZTRhKgvoSuC/go-libp2p/p2p/peer"
17 )
18
19 var log = logging.Logger("offlinerouting")
routing/record/record.go
+2 -2
@@ -6,9 +6,9 @@ import (
6 proto "github.com/ipfs/go-ipfs/Godeps/_workspace/src/github.com/gogo/protobuf/proto"
7
8 key "github.com/ipfs/go-ipfs/blocks/key"
9 - ci "github.com/ipfs/go-ipfs/p2p/crypto"
9 pb "github.com/ipfs/go-ipfs/routing/dht/pb"
11 - logging "github.com/ipfs/go-ipfs/vendor/QmQg1J6vikuXF9oDvm4wpdeAUvvkVEKW1EYDw9HhTMnP2b/go-log"
10 + logging "gx/ipfs/QmaPaGNE2GqnfJjRRpQuQuFHuJn4FZvsrGxdik4kgxCkBi/go-log"
11 + ci "gx/ipfs/QmY3NAw959vbE1oJooP9HchcRdBsbxhgQsEZTRhKgvoSuC/go-libp2p/p2p/crypto"
12 )
13
14 var log = logging.Logger("routing/record")
routing/record/validation.go
+1 -1
@@ -5,10 +5,10 @@ import (
5 "errors"
6
7 key "github.com/ipfs/go-ipfs/blocks/key"
8 - ci "github.com/ipfs/go-ipfs/p2p/crypto"
8 path "github.com/ipfs/go-ipfs/path"
9 pb "github.com/ipfs/go-ipfs/routing/dht/pb"
10 u "github.com/ipfs/go-ipfs/util"
11 + ci "gx/ipfs/QmY3NAw959vbE1oJooP9HchcRdBsbxhgQsEZTRhKgvoSuC/go-libp2p/p2p/crypto"
12 )
13
14 // ValidatorFunc is a function that is called to validate a given
routing/routing.go
+3 -3
@@ -4,10 +4,10 @@ package routing
4 import (
5 "errors"
6
7 - context "github.com/ipfs/go-ipfs/Godeps/_workspace/src/golang.org/x/net/context"
7 key "github.com/ipfs/go-ipfs/blocks/key"
9 - ci "github.com/ipfs/go-ipfs/p2p/crypto"
10 - peer "github.com/ipfs/go-ipfs/p2p/peer"
8 + ci "gx/ipfs/QmY3NAw959vbE1oJooP9HchcRdBsbxhgQsEZTRhKgvoSuC/go-libp2p/p2p/crypto"
9 + peer "gx/ipfs/QmY3NAw959vbE1oJooP9HchcRdBsbxhgQsEZTRhKgvoSuC/go-libp2p/p2p/peer"
10 + context "gx/ipfs/QmZy2y8t9zQH2a1b8q2ZSLKp17ATuJoCNxxyMFG5qFExpt/go-net/context"
11 )
12
13 // ErrNotFound is returned when a search fails to find anything
routing/supernode/client.go
+4 -4
@@ -6,15 +6,15 @@ import (
6 "time"
7
8 proto "github.com/ipfs/go-ipfs/Godeps/_workspace/src/github.com/gogo/protobuf/proto"
9 - context "github.com/ipfs/go-ipfs/Godeps/_workspace/src/golang.org/x/net/context"
9 + context "gx/ipfs/QmZy2y8t9zQH2a1b8q2ZSLKp17ATuJoCNxxyMFG5qFExpt/go-net/context"
10
11 key "github.com/ipfs/go-ipfs/blocks/key"
12 - "github.com/ipfs/go-ipfs/p2p/host"
13 - peer "github.com/ipfs/go-ipfs/p2p/peer"
12 routing "github.com/ipfs/go-ipfs/routing"
13 pb "github.com/ipfs/go-ipfs/routing/dht/pb"
14 proxy "github.com/ipfs/go-ipfs/routing/supernode/proxy"
17 - logging "github.com/ipfs/go-ipfs/vendor/QmQg1J6vikuXF9oDvm4wpdeAUvvkVEKW1EYDw9HhTMnP2b/go-log"
15 + logging "gx/ipfs/QmaPaGNE2GqnfJjRRpQuQuFHuJn4FZvsrGxdik4kgxCkBi/go-log"
16 + "gx/ipfs/QmY3NAw959vbE1oJooP9HchcRdBsbxhgQsEZTRhKgvoSuC/go-libp2p/p2p/host"
17 + peer "gx/ipfs/QmY3NAw959vbE1oJooP9HchcRdBsbxhgQsEZTRhKgvoSuC/go-libp2p/p2p/peer"
18 )
19
20 var log = logging.Logger("supernode")
routing/supernode/proxy/loopback.go
+3 -3
@@ -2,11 +2,11 @@ package proxy
2
3 import (
4 ggio "github.com/ipfs/go-ipfs/Godeps/_workspace/src/github.com/gogo/protobuf/io"
5 - context "github.com/ipfs/go-ipfs/Godeps/_workspace/src/golang.org/x/net/context"
5 + context "gx/ipfs/QmZy2y8t9zQH2a1b8q2ZSLKp17ATuJoCNxxyMFG5qFExpt/go-net/context"
6
7 - inet "github.com/ipfs/go-ipfs/p2p/net"
8 - peer "github.com/ipfs/go-ipfs/p2p/peer"
7 dhtpb "github.com/ipfs/go-ipfs/routing/dht/pb"
8 + inet "gx/ipfs/QmY3NAw959vbE1oJooP9HchcRdBsbxhgQsEZTRhKgvoSuC/go-libp2p/p2p/net"
9 + peer "gx/ipfs/QmY3NAw959vbE1oJooP9HchcRdBsbxhgQsEZTRhKgvoSuC/go-libp2p/p2p/peer"
10 )
11
12 // RequestHandler handles routing requests locally
routing/supernode/proxy/standard.go
+7 -7
@@ -4,15 +4,15 @@ import (
4 "errors"
5
6 ggio "github.com/ipfs/go-ipfs/Godeps/_workspace/src/github.com/gogo/protobuf/io"
7 - context "github.com/ipfs/go-ipfs/Godeps/_workspace/src/golang.org/x/net/context"
7 + context "gx/ipfs/QmZy2y8t9zQH2a1b8q2ZSLKp17ATuJoCNxxyMFG5qFExpt/go-net/context"
8
9 key "github.com/ipfs/go-ipfs/blocks/key"
10 - host "github.com/ipfs/go-ipfs/p2p/host"
11 - inet "github.com/ipfs/go-ipfs/p2p/net"
12 - peer "github.com/ipfs/go-ipfs/p2p/peer"
10 dhtpb "github.com/ipfs/go-ipfs/routing/dht/pb"
11 kbucket "github.com/ipfs/go-ipfs/routing/kbucket"
15 - logging "github.com/ipfs/go-ipfs/vendor/QmQg1J6vikuXF9oDvm4wpdeAUvvkVEKW1EYDw9HhTMnP2b/go-log"
12 + logging "gx/ipfs/QmaPaGNE2GqnfJjRRpQuQuFHuJn4FZvsrGxdik4kgxCkBi/go-log"
13 + host "gx/ipfs/QmY3NAw959vbE1oJooP9HchcRdBsbxhgQsEZTRhKgvoSuC/go-libp2p/p2p/host"
14 + inet "gx/ipfs/QmY3NAw959vbE1oJooP9HchcRdBsbxhgQsEZTRhKgvoSuC/go-libp2p/p2p/net"
15 + peer "gx/ipfs/QmY3NAw959vbE1oJooP9HchcRdBsbxhgQsEZTRhKgvoSuC/go-libp2p/p2p/peer"
16 )
17
18 const ProtocolSNR = "/ipfs/supernoderouting"
@@ -98,7 +98,7 @@ func (px *standard) sendMessage(ctx context.Context, m *dhtpb.Message, remote pe
98 if err = px.Host.Connect(ctx, peer.PeerInfo{ID: remote}); err != nil {
99 return err
100 }
101 - s, err := px.Host.NewStream(ProtocolSNR, remote)
101 + s, err := px.Host.NewStream(ctx, ProtocolSNR, remote)
102 if err != nil {
103 return err
104 }
@@ -133,7 +133,7 @@ func (px *standard) sendRequest(ctx context.Context, m *dhtpb.Message, remote pe
133 e.SetError(err)
134 return nil, err
135 }
136 - s, err := px.Host.NewStream(ProtocolSNR, remote)
136 + s, err := px.Host.NewStream(ctx, ProtocolSNR, remote)
137 if err != nil {
138 e.SetError(err)
139 return nil, err
routing/supernode/server.go
+2 -2
@@ -6,13 +6,13 @@ import (
6
7 proto "github.com/ipfs/go-ipfs/Godeps/_workspace/src/github.com/gogo/protobuf/proto"
8 datastore "github.com/ipfs/go-ipfs/Godeps/_workspace/src/github.com/ipfs/go-datastore"
9 - context "github.com/ipfs/go-ipfs/Godeps/_workspace/src/golang.org/x/net/context"
9 + context "gx/ipfs/QmZy2y8t9zQH2a1b8q2ZSLKp17ATuJoCNxxyMFG5qFExpt/go-net/context"
10
11 key "github.com/ipfs/go-ipfs/blocks/key"
12 - peer "github.com/ipfs/go-ipfs/p2p/peer"
12 dhtpb "github.com/ipfs/go-ipfs/routing/dht/pb"
13 record "github.com/ipfs/go-ipfs/routing/record"
14 proxy "github.com/ipfs/go-ipfs/routing/supernode/proxy"
15 + peer "gx/ipfs/QmY3NAw959vbE1oJooP9HchcRdBsbxhgQsEZTRhKgvoSuC/go-libp2p/p2p/peer"
16 )
17
18 // Server handles routing queries using a database backend
tar/format.go
+2 -2
@@ -14,9 +14,9 @@ import (
14 dagutil "github.com/ipfs/go-ipfs/merkledag/utils"
15 path "github.com/ipfs/go-ipfs/path"
16 uio "github.com/ipfs/go-ipfs/unixfs/io"
17 - logging "github.com/ipfs/go-ipfs/vendor/QmQg1J6vikuXF9oDvm4wpdeAUvvkVEKW1EYDw9HhTMnP2b/go-log"
17 + logging "gx/ipfs/QmaPaGNE2GqnfJjRRpQuQuFHuJn4FZvsrGxdik4kgxCkBi/go-log"
18
19 - context "github.com/ipfs/go-ipfs/Godeps/_workspace/src/golang.org/x/net/context"
19 + context "gx/ipfs/QmZy2y8t9zQH2a1b8q2ZSLKp17ATuJoCNxxyMFG5qFExpt/go-net/context"
20 )
21
22 var log = logging.Logger("tarfmt")
test/dependencies/iptb/main.go
+2 -2
@@ -19,8 +19,8 @@ import (
19 kingpin "github.com/ipfs/go-ipfs/Godeps/_workspace/src/github.com/alecthomas/kingpin"
20 serial "github.com/ipfs/go-ipfs/repo/fsrepo/serialize"
21
22 - ma "github.com/ipfs/go-ipfs/Godeps/_workspace/src/github.com/jbenet/go-multiaddr"
23 - manet "github.com/ipfs/go-ipfs/Godeps/_workspace/src/github.com/jbenet/go-multiaddr-net"
22 + ma "gx/ipfs/QmR3JkmZBKYXgNMNsNZawm914455Qof3PEopwuVSeXG7aV/go-multiaddr"
23 + manet "gx/ipfs/QmYtzQmUwPFGxjCXctJ8e6GXS8sYfoXy2pdeMbS5SFWqRi/go-multiaddr-net"
24 )
25
26 var setupOpt = func(cmd *exec.Cmd) {}
test/integration/addcat_test.go
+4 -4
@@ -11,16 +11,16 @@ import (
11 "time"
12
13 random "github.com/ipfs/go-ipfs/Godeps/_workspace/src/github.com/jbenet/go-random"
14 - context "github.com/ipfs/go-ipfs/Godeps/_workspace/src/golang.org/x/net/context"
14 + context "gx/ipfs/QmZy2y8t9zQH2a1b8q2ZSLKp17ATuJoCNxxyMFG5qFExpt/go-net/context"
15
16 "github.com/ipfs/go-ipfs/core"
17 coreunix "github.com/ipfs/go-ipfs/core/coreunix"
18 mock "github.com/ipfs/go-ipfs/core/mock"
19 - mocknet "github.com/ipfs/go-ipfs/p2p/net/mock"
20 - "github.com/ipfs/go-ipfs/p2p/peer"
19 "github.com/ipfs/go-ipfs/thirdparty/unit"
20 testutil "github.com/ipfs/go-ipfs/util/testutil"
23 - logging "github.com/ipfs/go-ipfs/vendor/QmQg1J6vikuXF9oDvm4wpdeAUvvkVEKW1EYDw9HhTMnP2b/go-log"
21 + logging "gx/ipfs/QmaPaGNE2GqnfJjRRpQuQuFHuJn4FZvsrGxdik4kgxCkBi/go-log"
22 + mocknet "gx/ipfs/QmY3NAw959vbE1oJooP9HchcRdBsbxhgQsEZTRhKgvoSuC/go-libp2p/p2p/net/mock"
23 + "gx/ipfs/QmY3NAw959vbE1oJooP9HchcRdBsbxhgQsEZTRhKgvoSuC/go-libp2p/p2p/peer"
24 )
25
26 var log = logging.Logger("epictest")
test/integration/bench_cat_test.go
+3 -3
@@ -7,14 +7,14 @@ import (
7 "math"
8 "testing"
9
10 - context "github.com/ipfs/go-ipfs/Godeps/_workspace/src/golang.org/x/net/context"
10 + context "gx/ipfs/QmZy2y8t9zQH2a1b8q2ZSLKp17ATuJoCNxxyMFG5qFExpt/go-net/context"
11 "github.com/ipfs/go-ipfs/core"
12 coreunix "github.com/ipfs/go-ipfs/core/coreunix"
13 mock "github.com/ipfs/go-ipfs/core/mock"
14 - mocknet "github.com/ipfs/go-ipfs/p2p/net/mock"
15 - "github.com/ipfs/go-ipfs/p2p/peer"
14 "github.com/ipfs/go-ipfs/thirdparty/unit"
15 testutil "github.com/ipfs/go-ipfs/util/testutil"
16 + mocknet "gx/ipfs/QmY3NAw959vbE1oJooP9HchcRdBsbxhgQsEZTRhKgvoSuC/go-libp2p/p2p/net/mock"
17 + "gx/ipfs/QmY3NAw959vbE1oJooP9HchcRdBsbxhgQsEZTRhKgvoSuC/go-libp2p/p2p/peer"
18 )
19
20 func BenchmarkCat1MB(b *testing.B) { benchmarkVarCat(b, unit.MB*1) }
test/integration/bitswap_wo_routing_test.go
+2 -2
@@ -4,11 +4,11 @@ import (
4 "bytes"
5 "testing"
6
7 - context "github.com/ipfs/go-ipfs/Godeps/_workspace/src/golang.org/x/net/context"
7 + context "gx/ipfs/QmZy2y8t9zQH2a1b8q2ZSLKp17ATuJoCNxxyMFG5qFExpt/go-net/context"
8 "github.com/ipfs/go-ipfs/blocks"
9 "github.com/ipfs/go-ipfs/core"
10 "github.com/ipfs/go-ipfs/core/mock"
11 - mocknet "github.com/ipfs/go-ipfs/p2p/net/mock"
11 + mocknet "gx/ipfs/QmY3NAw959vbE1oJooP9HchcRdBsbxhgQsEZTRhKgvoSuC/go-libp2p/p2p/net/mock"
12 )
13
14 func TestBitswapWithoutRouting(t *testing.T) {
test/integration/grandcentral_test.go
+3 -3
@@ -10,18 +10,18 @@ import (
10
11 "github.com/ipfs/go-ipfs/Godeps/_workspace/src/github.com/ipfs/go-datastore"
12 syncds "github.com/ipfs/go-ipfs/Godeps/_workspace/src/github.com/ipfs/go-datastore/sync"
13 - context "github.com/ipfs/go-ipfs/Godeps/_workspace/src/golang.org/x/net/context"
13 + context "gx/ipfs/QmZy2y8t9zQH2a1b8q2ZSLKp17ATuJoCNxxyMFG5qFExpt/go-net/context"
14
15 key "github.com/ipfs/go-ipfs/blocks/key"
16 core "github.com/ipfs/go-ipfs/core"
17 "github.com/ipfs/go-ipfs/core/corerouting"
18 "github.com/ipfs/go-ipfs/core/coreunix"
19 mock "github.com/ipfs/go-ipfs/core/mock"
20 - mocknet "github.com/ipfs/go-ipfs/p2p/net/mock"
21 - "github.com/ipfs/go-ipfs/p2p/peer"
20 "github.com/ipfs/go-ipfs/thirdparty/unit"
21 ds2 "github.com/ipfs/go-ipfs/util/datastore2"
22 testutil "github.com/ipfs/go-ipfs/util/testutil"
23 + mocknet "gx/ipfs/QmY3NAw959vbE1oJooP9HchcRdBsbxhgQsEZTRhKgvoSuC/go-libp2p/p2p/net/mock"
24 + "gx/ipfs/QmY3NAw959vbE1oJooP9HchcRdBsbxhgQsEZTRhKgvoSuC/go-libp2p/p2p/peer"
25 )
26
27 func TestSupernodeBootstrappedAddCat(t *testing.T) {
test/integration/three_legged_cat_test.go
+3 -3
@@ -8,15 +8,15 @@ import (
8 "testing"
9 "time"
10
11 - context "github.com/ipfs/go-ipfs/Godeps/_workspace/src/golang.org/x/net/context"
11 + context "gx/ipfs/QmZy2y8t9zQH2a1b8q2ZSLKp17ATuJoCNxxyMFG5qFExpt/go-net/context"
12
13 core "github.com/ipfs/go-ipfs/core"
14 coreunix "github.com/ipfs/go-ipfs/core/coreunix"
15 mock "github.com/ipfs/go-ipfs/core/mock"
16 - mocknet "github.com/ipfs/go-ipfs/p2p/net/mock"
17 - "github.com/ipfs/go-ipfs/p2p/peer"
16 "github.com/ipfs/go-ipfs/thirdparty/unit"
17 testutil "github.com/ipfs/go-ipfs/util/testutil"
18 + mocknet "gx/ipfs/QmY3NAw959vbE1oJooP9HchcRdBsbxhgQsEZTRhKgvoSuC/go-libp2p/p2p/net/mock"
19 + "gx/ipfs/QmY3NAw959vbE1oJooP9HchcRdBsbxhgQsEZTRhKgvoSuC/go-libp2p/p2p/peer"
20 )
21
22 func TestThreeLeggedCatTransfer(t *testing.T) {
test/supernode_client/main.go
+4 -4
@@ -12,10 +12,10 @@ import (
12 gopath "path"
13 "time"
14
15 - ma "github.com/ipfs/go-ipfs/Godeps/_workspace/src/github.com/jbenet/go-multiaddr"
15 random "github.com/ipfs/go-ipfs/Godeps/_workspace/src/github.com/jbenet/go-random"
17 - context "github.com/ipfs/go-ipfs/Godeps/_workspace/src/golang.org/x/net/context"
16 + context "gx/ipfs/QmZy2y8t9zQH2a1b8q2ZSLKp17ATuJoCNxxyMFG5qFExpt/go-net/context"
17 "github.com/ipfs/go-ipfs/util/ipfsaddr"
18 + ma "gx/ipfs/QmR3JkmZBKYXgNMNsNZawm914455Qof3PEopwuVSeXG7aV/go-multiaddr"
19
20 "github.com/ipfs/go-ipfs/Godeps/_workspace/src/github.com/ipfs/go-datastore"
21 syncds "github.com/ipfs/go-ipfs/Godeps/_workspace/src/github.com/ipfs/go-datastore/sync"
@@ -24,13 +24,13 @@ import (
24 corehttp "github.com/ipfs/go-ipfs/core/corehttp"
25 corerouting "github.com/ipfs/go-ipfs/core/corerouting"
26 "github.com/ipfs/go-ipfs/core/coreunix"
27 - peer "github.com/ipfs/go-ipfs/p2p/peer"
27 "github.com/ipfs/go-ipfs/repo"
28 config "github.com/ipfs/go-ipfs/repo/config"
29 fsrepo "github.com/ipfs/go-ipfs/repo/fsrepo"
30 unit "github.com/ipfs/go-ipfs/thirdparty/unit"
31 ds2 "github.com/ipfs/go-ipfs/util/datastore2"
33 - logging "github.com/ipfs/go-ipfs/vendor/QmQg1J6vikuXF9oDvm4wpdeAUvvkVEKW1EYDw9HhTMnP2b/go-log"
32 + logging "gx/ipfs/QmaPaGNE2GqnfJjRRpQuQuFHuJn4FZvsrGxdik4kgxCkBi/go-log"
33 + peer "gx/ipfs/QmY3NAw959vbE1oJooP9HchcRdBsbxhgQsEZTRhKgvoSuC/go-libp2p/p2p/peer"
34 )
35
36 var elog = logging.Logger("gc-client")
thirdparty/pollEndpoint/main.go
+3 -3
@@ -10,9 +10,9 @@ import (
10 "os"
11 "time"
12
13 - ma "github.com/ipfs/go-ipfs/Godeps/_workspace/src/github.com/jbenet/go-multiaddr"
14 - manet "github.com/ipfs/go-ipfs/Godeps/_workspace/src/github.com/jbenet/go-multiaddr-net"
15 - logging "github.com/ipfs/go-ipfs/vendor/QmQg1J6vikuXF9oDvm4wpdeAUvvkVEKW1EYDw9HhTMnP2b/go-log"
13 + ma "gx/ipfs/QmR3JkmZBKYXgNMNsNZawm914455Qof3PEopwuVSeXG7aV/go-multiaddr"
14 + manet "gx/ipfs/QmYtzQmUwPFGxjCXctJ8e6GXS8sYfoXy2pdeMbS5SFWqRi/go-multiaddr-net"
15 + logging "gx/ipfs/QmaPaGNE2GqnfJjRRpQuQuFHuJn4FZvsrGxdik4kgxCkBi/go-log"
16 )
17
18 var (
tour/tour.go
+1 -1
@@ -4,7 +4,7 @@ import (
4 "strconv"
5 "strings"
6
7 - logging "github.com/ipfs/go-ipfs/vendor/QmQg1J6vikuXF9oDvm4wpdeAUvvkVEKW1EYDw9HhTMnP2b/go-log"
7 + logging "gx/ipfs/QmaPaGNE2GqnfJjRRpQuQuFHuJn4FZvsrGxdik4kgxCkBi/go-log"
8 )
9
10 var log = logging.Logger("tour")
unixfs/archive/archive.go
+1 -1
@@ -6,7 +6,7 @@ import (
6 "io"
7 "path"
8
9 - cxt "github.com/ipfs/go-ipfs/Godeps/_workspace/src/golang.org/x/net/context"
9 + cxt "gx/ipfs/QmZy2y8t9zQH2a1b8q2ZSLKp17ATuJoCNxxyMFG5qFExpt/go-net/context"
10
11 mdag "github.com/ipfs/go-ipfs/merkledag"
12 tar "github.com/ipfs/go-ipfs/unixfs/archive/tar"
unixfs/archive/tar/writer.go
+1 -1
@@ -7,7 +7,7 @@ import (
7 "time"
8
9 proto "github.com/ipfs/go-ipfs/Godeps/_workspace/src/github.com/gogo/protobuf/proto"
10 - cxt "github.com/ipfs/go-ipfs/Godeps/_workspace/src/golang.org/x/net/context"
10 + cxt "gx/ipfs/QmZy2y8t9zQH2a1b8q2ZSLKp17ATuJoCNxxyMFG5qFExpt/go-net/context"
11
12 mdag "github.com/ipfs/go-ipfs/merkledag"
13 ft "github.com/ipfs/go-ipfs/unixfs"
unixfs/io/dagreader.go
+1 -1
@@ -8,7 +8,7 @@ import (
8 "os"
9
10 proto "github.com/ipfs/go-ipfs/Godeps/_workspace/src/github.com/gogo/protobuf/proto"
11 - "github.com/ipfs/go-ipfs/Godeps/_workspace/src/golang.org/x/net/context"
11 + "gx/ipfs/QmZy2y8t9zQH2a1b8q2ZSLKp17ATuJoCNxxyMFG5qFExpt/go-net/context"
12
13 mdag "github.com/ipfs/go-ipfs/merkledag"
14 ft "github.com/ipfs/go-ipfs/unixfs"
unixfs/io/dirbuilder.go
+1 -1
@@ -1,7 +1,7 @@
1 package io
2
3 import (
4 - "github.com/ipfs/go-ipfs/Godeps/_workspace/src/golang.org/x/net/context"
4 + "gx/ipfs/QmZy2y8t9zQH2a1b8q2ZSLKp17ATuJoCNxxyMFG5qFExpt/go-net/context"
5
6 key "github.com/ipfs/go-ipfs/blocks/key"
7 mdag "github.com/ipfs/go-ipfs/merkledag"
unixfs/mod/dagmodifier.go
+2 -2
@@ -8,7 +8,7 @@ import (
8
9 proto "github.com/ipfs/go-ipfs/Godeps/_workspace/src/github.com/gogo/protobuf/proto"
10 mh "github.com/ipfs/go-ipfs/Godeps/_workspace/src/github.com/jbenet/go-multihash"
11 - context "github.com/ipfs/go-ipfs/Godeps/_workspace/src/golang.org/x/net/context"
11 + context "gx/ipfs/QmZy2y8t9zQH2a1b8q2ZSLKp17ATuJoCNxxyMFG5qFExpt/go-net/context"
12
13 key "github.com/ipfs/go-ipfs/blocks/key"
14 chunk "github.com/ipfs/go-ipfs/importer/chunk"
@@ -17,7 +17,7 @@ import (
17 mdag "github.com/ipfs/go-ipfs/merkledag"
18 ft "github.com/ipfs/go-ipfs/unixfs"
19 uio "github.com/ipfs/go-ipfs/unixfs/io"
20 - logging "github.com/ipfs/go-ipfs/vendor/QmQg1J6vikuXF9oDvm4wpdeAUvvkVEKW1EYDw9HhTMnP2b/go-log"
20 + logging "gx/ipfs/QmaPaGNE2GqnfJjRRpQuQuFHuJn4FZvsrGxdik4kgxCkBi/go-log"
21 )
22
23 var ErrSeekFail = errors.New("failed to seek properly")
unixfs/mod/dagmodifier_test.go
+1 -1
@@ -21,7 +21,7 @@ import (
21 u "github.com/ipfs/go-ipfs/util"
22
23 ds "github.com/ipfs/go-ipfs/Godeps/_workspace/src/github.com/ipfs/go-datastore"
24 - context "github.com/ipfs/go-ipfs/Godeps/_workspace/src/golang.org/x/net/context"
24 + context "gx/ipfs/QmZy2y8t9zQH2a1b8q2ZSLKp17ATuJoCNxxyMFG5qFExpt/go-net/context"
25 )
26
27 func getMockDagServ(t testing.TB) mdag.DAGService {
util/context.go
+1 -1
@@ -1,7 +1,7 @@
1 package util
2
3 import (
4 - context "github.com/ipfs/go-ipfs/Godeps/_workspace/src/golang.org/x/net/context"
4 + context "gx/ipfs/QmZy2y8t9zQH2a1b8q2ZSLKp17ATuJoCNxxyMFG5qFExpt/go-net/context"
5 )
6
7 // privateChanType protects the channel. Since this is a package-private type,
util/context_test.go
+1 -1
@@ -4,7 +4,7 @@ import (
4 "errors"
5 "testing"
6
7 - context "github.com/ipfs/go-ipfs/Godeps/_workspace/src/golang.org/x/net/context"
7 + context "gx/ipfs/QmZy2y8t9zQH2a1b8q2ZSLKp17ATuJoCNxxyMFG5qFExpt/go-net/context"
8 )
9
10 func TestLogErrorDoesNotBlockWhenCtxIsNotSetUpForLogging(t *testing.T) {
util/do.go
+1 -1
@@ -1,6 +1,6 @@
1 package util
2
3 -import "github.com/ipfs/go-ipfs/Godeps/_workspace/src/golang.org/x/net/context"
3 +import "gx/ipfs/QmZy2y8t9zQH2a1b8q2ZSLKp17ATuJoCNxxyMFG5qFExpt/go-net/context"
4
5 func ContextDo(ctx context.Context, f func() error) error {
6
util/do_test.go
+1 -1
@@ -4,7 +4,7 @@ import (
4 "errors"
5 "testing"
6
7 - "github.com/ipfs/go-ipfs/Godeps/_workspace/src/golang.org/x/net/context"
7 + "gx/ipfs/QmZy2y8t9zQH2a1b8q2ZSLKp17ATuJoCNxxyMFG5qFExpt/go-net/context"
8 )
9
10 func TestDoReturnsContextErr(t *testing.T) {
util/eventlog/loggables/loggables.go
+3 -3
@@ -9,11 +9,11 @@ package loggables
9 import (
10 "net"
11
12 - ma "github.com/ipfs/go-ipfs/Godeps/_workspace/src/github.com/jbenet/go-multiaddr"
12 + ma "gx/ipfs/QmR3JkmZBKYXgNMNsNZawm914455Qof3PEopwuVSeXG7aV/go-multiaddr"
13
14 - logging "github.com/ipfs/go-ipfs/vendor/QmQg1J6vikuXF9oDvm4wpdeAUvvkVEKW1EYDw9HhTMnP2b/go-log"
14 + logging "gx/ipfs/QmaPaGNE2GqnfJjRRpQuQuFHuJn4FZvsrGxdik4kgxCkBi/go-log"
15
16 - peer "github.com/ipfs/go-ipfs/p2p/peer"
16 + peer "gx/ipfs/QmY3NAw959vbE1oJooP9HchcRdBsbxhgQsEZTRhKgvoSuC/go-libp2p/p2p/peer"
17 )
18
19 // NetConn returns an eventlog.Metadata with the conn addresses
util/ipfsaddr/ipfsaddr.go
+3 -3
@@ -3,11 +3,11 @@ package ipfsaddr
3 import (
4 "errors"
5
6 - ma "github.com/ipfs/go-ipfs/Godeps/_workspace/src/github.com/jbenet/go-multiaddr"
6 + ma "gx/ipfs/QmR3JkmZBKYXgNMNsNZawm914455Qof3PEopwuVSeXG7aV/go-multiaddr"
7
8 - peer "github.com/ipfs/go-ipfs/p2p/peer"
8 path "github.com/ipfs/go-ipfs/path"
10 - logging "github.com/ipfs/go-ipfs/vendor/QmQg1J6vikuXF9oDvm4wpdeAUvvkVEKW1EYDw9HhTMnP2b/go-log"
9 + logging "gx/ipfs/QmaPaGNE2GqnfJjRRpQuQuFHuJn4FZvsrGxdik4kgxCkBi/go-log"
10 + peer "gx/ipfs/QmY3NAw959vbE1oJooP9HchcRdBsbxhgQsEZTRhKgvoSuC/go-libp2p/p2p/peer"
11 )
12
13 var log = logging.Logger("ipfsaddr")
util/ipfsaddr/ipfsaddr_test.go
+2 -2
@@ -3,9 +3,9 @@ package ipfsaddr
3 import (
4 "testing"
5
6 - ma "github.com/ipfs/go-ipfs/Godeps/_workspace/src/github.com/jbenet/go-multiaddr"
7 - peer "github.com/ipfs/go-ipfs/p2p/peer"
6 path "github.com/ipfs/go-ipfs/path"
7 + ma "gx/ipfs/QmR3JkmZBKYXgNMNsNZawm914455Qof3PEopwuVSeXG7aV/go-multiaddr"
8 + peer "gx/ipfs/QmY3NAw959vbE1oJooP9HchcRdBsbxhgQsEZTRhKgvoSuC/go-libp2p/p2p/peer"
9 )
10
11 var good = []string{
util/peerset/peerset.go
+1 -1
@@ -1,7 +1,7 @@
1 package peerset
2
3 import (
4 - peer "github.com/ipfs/go-ipfs/p2p/peer"
4 + peer "gx/ipfs/QmY3NAw959vbE1oJooP9HchcRdBsbxhgQsEZTRhKgvoSuC/go-libp2p/p2p/peer"
5 "sync"
6 )
7
util/testutil/gen.go
+3 -3
@@ -8,11 +8,11 @@ import (
8 "sync"
9 "testing"
10
11 - ci "github.com/ipfs/go-ipfs/p2p/crypto"
12 - peer "github.com/ipfs/go-ipfs/p2p/peer"
11 u "github.com/ipfs/go-ipfs/util"
12 + ci "gx/ipfs/QmY3NAw959vbE1oJooP9HchcRdBsbxhgQsEZTRhKgvoSuC/go-libp2p/p2p/crypto"
13 + peer "gx/ipfs/QmY3NAw959vbE1oJooP9HchcRdBsbxhgQsEZTRhKgvoSuC/go-libp2p/p2p/peer"
14
15 - ma "github.com/ipfs/go-ipfs/Godeps/_workspace/src/github.com/jbenet/go-multiaddr"
15 + ma "gx/ipfs/QmR3JkmZBKYXgNMNsNZawm914455Qof3PEopwuVSeXG7aV/go-multiaddr"
16 )
17
18 // ZeroLocalTCPAddress is the "zero" tcp local multiaddr. This means:
util/testutil/identity.go
+3 -3
@@ -3,9 +3,9 @@ package testutil
3 import (
4 "testing"
5
6 - ma "github.com/ipfs/go-ipfs/Godeps/_workspace/src/github.com/jbenet/go-multiaddr"
7 - ci "github.com/ipfs/go-ipfs/p2p/crypto"
8 - peer "github.com/ipfs/go-ipfs/p2p/peer"
6 + ma "gx/ipfs/QmR3JkmZBKYXgNMNsNZawm914455Qof3PEopwuVSeXG7aV/go-multiaddr"
7 + ci "gx/ipfs/QmY3NAw959vbE1oJooP9HchcRdBsbxhgQsEZTRhKgvoSuC/go-libp2p/p2p/crypto"
8 + peer "gx/ipfs/QmY3NAw959vbE1oJooP9HchcRdBsbxhgQsEZTRhKgvoSuC/go-libp2p/p2p/peer"
9 )
10
11 type Identity interface {
vendor/QmQg1J6vikuXF9oDvm4wpdeAUvvkVEKW1EYDw9HhTMnP2b/go-log/.gxlastpubver deleted
-1
@@ -1 +0,0 @@
1 -1.0.0: QmXQEqXS3TDyhAFGBFeMadaBYJ2ismXXyQSn5i7HubcQUH
vendor/QmQg1J6vikuXF9oDvm4wpdeAUvvkVEKW1EYDw9HhTMnP2b/go-log/context.go deleted
-38
@@ -1,38 +0,0 @@
1 -package log
2 -
3 -import (
4 - "errors"
5 -
6 - "github.com/ipfs/go-ipfs/Godeps/_workspace/src/golang.org/x/net/context"
7 -)
8 -
9 -type key int
10 -
11 -const metadataKey key = 0
12 -
13 -// ContextWithLoggable returns a derived context which contains the provided
14 -// Loggable. Any Events logged with the derived context will include the
15 -// provided Loggable.
16 -func ContextWithLoggable(ctx context.Context, l Loggable) context.Context {
17 - existing, err := MetadataFromContext(ctx)
18 - if err != nil {
19 - // context does not contain meta. just set the new metadata
20 - child := context.WithValue(ctx, metadataKey, Metadata(l.Loggable()))
21 - return child
22 - }
23 -
24 - merged := DeepMerge(existing, l.Loggable())
25 - child := context.WithValue(ctx, metadataKey, merged)
26 - return child
27 -}
28 -
29 -func MetadataFromContext(ctx context.Context) (Metadata, error) {
30 - value := ctx.Value(metadataKey)
31 - if value != nil {
32 - metadata, ok := value.(Metadata)
33 - if ok {
34 - return metadata, nil
35 - }
36 - }
37 - return nil, errors.New("context contains no metadata")
38 -}
vendor/QmQg1J6vikuXF9oDvm4wpdeAUvvkVEKW1EYDw9HhTMnP2b/go-log/context_test.go deleted
-44
@@ -1,44 +0,0 @@
1 -package log
2 -
3 -import (
4 - "testing"
5 -
6 - "github.com/ipfs/go-ipfs/Godeps/_workspace/src/golang.org/x/net/context"
7 -)
8 -
9 -func TestContextContainsMetadata(t *testing.T) {
10 - t.Parallel()
11 -
12 - m := Metadata{"foo": "bar"}
13 - ctx := ContextWithLoggable(context.Background(), m)
14 - got, err := MetadataFromContext(ctx)
15 - if err != nil {
16 - t.Fatal(err)
17 - }
18 -
19 - _, exists := got["foo"]
20 - if !exists {
21 - t.Fail()
22 - }
23 -}
24 -
25 -func TestContextWithPreexistingMetadata(t *testing.T) {
26 - t.Parallel()
27 -
28 - ctx := ContextWithLoggable(context.Background(), Metadata{"hello": "world"})
29 - ctx = ContextWithLoggable(ctx, Metadata{"goodbye": "earth"})
30 -
31 - got, err := MetadataFromContext(ctx)
32 - if err != nil {
33 - t.Fatal(err)
34 - }
35 -
36 - _, exists := got["hello"]
37 - if !exists {
38 - t.Fatal("original key not present")
39 - }
40 - _, exists = got["goodbye"]
41 - if !exists {
42 - t.Fatal("new key not present")
43 - }
44 -}
vendor/QmQg1J6vikuXF9oDvm4wpdeAUvvkVEKW1EYDw9HhTMnP2b/go-log/entry.go deleted
-7
@@ -1,7 +0,0 @@
1 -package log
2 -
3 -type entry struct {
4 - loggables []Loggable
5 - system string
6 - event string
7 -}
vendor/QmQg1J6vikuXF9oDvm4wpdeAUvvkVEKW1EYDw9HhTMnP2b/go-log/example_test.go deleted
-16
@@ -1,16 +0,0 @@
1 -package log
2 -
3 -import "github.com/ipfs/go-ipfs/Godeps/_workspace/src/golang.org/x/net/context"
4 -
5 -func ExampleEventLogger() {
6 - {
7 - log := EventLogger(nil)
8 - e := log.EventBegin(context.Background(), "dial")
9 - e.Done()
10 - }
11 - {
12 - log := EventLogger(nil)
13 - e := log.EventBegin(context.Background(), "dial")
14 - _ = e.Close() // implements io.Closer for convenience
15 - }
16 -}
vendor/QmQg1J6vikuXF9oDvm4wpdeAUvvkVEKW1EYDw9HhTMnP2b/go-log/log.go deleted
-170
@@ -1,170 +0,0 @@
1 -package log
2 -
3 -import (
4 - "encoding/json"
5 - "fmt"
6 - "time"
7 -
8 - context "github.com/ipfs/go-ipfs/Godeps/_workspace/src/golang.org/x/net/context"
9 -)
10 -
11 -// StandardLogger provides API compatibility with standard printf loggers
12 -// eg. go-logging
13 -type StandardLogger interface {
14 - Debug(args ...interface{})
15 - Debugf(format string, args ...interface{})
16 - Error(args ...interface{})
17 - Errorf(format string, args ...interface{})
18 - Fatal(args ...interface{})
19 - Fatalf(format string, args ...interface{})
20 - Info(args ...interface{})
21 - Infof(format string, args ...interface{})
22 - Panic(args ...interface{})
23 - Panicf(format string, args ...interface{})
24 - Warning(args ...interface{})
25 - Warningf(format string, args ...interface{})
26 -}
27 -
28 -// EventLogger extends the StandardLogger interface to allow for log items
29 -// containing structured metadata
30 -type EventLogger interface {
31 - StandardLogger
32 -
33 - // Event merges structured data from the provided inputs into a single
34 - // machine-readable log event.
35 - //
36 - // If the context contains metadata, a copy of this is used as the base
37 - // metadata accumulator.
38 - //
39 - // If one or more loggable objects are provided, these are deep-merged into base blob.
40 - //
41 - // Next, the event name is added to the blob under the key "event". If
42 - // the key "event" already exists, it will be over-written.
43 - //
44 - // Finally the timestamp and package name are added to the accumulator and
45 - // the metadata is logged.
46 - Event(ctx context.Context, event string, m ...Loggable)
47 -
48 - EventBegin(ctx context.Context, event string, m ...Loggable) *EventInProgress
49 -}
50 -
51 -// Logger retrieves an event logger by name
52 -func Logger(system string) EventLogger {
53 -
54 - // TODO if we would like to adjust log levels at run-time. Store this event
55 - // logger in a map (just like the util.Logger impl)
56 - if len(system) == 0 {
57 - setuplog := getLogger("setup-logger")
58 - setuplog.Warning("Missing name parameter")
59 - system = "undefined"
60 - }
61 -
62 - logger := getLogger(system)
63 -
64 - return &eventLogger{system: system, StandardLogger: logger}
65 -}
66 -
67 -// eventLogger implements the EventLogger and wraps a go-logging Logger
68 -type eventLogger struct {
69 - StandardLogger
70 -
71 - system string
72 - // TODO add log-level
73 -}
74 -
75 -func (el *eventLogger) EventBegin(ctx context.Context, event string, metadata ...Loggable) *EventInProgress {
76 - start := time.Now()
77 - el.Event(ctx, fmt.Sprintf("%sBegin", event), metadata...)
78 -
79 - eip := &EventInProgress{}
80 - eip.doneFunc = func(additional []Loggable) {
81 -
82 - metadata = append(metadata, additional...) // anything added during the operation
83 - metadata = append(metadata, LoggableMap(map[string]interface{}{ // finally, duration of event
84 - "duration": time.Now().Sub(start),
85 - }))
86 -
87 - el.Event(ctx, event, metadata...)
88 - }
89 - return eip
90 -}
91 -
92 -func (el *eventLogger) Event(ctx context.Context, event string, metadata ...Loggable) {
93 -
94 - // short circuit if theres nothing to write to
95 - if !WriterGroup.Active() {
96 - return
97 - }
98 -
99 - // Collect loggables for later logging
100 - var loggables []Loggable
101 -
102 - // get any existing metadata from the context
103 - existing, err := MetadataFromContext(ctx)
104 - if err != nil {
105 - existing = Metadata{}
106 - }
107 - loggables = append(loggables, existing)
108 -
109 - for _, datum := range metadata {
110 - loggables = append(loggables, datum)
111 - }
112 -
113 - e := entry{
114 - loggables: loggables,
115 - system: el.system,
116 - event: event,
117 - }
118 -
119 - accum := Metadata{}
120 - for _, loggable := range e.loggables {
121 - accum = DeepMerge(accum, loggable.Loggable())
122 - }
123 -
124 - // apply final attributes to reserved keys
125 - // TODO accum["level"] = level
126 - accum["event"] = e.event
127 - accum["system"] = e.system
128 - accum["time"] = FormatRFC3339(time.Now())
129 -
130 - out, err := json.Marshal(accum)
131 - if err != nil {
132 - el.Errorf("ERROR FORMATTING EVENT ENTRY: %s", err)
133 - return
134 - }
135 -
136 - WriterGroup.Write(append(out, '\n'))
137 -}
138 -
139 -type EventInProgress struct {
140 - loggables []Loggable
141 - doneFunc func([]Loggable)
142 -}
143 -
144 -// Append adds loggables to be included in the call to Done
145 -func (eip *EventInProgress) Append(l Loggable) {
146 - eip.loggables = append(eip.loggables, l)
147 -}
148 -
149 -// SetError includes the provided error
150 -func (eip *EventInProgress) SetError(err error) {
151 - eip.loggables = append(eip.loggables, LoggableMap{
152 - "error": err.Error(),
153 - })
154 -}
155 -
156 -// Done creates a new Event entry that includes the duration and appended
157 -// loggables.
158 -func (eip *EventInProgress) Done() {
159 - eip.doneFunc(eip.loggables) // create final event with extra data
160 -}
161 -
162 -// Close is an alias for done
163 -func (eip *EventInProgress) Close() error {
164 - eip.Done()
165 - return nil
166 -}
167 -
168 -func FormatRFC3339(t time.Time) string {
169 - return t.UTC().Format(time.RFC3339Nano)
170 -}
vendor/QmQg1J6vikuXF9oDvm4wpdeAUvvkVEKW1EYDw9HhTMnP2b/go-log/loggable.go deleted
-34
@@ -1,34 +0,0 @@
1 -package log
2 -
3 -// Loggable describes objects that can be marshalled into Metadata for logging
4 -type Loggable interface {
5 - Loggable() map[string]interface{}
6 -}
7 -
8 -type LoggableMap map[string]interface{}
9 -
10 -func (l LoggableMap) Loggable() map[string]interface{} {
11 - return l
12 -}
13 -
14 -// LoggableF converts a func into a Loggable
15 -type LoggableF func() map[string]interface{}
16 -
17 -func (l LoggableF) Loggable() map[string]interface{} {
18 - return l()
19 -}
20 -
21 -func Deferred(key string, f func() string) Loggable {
22 - function := func() map[string]interface{} {
23 - return map[string]interface{}{
24 - key: f(),
25 - }
26 - }
27 - return LoggableF(function)
28 -}
29 -
30 -func Pair(key string, l Loggable) Loggable {
31 - return LoggableMap{
32 - key: l,
33 - }
34 -}
vendor/QmQg1J6vikuXF9oDvm4wpdeAUvvkVEKW1EYDw9HhTMnP2b/go-log/metadata.go deleted
-82
@@ -1,82 +0,0 @@
1 -package log
2 -
3 -import (
4 - "encoding/json"
5 - "errors"
6 - "reflect"
7 -
8 - "github.com/ipfs/go-ipfs/Godeps/_workspace/src/github.com/satori/go.uuid"
9 -)
10 -
11 -// Metadata is a convenience type for generic maps
12 -type Metadata map[string]interface{}
13 -
14 -// Uuid returns a Metadata with the string key and UUID value
15 -func Uuid(key string) Metadata {
16 - return Metadata{
17 - key: uuid.NewV4().String(),
18 - }
19 -}
20 -
21 -// DeepMerge merges the second Metadata parameter into the first.
22 -// Nested Metadata are merged recursively. Primitives are over-written.
23 -func DeepMerge(b, a Metadata) Metadata {
24 - out := Metadata{}
25 - for k, v := range b {
26 - out[k] = v
27 - }
28 - for k, v := range a {
29 -
30 - maybe, err := Metadatify(v)
31 - if err != nil {
32 - // if the new value is not meta. just overwrite the dest vaue
33 - out[k] = v
34 - continue
35 - }
36 -
37 - // it is meta. What about dest?
38 - outv, exists := out[k]
39 - if !exists {
40 - // the new value is meta, but there's no dest value. just write it
41 - out[k] = v
42 - continue
43 - }
44 -
45 - outMetadataValue, err := Metadatify(outv)
46 - if err != nil {
47 - // the new value is meta and there's a dest value, but the dest
48 - // value isn't meta. just overwrite
49 - out[k] = v
50 - continue
51 - }
52 -
53 - // both are meta. merge them.
54 - out[k] = DeepMerge(outMetadataValue, maybe)
55 - }
56 - return out
57 -}
58 -
59 -// Loggable implements the Loggable interface
60 -func (m Metadata) Loggable() map[string]interface{} {
61 - // NB: method defined on value to avoid de-referencing nil Metadata
62 - return m
63 -}
64 -
65 -func (m Metadata) JsonString() (string, error) {
66 - // NB: method defined on value
67 - b, err := json.Marshal(m)
68 - return string(b), err
69 -}
70 -
71 -// Metadatify converts maps into Metadata
72 -func Metadatify(i interface{}) (Metadata, error) {
73 - value := reflect.ValueOf(i)
74 - if value.Kind() == reflect.Map {
75 - m := map[string]interface{}{}
76 - for _, k := range value.MapKeys() {
77 - m[k.String()] = value.MapIndex(k).Interface()
78 - }
79 - return Metadata(m), nil
80 - }
81 - return nil, errors.New("is not a map")
82 -}
vendor/QmQg1J6vikuXF9oDvm4wpdeAUvvkVEKW1EYDw9HhTMnP2b/go-log/metadata_test.go deleted
-50
@@ -1,50 +0,0 @@
1 -package log
2 -
3 -import "testing"
4 -
5 -func TestOverwrite(t *testing.T) {
6 - t.Parallel()
7 -
8 - under := Metadata{
9 - "a": Metadata{
10 - "b": Metadata{
11 - "c": Metadata{
12 - "d": "the original value",
13 - "other": "SURVIVE",
14 - },
15 - },
16 - },
17 - }
18 - over := Metadata{
19 - "a": Metadata{
20 - "b": Metadata{
21 - "c": Metadata{
22 - "d": "a new value",
23 - },
24 - },
25 - },
26 - }
27 -
28 - out := DeepMerge(under, over)
29 -
30 - dval := out["a"].(Metadata)["b"].(Metadata)["c"].(Metadata)["d"].(string)
31 - if dval != "a new value" {
32 - t.Fatal(dval)
33 - }
34 - surv := out["a"].(Metadata)["b"].(Metadata)["c"].(Metadata)["other"].(string)
35 - if surv != "SURVIVE" {
36 - t.Fatal(surv)
37 - }
38 -}
39 -
40 -func TestMarshalJSON(t *testing.T) {
41 - t.Parallel()
42 - bs, _ := Metadata{"a": "b"}.JsonString()
43 - t.Log(bs)
44 -}
45 -
46 -func TestMetadataIsLoggable(t *testing.T) {
47 - t.Parallel()
48 - func(l Loggable) {
49 - }(Metadata{})
50 -}
vendor/QmQg1J6vikuXF9oDvm4wpdeAUvvkVEKW1EYDw9HhTMnP2b/go-log/oldlog.go deleted
-105
@@ -1,105 +0,0 @@
1 -package log
2 -
3 -import (
4 - "errors"
5 - "fmt"
6 - "os"
7 -
8 - logging "github.com/ipfs/go-ipfs/Godeps/_workspace/src/github.com/whyrusleeping/go-logging"
9 -)
10 -
11 -func init() {
12 - SetupLogging()
13 -}
14 -
15 -var ansiGray = "\033[0;37m"
16 -var ansiBlue = "\033[0;34m"
17 -
18 -var LogFormats = map[string]string{
19 - "nocolor": "%{time:2006-01-02 15:04:05.000000} %{level} %{module} %{shortfile}: %{message}",
20 - "color": ansiGray + "%{time:15:04:05.000} %{color}%{level:5.5s} " + ansiBlue +
21 - "%{module:10.10s}: %{color:reset}%{message} " + ansiGray + "%{shortfile}%{color:reset}",
22 -}
23 -
24 -var defaultLogFormat = "color"
25 -
26 -// Logging environment variables
27 -const (
28 - envLogging = "IPFS_LOGGING"
29 - envLoggingFmt = "IPFS_LOGGING_FMT"
30 -)
31 -
32 -// ErrNoSuchLogger is returned when the util pkg is asked for a non existant logger
33 -var ErrNoSuchLogger = errors.New("Error: No such logger")
34 -
35 -// loggers is the set of loggers in the system
36 -var loggers = map[string]*logging.Logger{}
37 -
38 -// SetupLogging will initialize the logger backend and set the flags.
39 -func SetupLogging() {
40 -
41 - lfmt := LogFormats[os.Getenv(envLoggingFmt)]
42 - if lfmt == "" {
43 - lfmt = LogFormats[defaultLogFormat]
44 - }
45 -
46 - backend := logging.NewLogBackend(os.Stderr, "", 0)
47 - logging.SetBackend(backend)
48 - logging.SetFormatter(logging.MustStringFormatter(lfmt))
49 -
50 - lvl := logging.ERROR
51 -
52 - if logenv := os.Getenv(envLogging); logenv != "" {
53 - var err error
54 - lvl, err = logging.LogLevel(logenv)
55 - if err != nil {
56 - fmt.Println("error setting log levels", err)
57 - }
58 - }
59 -
60 - SetAllLoggers(lvl)
61 -}
62 -
63 -// SetDebugLogging calls SetAllLoggers with logging.DEBUG
64 -func SetDebugLogging() {
65 - SetAllLoggers(logging.DEBUG)
66 -}
67 -
68 -// SetAllLoggers changes the logging.Level of all loggers to lvl
69 -func SetAllLoggers(lvl logging.Level) {
70 - logging.SetLevel(lvl, "")
71 - for n := range loggers {
72 - logging.SetLevel(lvl, n)
73 - }
74 -}
75 -
76 -// SetLogLevel changes the log level of a specific subsystem
77 -// name=="*" changes all subsystems
78 -func SetLogLevel(name, level string) error {
79 - lvl, err := logging.LogLevel(level)
80 - if err != nil {
81 - return err
82 - }
83 -
84 - // wildcard, change all
85 - if name == "*" {
86 - SetAllLoggers(lvl)
87 - return nil
88 - }
89 -
90 - // Check if we have a logger by that name
91 - if _, ok := loggers[name]; !ok {
92 - return ErrNoSuchLogger
93 - }
94 -
95 - logging.SetLevel(lvl, name)
96 -
97 - return nil
98 -}
99 -
100 -func getLogger(name string) *logging.Logger {
101 - log := logging.MustGetLogger(name)
102 - log.ExtraCalldepth = 1
103 - loggers[name] = log
104 - return log
105 -}
vendor/QmQg1J6vikuXF9oDvm4wpdeAUvvkVEKW1EYDw9HhTMnP2b/go-log/option.go deleted
-52
@@ -1,52 +0,0 @@
1 -package log
2 -
3 -import (
4 - "io"
5 -
6 - logging "github.com/ipfs/go-ipfs/Godeps/_workspace/src/github.com/whyrusleeping/go-logging"
7 -)
8 -
9 -// Global writer group for logs to output to
10 -var WriterGroup = NewMirrorWriter()
11 -
12 -type Option func()
13 -
14 -// Configure applies the provided options sequentially from left to right
15 -func Configure(options ...Option) {
16 - for _, f := range options {
17 - f()
18 - }
19 -}
20 -
21 -// LdJSONFormatter Option formats the event log as line-delimited JSON
22 -var LdJSONFormatter = func() {
23 - logging.SetFormatter(&PoliteJSONFormatter{})
24 -}
25 -
26 -// TextFormatter Option formats the event log as human-readable plain-text
27 -var TextFormatter = func() {
28 - logging.SetFormatter(logging.DefaultFormatter)
29 -}
30 -
31 -func Output(w io.Writer) Option {
32 - return func() {
33 - backend := logging.NewLogBackend(w, "", 0)
34 - logging.SetBackend(backend)
35 - // TODO return previous Output option
36 - }
37 -}
38 -
39 -// LevelDebug Option sets the log level to debug
40 -var LevelDebug = func() {
41 - logging.SetLevel(logging.DEBUG, "")
42 -}
43 -
44 -// LevelError Option sets the log level to error
45 -var LevelError = func() {
46 - logging.SetLevel(logging.ERROR, "")
47 -}
48 -
49 -// LevelInfo Option sets the log level to info
50 -var LevelInfo = func() {
51 - logging.SetLevel(logging.INFO, "")
52 -}
vendor/QmQg1J6vikuXF9oDvm4wpdeAUvvkVEKW1EYDw9HhTMnP2b/go-log/package.json deleted
-8
@@ -1,8 +0,0 @@
1 -{
2 - "name": "go-log",
3 - "version": "1.0.0",
4 - "language": "go",
5 - "go":{
6 - "dvcsimport":"github.com/ipfs/go-log"
7 - }
8 -}
vendor/QmQg1J6vikuXF9oDvm4wpdeAUvvkVEKW1EYDw9HhTMnP2b/go-log/polite_json_formatter.go deleted
-28
@@ -1,28 +0,0 @@
1 -package log
2 -
3 -import (
4 - "encoding/json"
5 - "io"
6 -
7 - logging "github.com/ipfs/go-ipfs/Godeps/_workspace/src/github.com/whyrusleeping/go-logging"
8 -)
9 -
10 -// PoliteJSONFormatter marshals entries into JSON encoded slices (without
11 -// overwriting user-provided keys). How polite of it!
12 -type PoliteJSONFormatter struct{}
13 -
14 -func (f *PoliteJSONFormatter) Format(calldepth int, r *logging.Record, w io.Writer) error {
15 - entry := make(map[string]interface{})
16 - entry["id"] = r.Id
17 - entry["level"] = r.Level
18 - entry["time"] = r.Time
19 - entry["module"] = r.Module
20 - entry["message"] = r.Message()
21 - err := json.NewEncoder(w).Encode(entry)
22 - if err != nil {
23 - return err
24 - }
25 -
26 - w.Write([]byte{'\n'})
27 - return nil
28 -}
vendor/QmQg1J6vikuXF9oDvm4wpdeAUvvkVEKW1EYDw9HhTMnP2b/go-log/writer.go deleted
-251
@@ -1,251 +0,0 @@
1 -package log
2 -
3 -import (
4 - "fmt"
5 - "io"
6 - "sync"
7 -)
8 -
9 -var MaxWriterBuffer = 512 * 1024
10 -
11 -var log = Logger("eventlog")
12 -
13 -type MirrorWriter struct {
14 - active bool
15 - activelk sync.Mutex
16 -
17 - // channel for incoming writers
18 - writerAdd chan *writerAdd
19 -
20 - // slices of writer/sync-channel pairs
21 - writers []*bufWriter
22 -
23 - // synchronization channel for incoming writes
24 - msgSync chan []byte
25 -}
26 -
27 -type writerSync struct {
28 - w io.WriteCloser
29 - br chan []byte
30 -}
31 -
32 -func NewMirrorWriter() *MirrorWriter {
33 - mw := &MirrorWriter{
34 - msgSync: make(chan []byte, 64), // sufficiently large buffer to avoid callers waiting
35 - writerAdd: make(chan *writerAdd),
36 - }
37 -
38 - go mw.logRoutine()
39 -
40 - return mw
41 -}
42 -
43 -func (mw *MirrorWriter) Write(b []byte) (int, error) {
44 - mycopy := make([]byte, len(b))
45 - copy(mycopy, b)
46 - mw.msgSync <- mycopy
47 - return len(b), nil
48 -}
49 -
50 -func (mw *MirrorWriter) Close() error {
51 - // it is up to the caller to ensure that write is not called during or
52 - // after close is called.
53 - close(mw.msgSync)
54 - return nil
55 -}
56 -
57 -func (mw *MirrorWriter) doClose() {
58 - for _, w := range mw.writers {
59 - w.writer.Close()
60 - }
61 -}
62 -
63 -func (mw *MirrorWriter) logRoutine() {
64 - // rebind to avoid races on nilling out struct fields
65 - msgSync := mw.msgSync
66 - writerAdd := mw.writerAdd
67 -
68 - defer mw.doClose()
69 -
70 - for {
71 - select {
72 - case b, ok := <-msgSync:
73 - if !ok {
74 - return
75 - }
76 -
77 - // write to all writers
78 - dropped := mw.broadcastMessage(b)
79 -
80 - // consolidate the slice
81 - if dropped {
82 - mw.clearDeadWriters()
83 - }
84 - case wa := <-writerAdd:
85 - mw.writers = append(mw.writers, newBufWriter(wa.w))
86 -
87 - mw.activelk.Lock()
88 - mw.active = true
89 - mw.activelk.Unlock()
90 - close(wa.done)
91 - }
92 - }
93 -}
94 -
95 -// broadcastMessage sends the given message to every writer
96 -// if any writer is killed during the send, 'true' is returned
97 -func (mw *MirrorWriter) broadcastMessage(b []byte) bool {
98 - var dropped bool
99 - for i, w := range mw.writers {
100 - _, err := w.Write(b)
101 - if err != nil {
102 - mw.writers[i] = nil
103 - dropped = true
104 - }
105 - }
106 - return dropped
107 -}
108 -
109 -func (mw *MirrorWriter) clearDeadWriters() {
110 - writers := mw.writers
111 - mw.writers = nil
112 - for _, w := range writers {
113 - if w != nil {
114 - mw.writers = append(mw.writers, w)
115 - }
116 - }
117 - if len(mw.writers) == 0 {
118 - mw.activelk.Lock()
119 - mw.active = false
120 - mw.activelk.Unlock()
121 - }
122 -}
123 -
124 -type writerAdd struct {
125 - w io.WriteCloser
126 - done chan struct{}
127 -}
128 -
129 -func (mw *MirrorWriter) AddWriter(w io.WriteCloser) {
130 - wa := &writerAdd{
131 - w: w,
132 - done: make(chan struct{}),
133 - }
134 - mw.writerAdd <- wa
135 - <-wa.done
136 -}
137 -
138 -func (mw *MirrorWriter) Active() (active bool) {
139 - mw.activelk.Lock()
140 - active = mw.active
141 - mw.activelk.Unlock()
142 - return
143 -}
144 -
145 -func newBufWriter(w io.WriteCloser) *bufWriter {
146 - bw := &bufWriter{
147 - writer: w,
148 - incoming: make(chan []byte, 1),
149 - }
150 -
151 - go bw.loop()
152 - return bw
153 -}
154 -
155 -type bufWriter struct {
156 - writer io.WriteCloser
157 -
158 - incoming chan []byte
159 -
160 - deathLock sync.Mutex
161 - dead bool
162 -}
163 -
164 -var errDeadWriter = fmt.Errorf("writer is dead")
165 -
166 -func (bw *bufWriter) Write(b []byte) (int, error) {
167 - bw.deathLock.Lock()
168 - dead := bw.dead
169 - bw.deathLock.Unlock()
170 - if dead {
171 - if bw.incoming != nil {
172 - close(bw.incoming)
173 - bw.incoming = nil
174 - }
175 - return 0, errDeadWriter
176 - }
177 -
178 - bw.incoming <- b
179 - return len(b), nil
180 -}
181 -
182 -func (bw *bufWriter) die() {
183 - bw.deathLock.Lock()
184 - bw.dead = true
185 - bw.writer.Close()
186 - bw.deathLock.Unlock()
187 -}
188 -
189 -func (bw *bufWriter) loop() {
190 - bufsize := 0
191 - bufBase := make([][]byte, 0, 16) // some initial memory
192 - buffered := bufBase
193 - nextCh := make(chan []byte)
194 -
195 - var nextMsg []byte
196 -
197 - go func() {
198 - for b := range nextCh {
199 - _, err := bw.writer.Write(b)
200 - if err != nil {
201 - log.Info("eventlog write error: %s", err)
202 - bw.die()
203 - return
204 - }
205 - }
206 - }()
207 -
208 - // collect and buffer messages
209 - incoming := bw.incoming
210 - for {
211 - if nextMsg == nil || nextCh == nil {
212 - // nextCh == nil implies we are 'dead' and draining the incoming channel
213 - // until the caller notices and closes it for us
214 - select {
215 - case b, ok := <-incoming:
216 - if !ok {
217 - return
218 - }
219 - nextMsg = b
220 - }
221 - }
222 -
223 - select {
224 - case b, ok := <-incoming:
225 - if !ok {
226 - return
227 - }
228 - bufsize += len(b)
229 - buffered = append(buffered, b)
230 - if bufsize > MaxWriterBuffer {
231 - // if we have too many messages buffered, kill the writer
232 - bw.die()
233 - close(nextCh)
234 - nextCh = nil
235 - // explicity keep going here to drain incoming
236 - }
237 - case nextCh <- nextMsg:
238 - nextMsg = nil
239 - if len(buffered) > 0 {
240 - nextMsg = buffered[0]
241 - buffered = buffered[1:]
242 - bufsize -= len(nextMsg)
243 - }
244 -
245 - if len(buffered) == 0 {
246 - // reset slice position
247 - buffered = bufBase[:0]
248 - }
249 - }
250 - }
251 -}
vendor/QmQg1J6vikuXF9oDvm4wpdeAUvvkVEKW1EYDw9HhTMnP2b/go-log/writer_test.go deleted
-160
@@ -1,160 +0,0 @@
1 -package log
2 -
3 -import (
4 - "fmt"
5 - "hash/fnv"
6 - "io"
7 - "sync"
8 - "testing"
9 - "time"
10 -
11 - randbo "github.com/ipfs/go-ipfs/Godeps/_workspace/src/github.com/dustin/randbo"
12 -)
13 -
14 -type hangwriter struct {
15 - c chan struct{}
16 -}
17 -
18 -func newHangWriter() *hangwriter {
19 - return &hangwriter{make(chan struct{})}
20 -}
21 -
22 -func (hw *hangwriter) Write([]byte) (int, error) {
23 - <-make(chan struct{})
24 - return 0, fmt.Errorf("write on closed writer")
25 -}
26 -
27 -func (hw *hangwriter) Close() error {
28 - close(hw.c)
29 - return nil
30 -}
31 -
32 -func TestMirrorWriterHang(t *testing.T) {
33 - mw := NewMirrorWriter()
34 -
35 - hw := newHangWriter()
36 - pr, pw := io.Pipe()
37 -
38 - mw.AddWriter(hw)
39 - mw.AddWriter(pw)
40 -
41 - msg := "Hello!"
42 - mw.Write([]byte(msg))
43 -
44 - // make sure writes through can happen even with one writer hanging
45 - done := make(chan struct{})
46 - go func() {
47 - buf := make([]byte, 10)
48 - n, err := pr.Read(buf)
49 - if err != nil {
50 - t.Fatal(err)
51 - }
52 -
53 - if n != len(msg) {
54 - t.Fatal("read wrong amount")
55 - }
56 -
57 - if string(buf[:n]) != msg {
58 - t.Fatal("didnt read right content")
59 - }
60 -
61 - done <- struct{}{}
62 - }()
63 -
64 - select {
65 - case <-time.After(time.Second * 5):
66 - t.Fatal("write to mirrorwriter hung")
67 - case <-done:
68 - }
69 -
70 - if !mw.Active() {
71 - t.Fatal("writer should still be active")
72 - }
73 -
74 - pw.Close()
75 -
76 - if !mw.Active() {
77 - t.Fatal("writer should still be active")
78 - }
79 -
80 - // now we just have the hangwriter
81 -
82 - // write a bunch to it
83 - buf := make([]byte, 8192)
84 - for i := 0; i < 128; i++ {
85 - mw.Write(buf)
86 - }
87 -
88 - // wait for goroutines to sync up
89 - time.Sleep(time.Millisecond * 500)
90 -
91 - // the hangwriter should have been killed, causing the mirrorwriter to be inactive now
92 - if mw.Active() {
93 - t.Fatal("should be inactive now")
94 - }
95 -}
96 -
97 -func TestStress(t *testing.T) {
98 - mw := NewMirrorWriter()
99 -
100 - nreaders := 20
101 -
102 - var readers []io.Reader
103 - for i := 0; i < nreaders; i++ {
104 - pr, pw := io.Pipe()
105 - mw.AddWriter(pw)
106 - readers = append(readers, pr)
107 - }
108 -
109 - hashout := make(chan []byte)
110 -
111 - numwriters := 20
112 - writesize := 1024
113 - writecount := 300
114 -
115 - f := func(r io.Reader) {
116 - h := fnv.New64a()
117 - sum, err := io.Copy(h, r)
118 - if err != nil {
119 - t.Fatal(err)
120 - }
121 -
122 - if sum != int64(numwriters*writesize*writecount) {
123 - t.Fatal("read wrong number of bytes")
124 - }
125 -
126 - hashout <- h.Sum(nil)
127 - }
128 -
129 - for _, r := range readers {
130 - go f(r)
131 - }
132 -
133 - work := sync.WaitGroup{}
134 - for i := 0; i < numwriters; i++ {
135 - work.Add(1)
136 - go func() {
137 - defer work.Done()
138 - r := randbo.New()
139 - buf := make([]byte, writesize)
140 - for j := 0; j < writecount; j++ {
141 - r.Read(buf)
142 - mw.Write(buf)
143 - time.Sleep(time.Millisecond * 5)
144 - }
145 - }()
146 - }
147 -
148 - work.Wait()
149 - mw.Close()
150 -
151 - check := make(map[string]bool)
152 - for i := 0; i < nreaders; i++ {
153 - h := <-hashout
154 - check[string(h)] = true
155 - }
156 -
157 - if len(check) > 1 {
158 - t.Fatal("writers received different data!")
159 - }
160 -}
vendor/QmdDfkqDWheE4gsCXNrhixwTwSHnZMPT2cGLcNbiBNcMyU/dir-index-html/.gxlastpubver deleted
-1
@@ -1 +0,0 @@
1 -QmeZ95gjQtxEbMbnttTiViadqjVb2JDZqQDsYQA4BBZpE4
\ No newline at end of file
vendor/QmdDfkqDWheE4gsCXNrhixwTwSHnZMPT2cGLcNbiBNcMyU/dir-index-html/README.md deleted
-6
@@ -1,6 +0,0 @@
1 -# dir-index-html
2 -
3 -directory listing html for go-ipfs gateways.
4 -
5 -![](http://gateway.ipfs.io/ipfs/Qmf82jUC9ZuoSTCNY55hyx3HmiDed3WnhFD5PC7CTSPmC2/cap.png)
6 -
vendor/QmdDfkqDWheE4gsCXNrhixwTwSHnZMPT2cGLcNbiBNcMyU/dir-index-html/dir-index-uncat.html deleted
-62
@@ -1,62 +0,0 @@
1 -<!DOCTYPE html>
2 -<html>
3 -<head>
4 - <meta charset="utf-8" />
5 - <!-- TODO: seed these - maybe like the starter ex or the webui? -->
6 - <link rel="stylesheet" href="/ipfs/QmXB7PLRWH6bCiwrGh2MrBBjNkLv3mY3JdYXCikYZSwLED/bootstrap.min.css"/>
7 - <!-- helper to construct this is here: https://github.com/cryptix/exp/blob/master/imgesToCSSData/convert.go -->
8 - <link rel="stylesheet" href="/ipfs/QmXB7PLRWH6bCiwrGh2MrBBjNkLv3mY3JdYXCikYZSwLED/icons.css">
9 - <style>
10 - .narrow {width: 0px;}
11 - .padding { margin: 100px;}
12 - #header {
13 - background: #000;
14 - }
15 - #logo {
16 - height: 25px;
17 - margin: 10px;
18 - }
19 - .ipfs-icon {
20 - width:16px;
21 - }
22 - </style>
23 - <title>{{ .Path }}</title>
24 -</head>
25 -<body>
26 - <div id="header" class="row">
27 - <div class="col-xs-2">
28 - <div id="logo" class="ipfs-logo">&nbsp;</div>
29 - </div>
30 - </div>
31 - <br/>
32 - <div class="col-xs-12">
33 - <div class="panel panel-default">
34 - <div class="panel-heading">
35 - <strong>Index of {{ .Path }}</strong>
36 - </div>
37 - <table class="table table-striped">
38 - <tr>
39 - <td class="narrow">
40 - <div class="ipfs-icon ipfs-_blank">&nbsp;</div>
41 - </td>
42 - <td class="padding">
43 - <a href="{{.BackLink}}">..</a>
44 - </td>
45 - <td></td>
46 - </tr>
47 - {{ range .Listing }}
48 - <tr>
49 - <td>
50 - <div class="ipfs-icon {{iconFromExt .Name}}">&nbsp;</div>
51 - </td>
52 - <td>
53 - <a href="{{ .Path }}">{{ .Name }}</a>
54 - </td>
55 - <td>{{ .Size }}</td>
56 - </tr>
57 - {{ end }}
58 - </table>
59 - </div>
60 - </div>
61 -</body>
62 -</html>
vendor/QmdDfkqDWheE4gsCXNrhixwTwSHnZMPT2cGLcNbiBNcMyU/dir-index-html/dir-index.html deleted
-60
@@ -1,60 +0,0 @@
1 -<!DOCTYPE html>
2 -<html>
3 -<head>
4 - <meta charset="utf-8" />
5 - <!-- helper to construct this is here: https://github.com/cryptix/exp/blob/master/imgesToCSSData/convert.go -->
6 - <style>
7 - html{font-family:sans-serif;-webkit-text-size-adjust:100%;-ms-text-size-adjust:100%}body{margin:0}a{background-color:transparent}a:active,a:hover{outline:0}strong{font-weight:700}button::-moz-focus-inner,input::-moz-focus-inner{padding:0;border:0}table{border-spacing:0;border-collapse:collapse}td{padding:0}/*! Source: https://github.com/h5bp/html5-boilerplate/blob/master/src/css/main.css */@media print{*,:after,:before{color:#000!important;text-shadow:none!important;background:0 0!important;-webkit-box-shadow:none!important;box-shadow:none!important}a,a:visited{text-decoration:underline}a[href]:after{content:" (" attr(href) ")"}tr{page-break-inside:avoid}.table{border-collapse:collapse!important}.table td{background-color:#fff!important}}@font-face{font-family:'Glyphicons Halflings';src:url(../fonts/glyphicons-halflings-regular.eot);src:url(../fonts/glyphicons-halflings-regular.eot?#iefix) format('embedded-opentype'),url(../fonts/glyphicons-halflings-regular.woff2) format('woff2'),url(../fonts/glyphicons-halflings-regular.woff) format('woff'),url(../fonts/glyphicons-halflings-regular.ttf) format('truetype'),url(../fonts/glyphicons-halflings-regular.svg#glyphicons_halflingsregular) format('svg')}*{-webkit-box-sizing:border-box;-moz-box-sizing:border-box;box-sizing:border-box}:after,:before{-webkit-box-sizing:border-box;-moz-box-sizing:border-box;box-sizing:border-box}html{font-size:10px;-webkit-tap-highlight-color:rgba(0,0,0,0)}body{font-family:"Helvetica Neue",Helvetica,Arial,sans-serif;font-size:14px;line-height:1.42857143;color:#333;background-color:#fff}a{color:#337ab7;text-decoration:none}a:focus,a:hover{color:#23527c;text-decoration:underline}a:focus{outline:thin dotted;outline:5px auto -webkit-focus-ring-color;outline-offset:-2px}.row{margin-right:-15px;margin-left:-15px}.col-xs-12,.col-xs-2{position:relative;min-height:1px;padding-right:15px;padding-left:15px}.col-xs-12,.col-xs-2{float:left}.col-xs-12{width:100%}.col-xs-2{width:16.66666667%}table{background-color:transparent}.table{width:100%;max-width:100%;margin-bottom:20px}.table>tbody>tr>td{padding:8px;line-height:1.42857143;vertical-align:top;border-top:1px solid #ddd}.table-striped>tbody>tr:nth-of-type(odd){background-color:#f9f9f9}.form-control::-moz-placeholder{color:#999;opacity:1}.form-control:-ms-input-placeholder{color:#999}.panel{margin-bottom:20px;background-color:#fff;border:1px solid transparent;border-radius:4px;-webkit-box-shadow:0 1px 1px rgba(0,0,0,.05);box-shadow:0 1px 1px rgba(0,0,0,.05)}.panel-heading{padding:10px 15px;border-bottom:1px solid transparent;border-top-left-radius:3px;border-top-right-radius:3px}.panel>.table{margin-bottom:0}.panel>.table:last-child{border-bottom-right-radius:3px;border-bottom-left-radius:3px}.panel>.table:last-child>tbody:last-child>tr:last-child{border-bottom-right-radius:3px;border-bottom-left-radius:3px}.panel>.table:last-child>tbody:last-child>tr:last-child td:first-child{border-bottom-left-radius:3px}.panel>.table:last-child>tbody:last-child>tr:last-child td:last-child{border-bottom-right-radius:3px}.panel>.table>tbody:first-child>tr:first-child td{border-top:0}.panel-default{border-color:#ddd}.panel-default>.panel-heading{color:#333;background-color:#f5f5f5;border-color:#ddd}.row:after,.row:before{display:table;content:" "}.row:after{clear:both}@-ms-viewport{width:device-width}.ipfs-_blank{background-image:url('data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAAWBJREFUeNqEUj1LxEAQnd1MVA4lyIEWx6UIKEGUExGsbC3tLfwJ/hT/g7VlCnubqxXBwg/Q4hQP/LhKL5nZuBsvuGfW5MGyuzM7jzdvVuR5DgYnZ+f99ai7Vt5t9K9unu4HLweI3qWYxI6PDosdy0fhcntxO44CcOBzPA7mfEyuHwf7ntQk4jcnywOxIlfxOCNYaLVgb6cXbkTdhJXq2SIlNMC0xIqhHczDbi8OVzpLSUa0WebRfmigLHqj1EcPZnwf7gbDIrYVRyEinurj6jTBHyI7pqVrFQqEbt6TEmZ9v1NRAJNC1xTYxIQh/MmRUlmFQE3qWOW1nqB2TWk1/3tgJV0waVvkFIEeZbHq4ElyKzAmEXOx6gnEVJuWBzmkRJBRPYGZBDsVaOlpSgVJE2yVaAe/0kx/3azBRO0VsbMFZE3CDSZKweZfYIVg+DZ6v7h9GDVOwZPw/PoxKu/fAgwALbDAXf7DdQkAAAAASUVORK5CYII=');background-repeat:no-repeat;background-size:contain}.ipfs-_page{background-image:url('data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAAmhJREFUeNpsUztv01AYPfdhOy/XTZ80VV1VoCqlA2zQqUgwMEErWBALv4GJDfEDmOEHsFTqVCTExAiiSI2QEKJKESVFFBWo04TESRzfy2c7LY/kLtf2d8+555zvM9NaI1ora5svby9OnbUEBxgDlIKiWjXQeLy19/X17sEtcPY2rtHS96/Hu0RvXXLz+cUzM87zShsI29DpHCYt4E6Box4IZzTnbDx7V74GjhOSfwgE0H2638K9h08A3iHGVbjTw7g6YmAyw/BgecHNGGJjvfQhIfmfIFDAXJpjuugi7djIFVI4P0plctgJQ0xnFe5eOO02OwEp2VkhSCnC8WOCdqgwnzFx4/IyppwRVN+XYXsecqZA1pB48ekAnw9/4GZx3L04N/GoTwEjX4cNH5vlPfjtAIYp8cWrQutxrC5Mod3VsXVTMFSqtaE+gl9dhaUxE2tXZiF7nYiiatJ3v5s8R/1yOCNLOuwjkELiTbmC9dJHpIaGASsDkoFQGJQwHWMcHWJYOmUj1OjvQotuytt5nHMLEGkCyx6QU384jwkUAd2sxJbS/QShZtg/8rHzzQOzSaFhxQrA6YgQMQHojCUlgnCAAvKFBoXXaHfArSCZDE0gyWJgFIKmvUFKO4MUNIk2a4+hODtDUVuJ/J732AKS6ZtImdTyAQQB3bZN8l9t75IFh0JMUdVKsohsUPqRgnka0tYgggYpCHkKGTsHI5NOMojB4iTICCepvX53AIEfQta1iUCmoTiBmdEri2RgddKFhuJoqb/af/yw/d3zTNM6UkaOfis62aUgddAbnz+rXuPY+Vnzjt9/CzAAbmLjCrfBiRgAAAAASUVORK5CYII=');background-repeat:no-repeat;background-size:contain}.ipfs-aac{background-image:url('data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAAnhJREFUeNp0Uk1PE0EYftruVlvAUkhVEPoBcsEoLRJBY01MPHjCs3cvogcT/4qJJN5NvHhoohcOnPw4YEGIkCh+oLGBKm3Z7nZ3dme2vjOhTcjiJJvZzPvOM8/HG2q325Dr3kLp7Y1ibpIxjs4KhQBZfvV6s7K5Vb0bjeof5ZlcGysP1a51mifODybvzE8mzCbrAoTDIThMoGXZiZ4YSiurf+Z1XeuCqJ7Oj+sK3jQcNAmg8xkGQ71mYejcAB49vpmeuzJccl0+dUj6KIAvfHCPg3N+uAv4vg9BOxcCmfEzuP/genpmeqhEMgude10Jwm+DuUIyUdTlqu2byoMfX/dRermBeExHsTiWNi3+lMpzRwDki8zxCIATmzbevfmClukiP5NFhJgwkjeRTeLShdOoVJqnAgwkgCAZ6+UdLC9twjQZ8pdzioFkZBHY3q6B3l4dJEEEPOCeD4cYVH7Xsf15F+FImC775INAJBJSkVoWo0QY9YqgiR4ZZzRaGBkdwK3bFxGLRZUfB3Rm2x4x9CGtsUxH9QYkKICDFuLxKAozGZwdTqBRs2FbLlXbiPdECMCHadj/AaDXZNFqedCIvnRcS4UpRo7+hC5zUmw8Ope9wUFinvpmZ7NKt2RTmB4hKZo6n8qP4Oq1HBkKlVYAQBrUlziB0XQSif4YmQhksgNIJk9iaLhPaV9b/Um+uJSCdzyDbGZQRSkvjo+n4JNxubGUSsCj+ZCpODYjkGMAND2k7exUsfhkCd+29yguB88Wl7FW/o6tT7/gcXqAgGv7hhx1LWBireHVn79YP6ChQ3njb/eFlfWqGqT3H3ZlGIhGI2i2UO/U/wkwAAmoalcxlNA1AAAAAElFTkSuQmCC');background-repeat:no-repeat;background-size:contain}.ipfs-ai{background-image:url('data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAAk5JREFUeNpsU01vElEUPTPzZqBAQaSFQiJYUmlKYhoTF41L3Tbu/Q/+AvsX3Bp/gPsuWLrqyqQ7TUxMtAvF1tYGoXwNw7wv7zwYgtKX3Lw379575p5z77O01ohW+/DVh8zj7aYKhflGdG9ZsGwLNydffgVfr19YHvsEa+Zu/nxndob5StQK+dyzvZzyw/gKlmMj7IygFM+xvNcanp4/t5dAomXHBy2UUBOO2MAl/B9/cPb6PULuoHx0WM0e3GvpUOxD3wZAJWutZqYUYmqpSg5OMgH3YQObL59W0/ullpryR3HegkKEqiWBSGV4R3vQ7sIhScTZFTpHx3A215B5sluVY/WWMg7+ATB/lcLsKpTonHzD+OMFEuTz8ikkt9Kwt9YJZB38cpBdoQAZJdLvCGByfoPB6Xdk90pYy6Xg3c/DaWwArg09DaG5lCsUFN0pckZAojdC8m4auBqaALuSgez7VB1RtDSUWOQvUaBLFUzJBMJ2DwmPgd1Jwm0WoSgJfjDvrTKxtwAIyEkAOQ5hU//Zdg5uowDlUNMnwZLW0sSuUuACYhwQRwFvJxupCjEYUUccOkoaKmdOlZnY1TkgAcXAhxhOwLsDsHoN3u4O5JTDfVCH6I9nfjId3gIgSUATFJk/hVevGtOMwS0XwQ3AzB/FrlKg8Q27I2javVoZrFgwD4qVipAEyMlnaFArzaj/D0DiMXlJAFQyK2r8fnMMRZp4lQ1MaSL5tU/1kqAkMCh2tYI+7+kh70cjPbr4bEZ51jZr8TJnB9PJXpz3V4ABAPOQVJn2Q60GAAAAAElFTkSuQmCC');background-repeat:no-repeat;background-size:contain}.ipfs-aiff{background-image:url('data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAAohJREFUeNpkU9tqE1EUXZmZpE3aTBLbJFPTtFURtSCthr7UCyKKFJ/9An3og6Ag/oXfoUj7og9asCBYKT6UIPHaWtpq7NU2aZK5z5wZ9xxMpMwZDuewz9prr32ZiO/7CNaDx3OLt6fOjBqGg/aKRCIInp8+KzfKH7fudnVF58nE16el+/yU2mBFSWZKpWJKVc0OgUBo02K4NDmU6o75Mx+Wdu9IUXFeiOA/pn1xHeYaugVDdzpbp91qGlAKGTx8dC19/Wpxhjnsxj/RRwk85hGJC9d1O6fneWAuoztDYSSLe9OT6SuXB2ccx73Z9uukwDwfls1g0xZIY/Ad/Gnyt/XVfbyYrSDRE8PExHB6/8B6QuaxIwRBFMt0iIAiMx+LCys8jfGJEUik2WpZOD2SQf9oDtVqQwopCAiY66FS/om3b75CVS2MlU7AJ2WiJBCZjZ2dJuRkDJZFwFAR7UCBja3fNfxY2YEoCtRCj9em3Tpds6FpJseGCBxS0GgYGBzqw62p84gnYnAI2CSbSbPhEpFAaE2zODaUAlWWwDoS5DheGqbWpVE/0CmqCY9qkEyINBceb2uADRNQ8bSWAVVzIFKomCQim+0luS4yKYlsHlRyZo7EsSEC23K5vAsXh/H92zZkuRvxeBS5nEx2yp2KqhxPoV5TYS/8CtdApylM9sZQKKSQzyeRTseRV2QoAzIYY8jme5DN9fI0dQoUIjANGydP9VM7PZw9p/AiBpNYrdbw/t0yTJqRtdU9UrfJCUMpSJIgbWzsYe51BcViHzLHeqCRqhZ1YX1tFwNfZBxS9O3NWkAcHqR606k/n/3coKAoV/Y7vQ/OYCZevlrmv3c0GsFh06u3/f4KMABvSWfDHmbK2gAAAABJRU5ErkJggg==');background-repeat:no-repeat;background-size:contain}.ipfs-avi{background-image:url('data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAAm1JREFUeNpsU8tu00AUPXZcN0nzTpq2KQ3pAwkIAnWHqCoeexBb+AQ+ABZ8A2s+AIkdm266QUJIFWKBkHg1KpRHi5omJGkbJ3bGHj+4M1EQrTvSyGPPueeec++1EgQBxHp+/9mbyuriRZdxjJaiKBD3W+u1+p9a856max+gDO8ebT+WT20Ezi9NZi/crqadvn2MQBAGfpCOpqNru2937vxPIpY6Onjccx3Twck9MBiSU0ncfHirXFmZX3Md9wqCUwiEVN/zaQfHt0vfbBe5uQyuPVgpl5Zn11ybL4/i/lkICOw5niQRGQShoiqI6Bo43W2ub8n3hRtLZT7gTynk6gkCX9gAOxpAnxhHZDwC1/aI1EViJolu/QhKRMHZ1UX0Gr1USIEn5FPWHy+/wTokkrQOq2vBaHZBN4hmY9Jwfr4An/teiEB45ZZDwDiMhoExT0N+sYDCuUkkplLIlXP4/XEXdo+RUhdhBSSfUwtVTUG8MIHK9QVqI7D/uY6vr2pwmCPrkz+Tk9gwARWQ9WxppbXZhNnpw+ya4A5HZi6L4lIR8WyCcL6sTZiAWjWgAmpxkn5+kqTamK6WkCwmERmLDLvjB0ML9ikWXPLFuozYOap3L8HYN6DHdbS/d5CeTVBndBz87FCBLYkNTyIjBQemnIEsSY5lYrK1+UoWcToLMjEHAyIQ2BCBSx/NVh+ZUhrqmEqBebS3WyhdLg0zt/ugAaIklsSGLHCLa6zDMGhZ2HjyGsnpFPqNHnY2fmHv3R5SMymYbROszSQ2ROAY9qHiofvlxSc5xsKKqqnY3diRE9h4X5d/pzg7lnM4ivsrwADe9Wg/CQJgFAAAAABJRU5ErkJggg==');background-repeat:no-repeat;background-size:contain}.ipfs-bmp{background-image:url('data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAAmZJREFUeNp0U+1rUlEY/13v9YV0vq2wttI5CdpL9aEGBZUDv0df668I6n+or0UQ/RuuD0EgVDAZrsKF4AR1a6COKW5qXvXec27PuVeda3bgcF6e8/ye5/d7niMZhgExnK9fbTrm5pbBGMZDkgCyq+VyhTUaT6Eo2ZHJePPWXJXRhez3B1yxmM/QdctXUSCgtV4Py4CvY3cky4e1x5DlLCaGbbzjXDcousG5OQe5HPRSCQPK4PpsEM/XH4WvhS4noeu3JwHGGRiULhsMoKZS4I0GtEIB9mgULJGA0+9DPBpBT7sffvf1W/Lg6OgJufw8C0CRGEXWazUwiiyFQjA8bsjVKjaJzovMD/Q5gxyJhG2cvyeXe2cAuADQNGBmBvLaGuTFRaDfh31lBTWi9pumjbK0B4JQul3vOQpM8JdskOLrdCvDcDjAsjtg5TIkoiKLaokMNR2cnZbqNAMycqG7XbHKR2fMzwO/dsxSwu0BiBJsNsv2LwAJAJCI5ux2gXYbqNetcz5PoORI1cDS0n8AxGW7A+zvEYBKZ2ZlcsEtJLbedMjePBaCTQMghx45ulyWkzxMVUQ2RMQhLfFO16YAqCrixPnm6iqKrRb2W23EfF4cUNSrHg90cr7hDyB33MTnSmUKALVs4uIlROjxg+AsPhGVl3fuIl2tIOB0Ya91gkOi9mxhAal0ekork1ic/kGLBORMxy2K1qS9V1ZQbNThIj2EGh+2tsyOnSai8r1UxMNIBB+LRTTULr4Uds0K1tU/uOLxIrmbNz8XXSrnASSpubG9fbKRyVh1n/zSw29t9oC1b47MfwUYAAUsLiWr4QUJAAAAAElFTkSuQmCC');background-repeat:no-repeat;background-size:contain}.ipfs-c{background-image:url('data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAAcxJREFUeNqEUk1rE0EYfmZnkgoJCaGNCehuJTalhJZSUZB66a0HwXsP/Qn+FM+9+hty0LNYCr2I7UVLIW0Fc0hpQpSS7O7MrO9MspuvVV8YMnk/nn2e5x0WRRFMvP/w6WSz5jbi/9NxfP693Wp3DrJCnMW5d28P7a+IE15lufR8o1ZEStwPhkWHsWbrZ+eNEPxsuubEF6m0TBv2Q4liPofXuzveulttSqW2UwH+GjqC0horpSL2njU89+FyMwjlTlxOJMTa9ZQHzDQIjgwdom9zLzfXPc75kbnOAswBJTlC2XrqQRMLxhi442DgB4UFBhgPpm3B5pgBHNUUxQKAHs8pHf3TEuFMetM9IKr/i2mWMwC0SnuSFTG2YKyppwKYVdGO7TFhzBqGIenVeLCUtfURgErucx5ECKREKBU4d3B718PHz6cICGT/1Qs8qpQtGOdyhtGEARWDQFqQJSeDL98u4VbLaKw9IRAJPwjtoJGlVAoDQ800+fRFTTYXcjlcXN2g++s36p5Lzzlve1iEROa8BGH1EbrSAeqrjxEqicHQt8/YSDHMpaNs7wJAp9vvfb287idboAVkRAa5fBYXP9rxO4Mgf0xvPPdHgAEA8OoGd40i1j0AAAAASUVORK5CYII=');background-repeat:no-repeat;background-size:contain}.ipfs-cpp{background-image:url('data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAAfJJREFUeNqEUs9PE0EU/mZ2WgqpXX+QIDFdalVslh8NlAOQaOKFAwfvHvwT/FM8e/U/MOnBmwcj8WD0ACEGghIkbU0baaEthe3OTJ0ZWV26q37JZt68ee/b9733yGAwgMbL12/fz+azbnAPY2Nrt7Zfqz9JMrYZ+J4/e2pOFjiciRvXlgp5GzHonXk2o6S8V6k/TjBrM/xGA4MLyeOSPZ8jkx7D+uqCU3Amy1yIYizB36AlCSkwfjWDR4uu40yMl/s+XwjeWThQQ4Z6QNSnSkYykcDXasP4lmfvOZTSF9q8TDBEFPbN5bOqCglCCCxK0TvvZyIV4CIxbgpC+4gm/PUmFCIE8iJPyME/e8Lon9j4HvyHYLjKSwRCSEUgf9+15mFbx8QS6CZJMzJ9SlBCwX3fJDLG4PX7ykcwkmQmJtpEhWa7g1dvNlSwjwelebz7tAXLolh0p/Fxe9fErK2WDFGEgKjxfNjegX0lDTc/heNuF99/HGEslcKXwyoazWNDdlCr6+DoJgrBzdI0T9rYO6yg2zszMlaKM3Dv5OBzbuyZuzm1B16U4Nzz2f3cFOx0Gq12F9cztpExncsqYoaHpSIKtx0zJdVIFpHQ6py29muNk1uTN829o/6SHEnh80HFaE6NjmLnWxUJy1LyTltB3k8BBgBeEeQTiWRskAAAAABJRU5ErkJggg==');background-repeat:no-repeat;background-size:contain}.ipfs-css{background-image:url('data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAAk1JREFUeNpsUktvUlEQ/u5DoCLl/RAKKKUvWmIxjYntQtcu3LvwJ/hTXLt16coFC2PsojEaMKZtCqFaTdGmjbS0CG3By+vei3OOBSGXSU7uzNyZ78z3zRF6vR6YvXzzPrMUCyf68bB9zO+VfpROn5hkOdfPPX/2lH/lfiLidztX5mN2jLGG0rKLENIE8liWpdzwP7HvqJqujmvudFU4bFY8Wk1FZsOBtKppd8YCDNu77CZevd3gflfTUFcUhP0ePLibiIR9rjSBpgwAfe4dVcV6dhtep4PH5msylGYLrzeybErcT85FYiH/CyPAf74gObC2vMhzsiRhPhpC6eQUM+EA1pJzILEnjRSuJsju7MJqsUCSRei6Dp3yXqcdGlHZ/rLPazQWGCn8+6YW4pAkEW0SjzUzanWlCa/LgcR0lNfovTEi6lcIkzesnM/R8RlN0INGp3h4DHoDsE5YRvQyiKiRSMzikRAOS2WoqoZWu41K7RwzlOOAVDMMMHhIGvFlRxJFrKYW0ep0IYgC3SDh4b1lTJjNfENsrazOAMAw680mPuW+8lFno1P4XDigRhOiwQAyJK7TbsNS/PaA7giAIAhYz2yRgBIfsVA8wIetPG6FAqhdNrC5u0f+TUyHgyMTDDToEt/ftQsEvW4EPG5OZcrvw0mlimarTXkPfpXPcNlQoGtjACgpryQXsPNtH/nvRXqBJpoKHMzGNkNB0Odls7LNyAYKpUq1dt1iuvB7fRDp9kr9D1xOFwkpoksXusmXaZWFn0coV89r/b6/AgwAkUENaQaRxswAAAAASUVORK5CYII=');background-repeat:no-repeat;background-size:contain}.ipfs-dat{background-image:url('data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAAfVJREFUeNqMU01PE1EUPe/Na0uptmlASg3MoiZgCA3hQ8PHAjbqwsS9C3+CP8W1W/+BSReyYUPwI4QAVkAgUEgIbVIg1FZb2pl5b3zv2cHBjsaTTOa+e989OffcGeK6LhTevFv+OJoZHPHOfrz/sl86KpWfhxnLe7lXL1/oN/MSZqonOXU/k0AA6lfNhEFIrlAsP2PMyPtr1AscLpyg5pbtIHErhqez4+awmc45nI8FEvwNaiQuBHqTcSxMjJhmX0/Osp1xr878FxWEzwMinxAzEA4xFIpnOjedHTKpYbxW4U2CP4j8uWxmUKsghMCgFI2mFe9QgHZj0Ba4yhFF+KvGJToIRLuPC/efnjD6+26wB1Lq/xgbSCBXKeWJG/OTdky8cWTdT3C9RmWSGk2XCLlWo4xTNbfN5qh7PpXM72GjZeHt0gpq9QbmH4whGb+NpU/reDQ7hcWVVXxvXOHxzCQopQEKXKEbL6o1ZIcy+LC5g62DY2zsHeC0fA4zndIrHOjvg2XbAQRSfsuy9XxC2qzi/H5B6/68W0AsGkW0KyJPBLbDO0fg3JX/CUM81i0bD6WKe6j9qOPJ3EMcF0tSNsFA6g6alqW+VtZBUL78Vtk+Oqne7U9rs5qOQCjSheJFBeFIFOfVujSUYu3rIc4uqxWv76cAAwCwbvRb3SgYxQAAAABJRU5ErkJggg==');background-repeat:no-repeat;background-size:contain}.ipfs-dmg{background-image:url('data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAAn9JREFUeNpsU01rE1EUPe9lkk47yWTStCmtNhFSWxos2EXVhSsRcasuxYV05V8Qf4DgD/AvCK5EV1oFI7iUBqmCNdDvppq2mWSSzEzy3vPOpFFq+uDNfR/3nnvueXeYUgrBWH1/9/NE7k5BKRnuRcfF2qdnmJq9DeF9tQ+2isuMsxXGWHh/a1mEVsPJSI5fSU3OPEj291IIlN49RXz0KqzEQjIeZS/L5Y/3wPGhDxIM/i/A7fZWgVG0t5EaG0ZUa0JGM8gvPrZmLt58QYwv91mfAqCIE0sAqgumBFITGQzpUYhuF0KfRa7waDyXXXolpVrsh/0tgSLDr5I+wUZo1UHCSkAficPzY6juFSmbRPrC/azjq+fkcO00gAqoU7B0ETKkfWbuCTjTYeq5oESAauexcTScX+ZACWFm0YQSLZKhHdr67+/wW0e0dgjYo3sCEXXybYtBDVSHLp2es3IpsILS24c42lkBg6DzRjgRzCDZ/xr0GNRJwwYiWgzt+hYMawleu0V3wbkT+kUirOc7IGJAz68R/Qak1BAlx3hqASPGBJRXpXOv58dkz3eAgQoOm4hyj57NgZm0MHvpBmK6QdUdg/DAg9cRkhicBSDaKJdeo1bdxmR2DtWDDUxl51HZ+QHTysD3XdQO95Gfv06aeGcAdBrY3Chi8lwO3768QWX7J5q1XWyVSxgajiOXLyBG2hzurRKV9lmt7ISNkkjo6HhNyjoK+2gXRsKE57ZIE2ot10Z1fz0Ue4ABVw3NMjnW14rInh8jTYywoTg3EOFpOM4mXNfH9PQUfGlrAwBOs3I8ljbtuMWhRWzIIPrkn+GcYcgIWEowbZ+0qB334/4IMADESjqbnHbH0gAAAABJRU5ErkJggg==');background-repeat:no-repeat;background-size:contain}.ipfs-doc{background-image:url('data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAAppJREFUeNpsU79PFEEU/mZ39vZu77g7DokcP04BBSUmiEKCSCxs7Ei00JAYO2NlTKyMrX+CJhaGwopSQ0dMtFEsbDRBgiZEQIF4IHcg+2t2Z8eZ5QDlnM1mZ9+8973vfe8NEUJArfSNhzPG0VIfeIiDRSDkw1cWVt3N8rhG6SdSO2Gvn8dfuueqZwuNZqk3Jxg7iNcIfBbgXD6ZC8u5qffzX8eoYeyDxC77uygKhcouovgVUQj1H4YB2ovNuD9+tTTU0zMVBmG/+C8AIYh8F361DL/yE5HnADKYlVdg6MDAmW7cuz5WGuw+PsWDYGAvbL8ECFUt4K7/AHd/I9c7BLaxinD2Ld5Zo7g78RLuRhlBS2cpWbGfStfhfwCEpK0nUjCbWuGsLciSOELPhkq/YgdY3l6HsLfRcLYf+pHNbH0JigEPkLAyMsiEJ7NrqQzM1i7wyhoMZqOhvQs6Z0ovXgdAJACRoulEg5HOwrOroKk0zOY2BDtVpTF0CU6kLkQJXa+BNEoG0lMSsBBKQXWNQktmoGcaYeSaQCIVWOvUYQAiWZFQtk5mSMoSzEILtBrTfEcviC5bwVwQmoh96wA0ic5dB57ngeoaTIPCdb34zDITYNLOOIeVSsW+dQC+7+NSWx6jJ4tY/rWNV7PfcGv0tBoPTM7M4eKJVgx2FTE9u4QPS6x+kHzfw/mOAjarW2hJG3hy8zIceweuY+PRtREMdzbjzcd5WBqPB6xeRGUMGRzHjWvMmxQ7tiOF1JBN6FiTd6Sy9RuFbHpX7MMMqOD088Ii+op5OUAO7jyeRGfBwrF8Cg8mXuDL4neMXzgFwhwZz+hf7a9d5yu3Z6DTPjVQIY9k7erO7Y63Lvc8ErEeyq6JaM6efjai4v4IMABI0DEPqPKkigAAAABJRU5ErkJggg==');background-repeat:no-repeat;background-size:contain}.ipfs-dotx{background-image:url('data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAAndJREFUeNpsU01rE1EUPTPzJk0y+WhMStW2qdVWxUVEQUF0I+4ELQiC7lz4N9z0T+hG9wrdZKUgLqulhrbSag1CKpT0g7RpYjqZmffle5NEKdMHlzfvvXvPPffcO4aUEno9f3Vt4dTp+BXOe+fB0u/NbVpv7h89NU1j1TCM8H7+xY9wJwPHZMbOjRadLAvE/2gToJTiTPx89k+OlVd/LT+0TPIPpO/SzyQk40xCMxBSZ9Z3CoAx5DOjeHT7SbE0XSpzwa8OWB9jINELolQg8AR0EgUKn1PIlIWpkUt4cPNxkTOU12trs8p95RiAXpqaztqou8q6SKQJJmZSqGwsodFsIJk1kcyLYv7IeafcLx4HUNkFF4jFTExMZ0B9DrfD4HUEusYhWs4GPEJg5wly/tBYRIOeDhpEwlS34xcyajdQr3UwOT2MlJOEBRuGNHWp9AQRVXDfQiFV/U5GBSiQ5p6ngBEa5z3fiIhC6g6IMDBwOdoHPkYnHPVyhN0tF7E4QSpr94CEOKELffq+y9Bq+DCJ7rWBoQQBVbPR2O6G4OlsLASJMtCZfQqm0NP5IVWnamdAkUxbyuIYtD7wWegb0YAzAVMkkI6NwPM9xEwHloyDGAmk7AKS9rAS0FKOdugbYeAHPu7OPEM+MY7q3hIKqTFQHmC3XcONc/fxdfMDrk/ew/edzyhvvTmBAddocVRqH3Frahau56qpZDho7+PnTgXffi/gbHYmLEvPSIQBp5JU62sYz13G609zKBXvoOMdYn2zgm7Xg2MVML/4Eu3uPgxhk2gXmNl8v/i2pcXTP8tKdTEcbWLZqDQXwu/l6pfwbEnSGsT9FWAA4mdHv2/9YJ4AAAAASUVORK5CYII=');background-repeat:no-repeat;background-size:contain}.ipfs-dwg{background-image:url('data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAAoFJREFUeNpsU0tPE2EUPfOg006hD4rQh8WgbCSwkKgbF2owujaCiQsXxpX+D6MmbtXEsHCLmIAbE6NLo8YlGIxREIshIqVl+mQ6j8/zFVCb4UtuZua795577rl3FCEE5Bl79vPd5LHYiOP7cH1AUWi85ytmvlas1bJ9E5ryBntH3BpuP/X9i7ovkluuiE8N9SDepaLpCcRCCqa/VDCaMuIjSWP25Upl6n+QDoCz6Yh7KKzh3sI2LuUimPtRRyaqodj0MDloYiITSTi+mH29Wu0AUf9CsZPJoW5czJl48LmCc5kIKo5Al67B9gUGYxrun+5NnMlFZ+GKiQADj2a7AquseLIvjMv5KMaSBu4sWVir+3i8VIVKYSby0UTdFU8Znu8AYBHQgVOJEN5uOXi4UsdawwU0FSf6TaSoyw6DRvukPkgGWpDKy4F8a3jImCrqFDFn6rhKPR4VGnhvOTAY3WLcjifcQAsqRfhUc/Gq1MKNbBh9nIAMDjEppocxs9HCMktfGTCwP/oOBkUKNk/qF3pDYC6Ktk8RfWzyaaoKrqdDaBDwya8W1m0/CPCR3kFy7CcnmWQRUJqcRJFUKtTnPCeR71LwoeYF92CYyVnCFZpCTrRtCv5to2St8SOrKxiPqEEA4fkYT+mI0rdoeUiH1XZVuQPpsIKqw2QmfifTsnOABiWySlH9uU0Hh2MqjsZV5LtpPSoGeN9rKnhBX7ehoOSLIIPfnGONXGMMWN7xUfVldYDbjM3mrh5HCDgS17DhHgDQcIU+XbBxnDTn1x1UuQcJ9iv7l5Q5e1zLGri92EDJFnoAgHtcfr6wbbVXUqq193+0z97n3UJt1+d51n7aHwEGAAHXJoAuZNlzAAAAAElFTkSuQmCC');background-repeat:no-repeat;background-size:contain}.ipfs-dxf{background-image:url('data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAAo5JREFUeNpsU0trE1EYPfNMmtdoH2kDNmJbaVFcaBVFpAsREQpFwY0bu3HjQnTj1mVd+ANcuC3qQixmry6E0kWFVIQ+bKy2tbFJm3emyXTujGca+4DkwsedfLnn3POd77uS67rw1vC79ek7fZEzpu3AYUqS9tKQGZPLpa3VXP0uFCmJ/8t9OLC3q/uJbcs5bkIybvdHoMsSbLKENRmvU2WcNnTjRFD7ML1WGSPJHI6sA4KRWMAWVDPxLYex3iCmfpuIh1QsFSyMxQO4GvXHHwOJ6XWSyIck8v6HQsnjAxFc7vTj2VwBg4aG78VdBHQFCk+dbVcxMdwev9gTSEC455sIBOu2KLsoJFzqasP9vjCeDBlYqzn4VXXwarGKZN7Crd5QfLDT/7KpBM84c9fFUFjFp2wdk6smflRsKKqMa7EgfJJ3Ac2OKlit2pEmBTQfngdpnupoU7BUtRGiiTe7fXiRqmK+KuDn6TpvYogmBRJcrOwIJLIWxmM+dOsyLKryQAaJpjJ1/AxrGO3SqdZt7kKZJrzJWBg5piHENuY8vV6e0UOye1TyftvC5l+gZB8SHJTwpSx4q4JeTUKaxhXoR57h7Rn+3iFolJ3xvPhab6HgJG/pJ7jsNP4sUX+jZiCgEsWd/DjH5IrSYpBUAr0yHpzSoXKOP25a6OBhndh0zcX1qIYM2RIbu6i0KiHD5B/GTMHG03kTGpEL7H80wHFOWwhqDZ+SpkBOtCDYJDhZE4gRcKNbYynAqbCMbXpwpVPFbEng0aKJGbYzK1p4wIegLlcEPmdt+DjXbzcsxFlCynRwwVAwW6hjqeg0Zt521SYCWCJvbe0Un29UDx7Hgrs3IEitHXkw3jOv2fl92D8BBgAJeyqBh90ENQAAAABJRU5ErkJggg==');background-repeat:no-repeat;background-size:contain}.ipfs-eps{background-image:url('data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAAmlJREFUeNp0U01vElEUPfMFCEVArdoSqEA0KV246UJdUJM2Lo2JK/9FjXu3utJqTNz4D9worrsQExbFpAFT0TYp0CZ8pIAiyMfMvBnvm2Foa9uX3Lw7c98979x77hNM0wRf7ufPsq7Z2SQYw2QJAkDxQalUZa3WI8hy3gmZr15bu+z8kILBkCeRCJi6bufKMji0NhwiCQR6iitdatTvQ5LyOLLEiWcYukm3m4Zhmbq1BX13FyoxuH7xAlbvpqKRK1fT0PWbRwEmDEyiy1QVg/V1GO02tO1tKLEY2PIy3KEAlmJRDLXb0TeZL+n9g4MHlLJ5HIBuYnSzXq+DlcsQLk/D9Hoh1WrIUjlPcpsYGQzS3LWoaBhvKeXWMQCDA1D9pt8PaXERUjwOjEZQFhZQp9L2yERiqYRCkPt/z58ogTGqHQLE1BLgUmC6XGD5AlipBIFKkbhanKHGYLBDqQ4ZED0OAbfLlo8OIxwGvhVgyTHlA3xkomjH/gegBgDURMv6faDbBZpN+/tHkUApkdTA/PwZAPxntwdUyjYA/+ZMqJHjLgM9iv/6zRt2GgMaIE21aVIjnSm0DGPfmhzyde0UAE2Dj+p7urKCPvkZku9eJILOSMUnkvVhIo7GYIB3xSKYdhoA1erXGVKXpvFxZwdBonnD68PQ7YEwM4O4xwMPxc8RYE87g4FIcz+kvfmnA0YzIJIy77/m0OCqsTkkCTysKPjJG3viLei63Gm3kCO6UWqcMejjxecMPmxsoFKtYop6UNirYL9Wtc5OHqzznIXHq1na7OfMJROcK8a6O7MjW7nfzZdrd7jzT4ABACh3NGsh3GcdAAAAAElFTkSuQmCC');background-repeat:no-repeat;background-size:contain}.ipfs-exe{background-image:url('data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAAo1JREFUeNp0k8tPE1EUxr+ZzvRJO62lUAQaKIQ0FVJFjBBdoIkrDDHuXJi4NnHtX+HCjW408Q/QmHTRaCRRohIJifgiiBICTQu29mHfnc7MHc+MlECKdxZz595zf+c737nD6boOYzxJLC6Nhwej7e/24HkO779s7G6mMjcEwfKZ21+/d+em+RbagaFev28qEpZwzKg3ZckqCPH1nfS8hScIdyhBe6JqTG3PfyTTeLrwFhvbKdy9/xi5QglXL0yGJsKDccZY7LDIAwWHpSferWBh+RN8ni4UylVER8MY6PHj0uSpUK0hxzfTmWsUtnoEwO3rer64jEyxim6/Hy67DXaHExvJX3jw7CX8XjfORUdDlOohhU4fAVjILCPbm9V1yIqK2FgYt+ZmsZcv4lH8Nb5upXD7+hVMjIRQa8qeDg8UTYPU5cTcxSk4nS709XTD53ZhpD+IYMAPj+TBz93fZiz5oHV4AP1fGdlyHZIkIZkrI7GyhnK9CZXy+Aig6p1+HQAY003AcF8AVtGGfLWG9XTO4MLZ5cL0WAixoT4zVmPHADSiMo3hzHA/xgeDWFjbNg8H3A7kKnX0koEcPdTu/ylgRGZgOjNv38zoSXC8BZJDRKOlwGEV0VJVGM0y4joAPO1spXbx6sNHeD1uRIYGUCxVSRlDt1fC8rfvcDnsmJ+dOaLgoAs6AVLZPJJ7WdhEkUyT8GJpBflSBcVKDTvpDBw2GzQqQT1OgaZqUOhtFQUTUKnVTVWNpgy51YLVKph7sqKYkA4A1ScEfT66vm5kC3+ofh6Xz59FQ5bpkvE4QW3M5Apoyorhl9ABIKnFgNdTOh2NkJG6WSf9eRBJtmFwLDJmriUzeaOkYvvcXwEGAIVNH6cDA1DkAAAAAElFTkSuQmCC');background-repeat:no-repeat;background-size:contain}.ipfs-flv{background-image:url('data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAAmtJREFUeNpsUl1PE0EUPbssLYUCXdpaC9gWoSTgAyFigiRGY+KjvuuTr/4A44MP/gx/gMYfwIsan0RjIjGiJIZgSIGFIoXSD0t3Z3dnd70zpITazuZmJzP3nnvumaMEQQCx3jx69SV3a3KWMxetpSgKxP3m242Do43SQy2k/YRydvds67n8a63k+FRSn7l/bdg5tdsAuM3he/5weDC8vLdqPLgIIpba2niux52mg//DqlsYSg3iztO7mczN3DJ3+ByCLgCBH4hOFEF7cDpzPCRyOpaeLGXSc2PL3HbnW3XaRQCPEgWI2MsRVAVqrwbX9bHxbhOKpiJ/bzpDOr2k68V2BtRNzMtqDEqPejY/4zSGjb54BM0mQ8k4xsDoIMauXxnqYOD7PmwScP31d0SS/eAuh1lrolFpIBQNQw2pqJdqsAlIceB1AJCIkkE/FZskXDQVRXw6IYHiE0nBEcaPXSSvJnGwWkQXAE4acAhbxPMJpOdHweoMhc9b2F8zwKizbdlyPLVH7QLg+JKBYzoorxzjz3oRzUoToaEw9KyO8XQW5AE5jrFT6AbAYVVNxCZ0Ka3So+DSTAoDiej5ywTySbls1OEDobhFlMcXxrHw+AbINEjNXgb7y6BndLhk8cRkHHbD7g4gEhiJFxsdhrDqaamBaDKKerGGSKwPI9kR9EZCaNA5ubE7A5s8IFhsrxQkgJhZoa/06xC5xRz2v+3BOjFlbqcGlquxsondT9vY+2pAJdeZR6fI355CgQCN2A4O1w7gkQ7cdLUOAKdhV6uFSv3kd/n8mT68eC8dKWLnY4FsfeZQh7nVVt0/AQYAsf5g+SvepeQAAAAASUVORK5CYII=');background-repeat:no-repeat;background-size:contain}.ipfs-gif{background-image:url('data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAAmVJREFUeNp0U0tPE1EU/trplAqlL0laiw40xASByEJIZFGVnSvj1j+gWxNXJq7VrbrwF7h10cSNhMRHojEuACVBKmH6SJQyJeXRxzzv9dyZPiCtN5lMe8853znf953xcc4hztDzZ1+C6fQMHAfd4/MBFG+p6h/n4OAeAoGNToi/eOm+A50LKRaLh6amoty2vVpZdotNXccMEK3LwZxa2bsDSdrAqePv/mLM5tSdMwYBYqyvw9zdhUn/L59P4OGtG8qlZCoH254/DdCdQBCxqZu+ugqnWoW9swN5ehp2NotgIo6bGQWGtaS8+vQ5V9a0u5S+1gfABEilAqdUgm98HDwUQkDT8JXoPPq+BoM5kCYmFT9jryn1+hkAt7heBx8dhbSwACmTAUwTgdlZ/CVKJaLnI1GD8TikZiPSR8Gxib8chH95mZTxgwWHwH7+gFMswqcokIRbjMO2HDCnZ1VvArpjEmnKZc8+cZJJYGsLsMiZ8AgwEqaY6Mb6RQR33JFhGECzCRyfAFXNu9v+RVNRZWIMuDJNuYMAaDycUFGhCOgtuAtFVDA83G5A8TrFDw+F5QMAxAKJJxz2xnW3RPJGbm+rCyjotZetH4DGzaSSeDA3h4Zl4R0JOEZWTpIzF4n/m995bNdqZwB6m0gFft3Ak6vz+KYWwFsGlqIxXItEcDt1ARMEtKdVgZb+fwA0G2C2hXM0ZTZNRcSf0b1pmXi7uYnjI+Lfanm5fRQsK8BIxKcrK7i/uIgP+Tw+FlREqHN5fx/vyU4uHBE6UO4gDWqk/JFaLuMxcXeFk6TuJ90V0HOk1in7J8AAjmgkPfjU+isAAAAASUVORK5CYII=');background-repeat:no-repeat;background-size:contain}.ipfs-h{background-image:url('data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAAbRJREFUeNqMUk1Lw0AQnf0woK0ttVqp0hwqVCl+UBERT94F7x78Cf4Uz179DT14F8WbYHtRkBYRLNqDtdaPZLObuLs1NGlXcWDJZGbey+x7QUEQgIqT07PL5WKhHL5H46J+22q22vsWpbWwdnR4oJ80LNiz2czGUjENhvj4ctIE4Wrj8XmPUlKL9nCYcOFzE9j1OKSTCdjdrtiLdr7KhVgzEvwW6krC92E6k4Kd9bJt57JV5vFK2KfRQRV+RAMkzxglYI1RaDy2dW1rpWRjQo5VGicYIorWVooFvQVCCAjG8Omw1MgG8AM0uSBUDSnCfk/IGCHwf3DCD/7UhOLBrFkDuep/hDUSSCv1iYo4rIfqGwmUSNJjfYbBcQKhZw0aBMA4B48LwBhBt/cON80HmM9NQ6fXg/Wlku4TwmNWDzaQqzHG+0PSKod5cH5Vh2RiAhYKc8DlV1UPSyuFMGygVlMg1/P6BC6DqXQK8jNZDXAYA1f21V34wMXYFaiyVw0rJyzLgs3VMkxOjGtix/V0XWChZ0cI2i/dzvXdfTd0Qf91BMPrhyNzgKfOmxaWypqaDXHfAgwAtCL8XOfF47gAAAAASUVORK5CYII=');background-repeat:no-repeat;background-size:contain}.ipfs-hpp{background-image:url('data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAAehJREFUeNqEUk1v00AUHK/XKf1yZdESVRBXjRSRFqMQVBA5Ic5I3DnwE/gpnLnyG3LgXglx4UDDLZS0RWkDLiRxSusk9u6GXSembmLgWZbX7+2bnZl92mg0goo3b3ffO/ncdvyfjHef6q2Dlvs8Q2ktzr16+SL60jhhZ69bO8X8ClLC7w9XdKJVG8fuM0r1WrJG4gXjgqU1D0MGc2kBTytl+7a9XmWcl1IB/hZKEhccq5aJJ/e3bTu7Wg1CVo7rNLlRhUh4oMnXoDoyhoHGyWmUe+QUbELIa7W8CjAFlMzdzeckCwFN06ATAn8QmDMMMGlMuwWucpoCHNe4jBkAMenjYvRPTyi53JvuwX8AplleAeBcRFrH6rXIxLim9I/pi3QA1RhKaYxdjkN8IwalCMIwWs9ljMkh0wzk+9M7w179C3LZNXxve2h+c3Hu91HeKmD/6zHOLnw83ilB1/V0CeqU3Q81LC/O41b2Btx2N2JVP2riR8eTUxmi0TzBwrKZMsqMoz8MsDh/DWuWhUBKURLKxQIeOMWoptYPnS1c+INZBkwISomOSsmBZS7B+3WOzZvrKGzkMAiGqNy7g+LmRkRfekBnANy2163PZXrSbrQ6vch19Xz8fPDHyL39QzkHBKedXjfu+y3AAGU37INBJto1AAAAAElFTkSuQmCC');background-repeat:no-repeat;background-size:contain}.ipfs-html{background-image:url('data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAAmBJREFUeNqEUktPE1EU/mY605a+hhZTBNKRDApNrWIRA4nEBUZdmCgLNi4MK5f+FNdu3bFv1J1EXODCR1JJSMTwpqUP6NiCpe10Zjz3hj5Mm3iSybl37jnf+c53jmDbNpi9eb+6Ftcisea909bWNzNb6dwzSXKkhIt/r14+515qBqmDA8HpqKagh53XaopblpIbe+knDpFAhPab2Dw0TKvRK7lmNODzePBgZlK9oUWSpmVNdpIU8T+jaMsyMaD4MDcZVa+NhJMN00w0n6V2nN3yQgdHWZag+LzYPTomIAtT0THVtPGanmb/BbjwLFkvn2IttYGYplKyDzsHh7gdmyAWfh5zVq0Guhg4RAHFUhmfvq3j134aXo8bd+ITnMFOOovU5jbGRoZwNxFn1cxuAIcDW/sZDjA/c4u+BNxOJyxqaenpI3z88gMfPn9Hv98HQZS6RazW6kjExvFi8TGdDSy/W0Emf4LS6R8sv11BmfzSwkPcm74Jo9Ei0GZgmkw8QCOao8OXcaz/5vSZnPdnp3ApqBBLkWJE0Ci7ASzbIhCLLQ1E0iOkBDh9NpUgiUejo8oNuJwyn0YPABtn51UYFFivG3yBGCNZkuDtc/MW+ZQI3OrYpBaARCKufk3B5XIiWyhiL5ODp8+FfFHH+KiKSqWKUL8fC/NznGlPBmz+24dZjKnD0CJDcMoyW0SqXuMtHBFw7rhIAD1ErNUNafxKBNevapwu65NpEQ4FqXIA+RMd6VwBP3cPSERb6gLIFIq61+UqGWaFdcrVt/lmAuWjAi2aiMFwmOYuIJ/N6M28vwIMAMoNDyg4rcU9AAAAAElFTkSuQmCC');background-repeat:no-repeat;background-size:contain}.ipfs-ics{background-image:url('data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAAhRJREFUeNqEUkFPE0EU/mZ2dra7bLNpi2AxQFKalkJrohICiYkXPagXrx78Df4K48GDBzmQePLMhUODNxQ5ciEkJVqDtJGmMWrCATRbd2ecoS5u3aovmezsvu9973vfPiKlhI4XL7c2r5YL81LIELEghLA3u/udxmHnPmfGW/Wuv+LpwwdneRYBx7PeWK0wOYYhcXxyckGV1fdbnbuMsXcklqPRJQxFMKz4RxDCtVO4s3xlRjWoB0FYjlQPEEBieChwKCRGMx5uLtaKs1P5ei8IKlGa/YkXMXYtlTEDlsnw/mMXhBJcqxSK6vlcpa4PEpCooUyIqs5M6hG1o2CUwqA091cFcYLf/sjzcX75EiQIojI9779CTYR4jwTBf+r7GAwh0AxCiL6JMT/04vQ79u8aI2O/7Jzg69o6Go8ewycUahtBpADhHKLnK/eVbkMdtROWIv80NQ2sPhncA9Htwn+9hZG0rY6DzFwJl+7dhs0ZstUy8rduwPS/wd/ehmi3kwq4zTHiWUgXp+EuL8FvNvFl5Rn4xAS86iyI2kY3n0Mv48ByrOQmancdi8I0Kcj3U5iuA29xAelKCUHrEIayzltagG2E4IwkFaQgSC6lYI09iN0d8It5uNV5nG5sgJdKYC0G8WoTOZvBISFNEBxnsuzD3GX4vfDsszzqAu0jkJQDedCGbB6AWg54pYbPo+NGVPdTgAEAqQq70PytIL0AAAAASUVORK5CYII=');background-repeat:no-repeat;background-size:contain}.ipfs-iso{background-image:url('data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAAjlJREFUeNp0kstrU0EUxr/k5qbJzdPYpGkpsUJoA2q1oLjTdiGiIC5cuXHlxv9BEOrStTvBnQvRrSAIsejCrlqpsURq2hCJNQ+TNLm5uc/x3MmzJh34mDNnvvnNzOE4GGOwx8+t9XQkfn0VE0Y5/7Z+kHm+dvOhtd3P9c/xwNZh7nWaMYtNUmX/Fct/vlN7/8J5aRRgyzm8xzpRDjGE2aVH4VTqdnoUYg/XkEhmy+Cx3DhA5tMzdFolvg5Mx3Fx9SmH0JIg79Zo3j4GADMIokJTKtjbfAKXU4Y/2NvSfyH75TFOxa9Cmr0XnlPFl5ReOQ6wNMDsoFX6AElqQlNV1KsOuNwS/AGFjEUIDhmn5+/DMM16/9igBowAzFKIswPJr6MjlxFP3sV04gaP7RzMPe6xvWM1gNUBM2UKYlBau3QghGphg29J3gDlLLilWNdD3gkvIIDRhD9yGe2mCV0V4HFXuCxT5Dlv8Dz3sIkAs03FalDxBMQSt9BRBMhNncuO7dyU28c9tnf8C/Q0ZtR4GImeQSj8APLRH772BWcgiFODffCv/t8H9tO0v3RjV7VqkeeXLlzDfvYjj88uXhl4JwIsrYxmLY/M1gYclIvGE9jZfNPrSCD3/QgLyeWTADV6wW9AryIcCkB0u1Aq/oCPumlufoF72vIheaLDr4wCLIOqrYnULA14PSoqpSJEAUilZrD77Sv3LK+cI0+Be8cAbbmAOrob0agtD491LYfkoqvnyZLsWRkA/gkwABL4S3L78XYyAAAAAElFTkSuQmCC');background-repeat:no-repeat;background-size:contain}.ipfs-java{background-image:url('data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAAjxJREFUeNp8U01v00AUnNiOEyepQyhQobRBSlVIoRCBEPTAjQsSEneE+An8FM5cuXLNoQduIAE3qopKNJAIIppA2jrOR93aa6/N8yZuUxyxkrXr3ffmzczbTQRBgHC83nj3ca28dD36nx6fvnzrNNrdp4oibyUmey9fPBezEgWVFuYLdyvlPGaMY4fl1aRS+9pqP5ElAkmcnknRwuO+Nyt5u/ETYfyj9WrpZnmpxn2/Ok1Swn/GvtnH5k4TLue4kNfxoFoprRQv1TzOb8cAIu3+ZD7oD/Hm7XuxzqRUNDtdkuLiTmW5tFxceBXlnXgQTAORSMt2oGezUJJJrK9dFWdEH7Ik4dB29LiESeUEJXd7/dAT3L+1ivlCHr8NEzutXTBvbJPPSdO/AH5wysChwM/1HzCGlmAzOrKxu2eCud6Z2Jke2MwThpUXL6Nn2ZAVFTlNw70bK0iRnGAq9qwHtOmTRpsx1NsHyKRVnNPnoMoK9kc2BjbD4vk5JGV5NkBoEPM4FFnCteJFWOS4ntHEfphQyKaFTWFLw704AJ26ZFx/ZEEi3YyY0O1Dmr4EKTUHA8hUnS6siI0DEHLYog+b28RCRuNXR/iQUpPUEQ+NVht6Lodnjx+GXYgDSFRnq97Ed2pXSlXhUSeGhxYc5sKlNXM5DGLR2TMwfZVPAIi+otGNWy1fEZUKeo4qc4ysI+F8VksLIJfYcD9QYgB/DNPMptWBlsnBIS86xmDMTBo/PWd0LB6VZfdEbJT3V4ABAA5HIzlv9dtdAAAAAElFTkSuQmCC');background-repeat:no-repeat;background-size:contain}.ipfs-jpg{background-image:url('data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAAmlJREFUeNpsU8luUlEY/s4dmMpkWxRopGJNNbiwhk1tItbGtXHr0hcwmvgOdWld6Bu4coXumtREE3ZKu8FgOlC1kIoXtC3jPfdc/8PUIpzkBM7wf+f/hsts24YczuerGUc0moBlYTAYA+i8sbdXtAzjITRtq39kr73s/Gr9DTUYPOeamwvYnHdrdR0SnDebuCbswJGqpX+Uf92Hqm7hzFAG/4TgNr1uCwEJ0trcBC8U0Kb1/PQkHt9JxSLnL6TB+Y2zAIMOJBGLXmtsbEAYBsx8HnqCGKVScAX8uHf5EpqmGXv18VO6VDEe0PXsKABN8+AAgiabmYFNNJTDQ2RUFc8+Z9G0OPR4PKYwvKari0MAgiY/OQGCAajhMNR4nDZMaInrKBGl70SPMScck1NQG3X/CAWLE3/dAWV5hRRVIJxOWNksrP19sFgMqqAebUGYHMI6teq0A9oTVAhqu2sfbYYjsL7lCZ3683gA70T3TK7/B4BNoO020GwB9TpwfAz8LgMtWn/NkV8EHgoB81c7nYwCyBZlEVkHcqMTKFnkmehJTOPvEfCnKi0fAyADJKfXC/h83TaZTJjaa5lANLpOFqAXtlEAorAwO9u5syT5UxLfU0e3o1FMu1x4u7ODYq02BKAMAVSrSNLrK1MhLPj8mNF0vFm+C1ZvwKBwXXE4AGn1WAASazESwUW3BzUSMeJ2o1Aq4sPurvQYSRLwlhRR6mSaYyi0WlpAJrFRx3ouh5/lMt5lv8BLwXp0M4lSpYL17e2uK5wP6lj/c2ZPn2RI+YT8fDvqoyegVLyfG5kBKaQQOfvF2pLc+ifAABiQH3PEc1i/AAAAAElFTkSuQmCC');background-repeat:no-repeat;background-size:contain}.ipfs-js{background-image:url('data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAAyJpVFh0WE1MOmNvbS5hZG9iZS54bXAAAAAAADw/eHBhY2tldCBiZWdpbj0i77u/IiBpZD0iVzVNME1wQ2VoaUh6cmVTek5UY3prYzlkIj8+IDx4OnhtcG1ldGEgeG1sbnM6eD0iYWRvYmU6bnM6bWV0YS8iIHg6eG1wdGs9IkFkb2JlIFhNUCBDb3JlIDUuMy1jMDExIDY2LjE0NTY2MSwgMjAxMi8wMi8wNi0xNDo1NjoyNyAgICAgICAgIj4gPHJkZjpSREYgeG1sbnM6cmRmPSJodHRwOi8vd3d3LnczLm9yZy8xOTk5LzAyLzIyLXJkZi1zeW50YXgtbnMjIj4gPHJkZjpEZXNjcmlwdGlvbiByZGY6YWJvdXQ9IiIgeG1sbnM6eG1wPSJodHRwOi8vbnMuYWRvYmUuY29tL3hhcC8xLjAvIiB4bWxuczp4bXBNTT0iaHR0cDovL25zLmFkb2JlLmNvbS94YXAvMS4wL21tLyIgeG1sbnM6c3RSZWY9Imh0dHA6Ly9ucy5hZG9iZS5jb20veGFwLzEuMC9zVHlwZS9SZXNvdXJjZVJlZiMiIHhtcDpDcmVhdG9yVG9vbD0iQWRvYmUgUGhvdG9zaG9wIENTNiAoV2luZG93cykiIHhtcE1NOkluc3RhbmNlSUQ9InhtcC5paWQ6RUQ5ODY5Q0NGMTE4MTFFMTlDRjlDN0VBQTY3QTk0MTEiIHhtcE1NOkRvY3VtZW50SUQ9InhtcC5kaWQ6RUQ5ODY5Q0RGMTE4MTFFMTlDRjlDN0VBQTY3QTk0MTEiPiA8eG1wTU06RGVyaXZlZEZyb20gc3RSZWY6aW5zdGFuY2VJRD0ieG1wLmlpZDpFRDk4NjlDQUYxMTgxMUUxOUNGOUM3RUFBNjdBOTQxMSIgc3RSZWY6ZG9jdW1lbnRJRD0ieG1wLmRpZDpFRDk4NjlDQkYxMTgxMUUxOUNGOUM3RUFBNjdBOTQxMSIvPiA8L3JkZjpEZXNjcmlwdGlvbj4gPC9yZGY6UkRGPiA8L3g6eG1wbWV0YT4gPD94cGFja2V0IGVuZD0iciI/PoT8zQ8AAAJdSURBVHjadFNbTxNREP52t7S0bktbKFAvTUVaw60YqkExUTD6oD74qC/yD/wp/gh885XEEI0RAyYQUiMpIBGMkYR6o23abi+73e2uc04v1LROMtnZPTPffvPNHMGyLDB7sbJ2ciUSli3U35smkK9t7x9v7n2dD/g8KUkUwWqeP3vKz23NxJGzgwOx0RC6mSgIo+WKuvP56MeUzy2nJEk8PWsGJVVTuhWbpgmHw47FB7d98Wg4mVWK52o1sxOg3Va3PmFp+Q2PdUquaFUM9/vw+O6cP3bxwm46Xwh1ALR3/vL1e+hGjcc9koScUsTSq3coVDQsXJ3wzo5HEs3clgZNMTVdx1T0Ep7cn6//QRQwMhzA6uZHLD5cIFEFSKIU+G8LK+tb0KsGZKcTJoEyP08AbpcLy6sbPKdQrigdAGaDwWxsDH1uGbliCYIgcM8WFPg8Mq5Pjzdyu4jYbCE44EepXMHuwXe+A8x3KKYxYsjvbUzmlPGpBmYdgI1oYjSMbL4Ao1YXMkcM2Dd2xnbAamPQAqg1GORLZdycmYTdJqFKk2DPR3fmwI4zBDrg9RADqxPAbPBif2WTSB584/3/TGegEOit+DRcvQ4OZJi1LgwIQKVCg2i6nb1I7H3Br3QWqT9pBAP9uDY5xjdSM3RqxeoUkfVnEOW8UkLykERTNXjkM7h3Iw6NNvHw6JjuhAhVrba0+QeALozcI9nQR0VvNxJc/ZmxCNGvIBQcpDG6udA22kyW29HC72wu8yG579ZoiSYuR/ly2+y9CA4NceWLmo717T1i5ULqJNtapL8CDACskxPFZRxLwQAAAABJRU5ErkJggg==');background-repeat:no-repeat;background-size:contain}.ipfs-key{background-image:url('data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAAlZJREFUeNpsU11PE0EUPbM7u/2AtJUWU6qiiSYYo5EmmPDCD9AH46sx8cEnja/+CB989z+Y+MKPgMiDsYQACcbaWBBogYD92t2Zud7ZlQZsbzKZ3bl3zj3n3IwgItjYeDO3MlWme0bjUth8e8/fO2tHzx3XqUEk50uft+Ndnhdmc3SlfNPkVZT8Cy600DoIISvVfKYtlvfX1p66XmoIYsMZdjJQWvEFbbsC/S5g2QhSkKUK7rx6OzvzqLpsovAhaAxA3DUBQn2TUFsl7KwTfm4Z9DoO5LW7uPXi9Wxpfn7ZKF09vyPxX2iWcNRkKGZz0mQWKoNs8AVB6x1yRY2pYnc2LLofuXTxMgAlmlXIfngCxNxEzM+DPv6NQa2BygLgZyX6JT83ngHTN5GAL0WSoUQkSQnXkyBh/k0GegTAaldM20sTKvet+yyhIZApECamL0jUSe3oFChx3TopM4TeEQP2gc6BgGIwb4KGNXRhCkMGxgg2kJeybRiZM45D8W61qEAknSmpHStBhywu0nFVupSCTAcM4ECwqapv+NQ6LS9JGALoMIIoPYDjZiEL1xHtbyO39AQUDaA7R1AH23DSeSA4hv5RG/VAhxomPYP8sw9A4TaC9iHkjUWmrtGvbyC18BLe3GP0m3WW4I5hEBEnPIStXzyuFIxb4EkMEJ79Qa/xHbKxCdM7xeCwzUZOjgEwnuzt7qLz6T3cySmQP43uzjeIiTJM6io6W19B/NLCKMVGCzkCoLR/0lrfOI2fNy/huKC1FTsK/rbGNeMRC8dHpHByfu+vAAMAL/0jvAVZQl0AAAAASUVORK5CYII=');background-repeat:no-repeat;background-size:contain}.ipfs-less{background-image:url('data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAAyJpVFh0WE1MOmNvbS5hZG9iZS54bXAAAAAAADw/eHBhY2tldCBiZWdpbj0i77u/IiBpZD0iVzVNME1wQ2VoaUh6cmVTek5UY3prYzlkIj8+IDx4OnhtcG1ldGEgeG1sbnM6eD0iYWRvYmU6bnM6bWV0YS8iIHg6eG1wdGs9IkFkb2JlIFhNUCBDb3JlIDUuMy1jMDExIDY2LjE0NTY2MSwgMjAxMi8wMi8wNi0xNDo1NjoyNyAgICAgICAgIj4gPHJkZjpSREYgeG1sbnM6cmRmPSJodHRwOi8vd3d3LnczLm9yZy8xOTk5LzAyLzIyLXJkZi1zeW50YXgtbnMjIj4gPHJkZjpEZXNjcmlwdGlvbiByZGY6YWJvdXQ9IiIgeG1sbnM6eG1wPSJodHRwOi8vbnMuYWRvYmUuY29tL3hhcC8xLjAvIiB4bWxuczp4bXBNTT0iaHR0cDovL25zLmFkb2JlLmNvbS94YXAvMS4wL21tLyIgeG1sbnM6c3RSZWY9Imh0dHA6Ly9ucy5hZG9iZS5jb20veGFwLzEuMC9zVHlwZS9SZXNvdXJjZVJlZiMiIHhtcDpDcmVhdG9yVG9vbD0iQWRvYmUgUGhvdG9zaG9wIENTNiAoV2luZG93cykiIHhtcE1NOkluc3RhbmNlSUQ9InhtcC5paWQ6RjZERjZENTJGMTE4MTFFMUIwOEVERjQ5MTZEMkVBREUiIHhtcE1NOkRvY3VtZW50SUQ9InhtcC5kaWQ6RjZERjZENTNGMTE4MTFFMUIwOEVERjQ5MTZEMkVBREUiPiA8eG1wTU06RGVyaXZlZEZyb20gc3RSZWY6aW5zdGFuY2VJRD0ieG1wLmlpZDpGNkRGNkQ1MEYxMTgxMUUxQjA4RURGNDkxNkQyRUFERSIgc3RSZWY6ZG9jdW1lbnRJRD0ieG1wLmRpZDpGNkRGNkQ1MUYxMTgxMUUxQjA4RURGNDkxNkQyRUFERSIvPiA8L3JkZjpEZXNjcmlwdGlvbj4gPC9yZGY6UkRGPiA8L3g6eG1wbWV0YT4gPD94cGFja2V0IGVuZD0iciI/Pl1w97IAAAJhSURBVHjahJNLbxJRFMf/wPAIMIxMkUI7tS0VYqlGDLGhjdKkqyZ24cJFN925de+XcONHaHRj4k7TND6SGo1VWwmp2kSLhlqMDbQ87gzPYcY7k4GgoJ6bmdw598zvnvM/95pUVYVma+svcovx8yMnFZHAMJPJBJfDzq5vpX6+/vD5qo/z7DOMBdo/d26t6jFMJ3iY51jBz4M+LP6wxEw40Gy23qYzB3HO7fpmpZCOmfEfa7Xb4NxOrC4lvbPToe2yKE3K1PdPwNOtHdx79ESfq4qKkijB5/XgevIyHxEC24USmewDqD2ABxubaLRkfW6zMqjWGlh7/ByyAtxYnOPnL0Q2+gGGmKRaw8zUBJaTiS5QOO1FJnuIAM8hciaIWHgi8NcSNt+loVDY8JBXh2ojJAR1HbTSNFMUpV8Dxcjg0nSYBrtBxdLbqI1iheCUh9XXNGurAwCdEkb9QyBSFam9TDfoPZ1LUg1BH28IiwEARTVAQOzcFKRaHZpLoa9avY6L1Gfs0c32t4PU6W2lWsV8LAorw0Cs1nXftYWE3qZGqwWHzYp2zzlgetuolVFvtiDLbRRKFTAWCxx2G/KlMtXFhWPqOzsWHJwBx7rxKv2R7mwFz3lw9/5DLC/M4Us2RwV0g3U58XJnF7dvrsBOoX0Abbej/DFKRMKI30fTVGC32WA2m5H9cQQvhYi0vE/7Wdgczn6ARA9QPBrBszcp/XvpyqxebzQ0Tlsq6llxLhe9bD4cFMr9XdjLHpLv+SLGBYHAYiVu1kNOpAaRTWbCejgiw0zGhFGSK1aw+zXbvfK/BBgAPwADAs5GpGsAAAAASUVORK5CYII=');background-repeat:no-repeat;background-size:contain}.ipfs-logo{background-image:url('data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAoAAAAEACAYAAAAjlcdmAAAABGdBTUEAALGPC/xhBQAAAAlwSFlzAAALEwAACxMBAJqcGAAABCZpVFh0WE1MOmNvbS5hZG9iZS54bXAAAAAAADx4OnhtcG1ldGEgeG1sbnM6eD0iYWRvYmU6bnM6bWV0YS8iIHg6eG1wdGs9IlhNUCBDb3JlIDUuNC4wIj4KICAgPHJkZjpSREYgeG1sbnM6cmRmPSJodHRwOi8vd3d3LnczLm9yZy8xOTk5LzAyLzIyLXJkZi1zeW50YXgtbnMjIj4KICAgICAgPHJkZjpEZXNjcmlwdGlvbiByZGY6YWJvdXQ9IiIKICAgICAgICAgICAgeG1sbnM6dGlmZj0iaHR0cDovL25zLmFkb2JlLmNvbS90aWZmLzEuMC8iCiAgICAgICAgICAgIHhtbG5zOmV4aWY9Imh0dHA6Ly9ucy5hZG9iZS5jb20vZXhpZi8xLjAvIgogICAgICAgICAgICB4bWxuczpkYz0iaHR0cDovL3B1cmwub3JnL2RjL2VsZW1lbnRzLzEuMS8iCiAgICAgICAgICAgIHhtbG5zOnhtcD0iaHR0cDovL25zLmFkb2JlLmNvbS94YXAvMS4wLyI+CiAgICAgICAgIDx0aWZmOlJlc29sdXRpb25Vbml0PjI8L3RpZmY6UmVzb2x1dGlvblVuaXQ+CiAgICAgICAgIDx0aWZmOkNvbXByZXNzaW9uPjU8L3RpZmY6Q29tcHJlc3Npb24+CiAgICAgICAgIDx0aWZmOlhSZXNvbHV0aW9uPjcyPC90aWZmOlhSZXNvbHV0aW9uPgogICAgICAgICA8dGlmZjpPcmllbnRhdGlvbj4xPC90aWZmOk9yaWVudGF0aW9uPgogICAgICAgICA8dGlmZjpZUmVzb2x1dGlvbj43MjwvdGlmZjpZUmVzb2x1dGlvbj4KICAgICAgICAgPGV4aWY6UGl4ZWxYRGltZW5zaW9uPjY0MDwvZXhpZjpQaXhlbFhEaW1lbnNpb24+CiAgICAgICAgIDxleGlmOkNvbG9yU3BhY2U+MTwvZXhpZjpDb2xvclNwYWNlPgogICAgICAgICA8ZXhpZjpQaXhlbFlEaW1lbnNpb24+MjU2PC9leGlmOlBpeGVsWURpbWVuc2lvbj4KICAg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O4qxDy/KPWcv/tsh82bPxyKRSyH+woXBUiwwNcNIYdO5ZbPVtXWLq6DFPsSQ0C4xgDOZkI2p+CNzskdImGjb+rXXHXbQwhkSfwm9LGpMBERABEQgiwloBNDDxT1706bpDUsfuqmkuuZELKTI52igaX5hBiRmyJgyhI7hatVkFT+PAHLBTP+eZju0C7OxmBQKP476Ydp3tGf7ticC9TNOfeCcc3aZ1NU+IiACIiACIiACYwQkABNwJ5z56BNvbHnhuduRGu4wt2nluFKY/oFccWs6kuimy34UgBTJXJlMP78ogjqblpfStzU2Nlgjo5/611cv/JdpXe0nAiIgAiIgAiLwMgEJwJdZeP7rA7++6cyR0ZFfIK1cNVcLm45q8cBMJxeCf2CgEvEDE1j8JgCHuhnPD35+SONmWjhaynA6SN820N/U/G1M9f7MtK72EwEREAEREAEReDUBCcBXM/H0ypLVq0t3PPHUdwtD5V+CaCliOBPTaWHG3iupqbFCM+utwtJST/1wKvtFAEbh59fX3AQR1zFp3EGnvxO3HBFl+BwwjPVs33r74R/8wJIbjjhiYOI++lsEREAEREAERMA9AQlA98yManzquedmN69cdUtJVfW74B+YZwcxNgwbwxGvshl1ViniB/JvLyXdApCjoAOI59ffssd8RJRhXTDiB0E82rNr5wtFleWnPHjeeZu8cFBdERABERABERCBlwlIAL7MIil/nXrfA+/o2bHt94GqmgMYO9BVWjmscrXDxmBU0Mna4baT6RKAzC7C0T6GdWFWFNNip2/DIo/+5qYWjPwtWfaNr/7dtK72EwEREAEREAERMCMgAWjGyeteee+78befQyM/Ki4LVYxEhoyzW/DA9AukfyD9BN2WdAhA+vfRz4/+fqaFWVPykXYu3N0VHtjT/OMV//vty1B31LS+9hMBERABERABETAnIAFozsrznues2FC++/nlPw1UVZ2dl5dfGIMQNPYPhD9cKVYKlyJsDPPcmpZUCsBoOIzpXoR1wQpfN+fFfMOjsehI17Zt98487G2fuuPU47tNz0/7iYAIiIAIiIAIuCcgAeiemeca57z44gEND/7rDyW1046KDUfy7NXChv6ByEds5xYuhY+gSVq5VAhAO30bfPyYuzeG2H5GBX5+9upeTPf27NqxIThr5qn3nXnmGqO62kkEREAEREAERMATAQlAT/i8Vf74HXe/v7+n8zfFobL62BDDxhiKJxy2CKuEQ/WzrJLqagZF3mdHhvv6rPYN6yddeev4FdJfb+/C92oOO9wqDoX2fuvlf9PPr7MT072NrjKb2OnbAsXWYGdnV7Sj+0v/uuQrt7zcqP4SAREQAREQARFINoF9K4dkH1nt2wTOWraspHVHw/9AcH2zIFAc5DSq6fQphR9WGVuhWbNsQTgZ0qGuLqtz86ZJBeBk+7/0GgXgQQdbmK5+6aWJfzB9W19joxXu6oSn3qsF5MR9nb/t9G2Yvh4eGBzGaOGvFh51xNdvXrTIPBK005C2IiACIiACIiACnghIAHrCl7jKTCvX+PC/rg5UVJ6CIb18ho0xFYKcSg3W1iKjSL0dPoW9Yl2Kvz4kzRgeHIyro0XBIMTlbFsEOllK2C+s0LUG29uNw7rY8fwQ1mUUSrFnx/ZltW9+05l/ed/7muLqlCqJgAiIgAiIgAh4JiAB6BlhYhs4+5lnXtOw6qlbg9Nq34hp4Tw3YWMYNLkMsQMLse1vacEq3MSspQhUViIu4QykbRsa8/PD1rTYYV2K6ee3a1tJZfnp93/mM6tM62o/ERABERABERCB5BCQAEwOV8+tnvzHP38k0tt3XXFl5YwY8uW6SStH/73J/Pq8dMptm/YCD+Q5Dre19mCa+Kv//ubFN3g5vuqKgAiIgAiIgAgkjoAEYOJYJrylU1auDA5u3PQdzOtemF9UGKAQNJ0WTnhnDBscS99WYmGqODrQ1PD7acce88U73v72+OagDY+p3URABERABERABNwRkAB0xyste5+1du3MxkdX/iZYUfG+kZHRfISOMV54kbIOY9SxoAjp2/KRvm33rifLF8w79Z5TT92ZsuPrQCIgAiIgAiIgAsYEJACNUaV/x9MfffSt7Rs23hqsrD6U/nhu/AOT2Xv6+dHvsHdPU0N+nvXfD37xiw8n83hqWwREQAREQAREwBsBCUBv/FJfe3Q076Q/3blkNBy+vCAYrIohbMxILJb6fuCITN9WwLAuvb0DA91dP1x+0Zd/iNA0ZjFh0tJjHVQEREAEREAERIAEJAAz9D44Y9Wqis71G3+EtHBL8kbzCqMu0sp5PWU7nh/Tt43GRnoaG/4y+53HnHvrUUf1eG1X9UVABERABERABFJDQAIwNZyTdpSznl13cPMTj/0uUF19FKaE8+xUbIaBmV13yvbzK7JTuPU17F5fVj/3k3ef/vEXXLejCiIgAiIgAiIgAmklIAGYVvyJO/ip997/3t6mhhuLK6vnxJLgH2jH84Of32DLno6RyPD5D110wW2J671aEgEREAEREAERSCUBCcBU0k7ysZasXl3U+J8NF46OjnynMFhaFg0Peg4bY0/3lgSt4b7eyEBb2y8OOW7RJTcccYR50uIkn7OaFwEREAEREAERcE9AAtA9M9/XOHft2prGx578ZXFF+SmjsVhBjP6BLqeFGfi5AH5+Vn7+aO+uXQ/P/H9vPu2Pixa1+f7k1UEREAEREAEREIEpCUgATokoc3dY/Pzzr2t54qlbSiqr30QRaBo2Zix9W8Dqa2rcWjyt+oz7zzxT6dsy9zZQz0VABERABETgVQQkAF+FJPte+Ohdfzt9qLf3F4XBYK3tHxiNTnqSY+nbAtZQT09ftK/3kocuvODqSXfUiyIgAiIgAiIgAhlNQAIwoy+feedPWbY2FN75zLes/KIv5xcWBKIT0srZfn7I24sVxNHBlqbf17z1fRfcsei1feata08REAEREAEREIFMIiABmElXKwF9XbJuXf3Oxx6/KVBeeQJEYD6bLAiUjPY17n6y9uADT73jpJOUvi0BnNWECIiACIiACPiZgASgn69OEvt2+qOPHzfQ3Hg3FokUxqKxT9x75ml/TeLh1LQIiIAIiIAIiICPCPx/9LZZ0UZyLiQAAAAASUVORK5CYII=');background-repeat:no-repeat;background-size:contain}.ipfs-mid{background-image:url('data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAAnhJREFUeNpsU01PE1EUPdOZKWUotKUKFLEWkQ1EASGGxGBi4sIVrt27IixN/Cn+CxfVnQsXJiz8IAoqRBGEaMUUWzofnXkz781436QDkjKTyXuZe96595x3rxJFEeTzaKW6dmdpfIoxjuRRFECGn7/4Utvarj/syWgflU5s891qvGoJePJasfBgeSpnW+yEIJVS4DEBx3FzGT2qfvh0tJxOE4mCU0yy8X3BLdODRQTJZ5oMzYaD0UuDePzkbnnx1mjV9/lMp+izBKEIwQMOzvnJGoYhhBDgFKtMjmBl9XZ54WapSjLnknMnEkQYgflCVhKXLt+/dRMy2d5OHdVnPoxeHUtLV8u2w5/S78UzBJwLMC8gAsosIqy9/ga37WNmvgKVKmEkb7JSwI3pIdRq1kBXBZJAUKkb6wd49fIzbJthdn6cIhE0XUWbyP4cmshmdZAE0eUBD6gCN0DtZwM7Xw+RUlVEJCui7CmyPaS94zC06ZMedREERNA6djBWHsS9+9fRS3p9AraOXbhELMlUQju2G2O7JAQENk0XhpHG3MIVlEZzaDbdOKO8jWy/TraGsMmL4L8KTgnIfcfy4JBWeQNp0j10MQtB4EJOg6qFMI/bEH3pGNtF4LOAjHMxO1dGvW4jXzDi7Iw60TB0jJRyONhv4MdunbDneMA6BMPDA6iMFzExcQH9AxkUiwby+QzevtnF2OU8lBT1i8fOa2UO1/FwdGTHE2STHM/14+vlPOz0RxibKPfn9AHXZHBzYx866ZdTKkuVndhHuqenS1h/v4ffvxqyvbUuAtPizZ0Dp7X1fTs+FA9cMnWd4ZG90NOjomVFzeTcPwEGACDGeYddZX86AAAAAElFTkSuQmCC');background-repeat:no-repeat;background-size:contain}.ipfs-mp3{background-image:url('data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAAnxJREFUeNp0U89PE0EU/ra7XWxpSsFYIbVQf9REFBHkYBRIPJh4wrN3DsZ4MPGP8b/wUCIHEw5EY0w04o9ILcREGmwVgaXbbXdnd2bXNxPahGyczebtzrz3ve99740WRRHkWn5cebu4cH6SMY7e0jRAHr9c3WxsVvcemmbys9yT6+uHJ8oaPefypdPDD5Ymh5w26wMkEho8JtDtuEOZFCrvN/4uJZNGH0T59D58X/C27aFNAL3Xthmsww5GCyN4+uzu+OLtQsUPxPQx6ZMAoQjBAw7O+bEVCMMQgqygs+LFs1h+dGd8bna0QmXO9OL6JYgwAvOFZKKoy3V44CgNfv7Yx8oLH+lUEgvzF8Ydhz+n41snAGRG5gUEwClzhHdvttFxfNyYK0EnJozKK5eGcf1qHo1GOxtjwI+pfvm4g/W1qtJgerYE2SXJSIL9+W0jk0mCShAxDXgQKgbNXxZq35vQKCiKQkSUXdc1+gcch1FHGPmKuIgBCdc66qJQHMG9+1NIpUylxxHtuW6gEiTIu+N4yjdWgty0yTmdNjFzcwKjY0MU7MLt+IjoSad16FoIx3b/A0DZ7FYXnsdpAjUMDOjI5zPgfoBsRodhhGhZHfBBU/nGAGRtxWIOg5lT2NtrI5dL0SB5KJzLodloqXaOEatPGztKq5gG3S5DNjuAK5NjKJfPYKI0okBkSdemCiSgS/rkQNLSePtxBj4LSCwfFtE0krqqX7ZVMnu9XlMXy2l7ME0dzA3iANQyY6vWxC61UY41zTyNcYh6/QCNXQvzi5dR39nHVq1BUyuMGAARsF6tbbe4iKD1r7Om5iFBdmW1SsDflLiuB6sX90+AAQDHAW7dW0YnzgAAAABJRU5ErkJggg==');background-repeat:no-repeat;background-size:contain}.ipfs-mp4{background-image:url('data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAAnBJREFUeNpsk99r01AUx79psrTrujVtbceabnZs4DYRHSoMh6Dgq77rn+AfoA/+If4Bok+C0CfxVRDBh+I2NqZzrpS1DVvbtU3SJPcm8SSlsJlecsn9dT73nO85V/B9H0H78OLdt/LDlQ1uMYybIAgI9n99OWxoe83nkiz9hDDae330JvxL48O51Xxm/enNtKPbVwAh0Ec6kYpXat9Pnl2GBC02HrjM5Y7h4P8+7FtIFVJ49OrxUnl7ucIdfhv+BIDv+fBcj7p/tXMPrs2RXVTw4OX2UnFTrXCbbY7tpMsA13FDSDAOQ4gJEGUJLs0PPh9CkESsPrmxxEz2lra3rnpAt3G6adgdQhBpmeLkFodNmsjpOPoXBrQTDcmFFNS7i3MRDzzPCw/vva8ikU+COQxm14BBhvJcHLGpGPTOAJxxeLbrRgAkYujBdH4G5oWJWXUW19YL4XqunAMFhnq1BqWYgaY1MAHASQOiU96zKzkU76mwehaOvx6h9uMv7KFN3RopL4oTAI4HRh4wSl399xla+00YbR3yrIzM9SzSqgJJnoKcklGrH08CcJjnBtLLCsSEGGpSWJvHtDKNoFippsJ0ulIsDDUCCATMlBQkNuahEyiZTcLsmFBKaQxaOk53TlHeKkM70AjAooCghBOk9sKtIvqtPqS4FBaRnJSRX8tj2DOh3lFB5Qw2ZNFK5LRo6w4sKt2ggAzywidAMN/9uIPSZglBLDO5FF3mRD3wHE9qVRvoHrUpfn+UEQK0/7ShtwboHJ6jdH8RZxSC57hSVETb7e5/2u0FxqPHJow+8iZ4lYY2QGu3idhIxO7Y7p8AAwALCGZKEPBGCgAAAABJRU5ErkJggg==');background-repeat:no-repeat;background-size:contain}.ipfs-mpg{background-image:url('data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAAnxJREFUeNpsU0tPE1EU/ubRdlqmnUBboa0UeUQDiUGCC1+JmrhxoXt/gBvXJi74If4AV0Y3sNKF0YUaICqoIfjgVShEiGF4tDOdO/fOeOaSKtie5GZu7pzz3e/c7ztKGIaI4vn9p+/P3h4e4a6Pv6EoQBDiy7P5rc1P1Xt6XP8M5ejXo6UJ+dWbuemeTGdpvNdiNe9YvQLe4Bi4PmTpRmyq8m71rp74BxKF2twIHvAo+f/l1T2Yp0zceHizfOZa/xRnfBRhG4CQqAYioBWeXDyA8Di6ei1ceXC1XBwrTXHPH2vW6ccBBBMI6BsSUEQzakGL6xB0tvjyBxRNxdCtc2Xf8R9TyaWTDOg2TjfVdw6hqIoE9B2GxkEDWlLH7s4ette2kSp0oDRezrQwCIIA3oGHr0/mKMmE53qo23W4+w5S+Q5ohob9X3tgHgO8ULQACC7gMx9mKQP30EW6mEHpYi8xcJEdzMucjfkKcrTfmqmiFYBxCF/Id+gayKJwoQjHdrA5v4HK7Cq44KjZNWpagaqp7QACks0H9znW365ia24DzoEDozOJbH8eVtGShXHTwNracnsG7q6LzsEuaAlNPm9h7DSSVjLyCMkppDI+GS2StQWA1RlKo0X56n2X+6QHkmkDakxF9WMVqWyK+s/BrthYfvWz1Ug+zUDcjMPMm0h3pxEjFma3CbIuCud7oMc0LL1ZgmElpGJtW3B+15HIGNITrMYIlOH7i0U41NrInREylYbu4R5qQbQBaAh95fVKZCnpQCnb9DrWZyrRERS6NDeUw+yHaXh7rt4C4B8y+9vkwn7kwKNRpDoa9aiFKBYnF+RcREqQ2e1m3R8BBgAy9kz9ysCE6QAAAABJRU5ErkJggg==');background-repeat:no-repeat;background-size:contain}.ipfs-odf{background-image:url('data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAAi5JREFUeNp0UktrU0EU/mbu3FfE1KRRUpWYheALNBURUVy7cy9UkO6KW/+Lbt0IPsFui4gLBbUqFaUuXETUKCYa0jS5yZ2ZO557b5MmTXpgmDPnfOc7jznMGINYPi0de5UvmpORxpjE/kbNqW005DVu8TWw1H758ZfkFgNgJmtyxSPRjJIj0QTW/RDiYGXGb7Dl32/eXrVsd0gSCx9miqC0ooCdp69g5Q/h6OLN0ty5ynIkwzMwUwh2FwMdcbDiCZQXlkqFCpEoPT/wih1YjLInANcD+/Ua9bu3wJlGvrBZCmet2+S6ME5g4oGlZ9A/I70XCDhhDexPNTFmswJBwcnuXkF86VSNZxVu0ukLSGnBcqlnN4HoCQIaIuIv7LUooMOgQ7q75LAAb59B9gCBHSKgqemRr94mMKmD24CfM8nb7THYGQNLpAkUkcb66JyGBFFEWRVL57gFEH5qj8Lxwca2qS3EZaugmzAw24dR/XQgwtsCSBjPIdWbUoE2UJLBnV8Ac/ciWHsK9/glWLnD6K2vgPszsOdOQdfeQ1c/ThKoTgDn9A3KUED/52d45xchZsvorD6Bf/Z60riV3Q9Z/0bbGU1uopYGkfERSQ3VbsMwl0qlqoIARmSoPYXWy0dor79LfBMEEd8jGs/uQ3Yl7PJFNFbuEXiV2riCf88fovXhBbo/vqP3t02/ZYmJFqTkzY160Go9uEMbFK8hR/NrdXtFuUVmnmySVGgO4v4LMAAjRgmO+SJJiQAAAABJRU5ErkJggg==');background-repeat:no-repeat;background-size:contain}.ipfs-ods{background-image:url('data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAAetJREFUeNqMUj1IHEEU/i7u7Z23e8tGgneGQPw3hZDkkhQiSuwMQREba4uUgpVlCrvEQhurkCoWqcQQ0oTAaYKNqJygGEwgHCSB6Knn7eXcdX/GmdHVPWYFP3gw78173/vmvYkQQsAwNvckq96UnyIEh7/d4t7uUd/8y+85P+bXSX4grkhI6nJYPW7LrXpBK2YxiSoShhu4Buq1NPofDeqdrZ3Z4cl7D4J3UtA5VyVAlmJoru9Af2ZAp1lcCQ3nqgiuKmbY3l/BH+MnHM9GVLP0Ww3KNA33CQoQQnL834Fj74PUGkANEIkCSSsa8gQqgYTIcB0PVsXB318GInRiCVWCkpRFAs+j5gKlA4t29Ggh4d0t04FKt9PQqF4UFgumSEA8ApeaElilWbYRVy/lsns/N1QBkxtENF4jxPxcgcB1CZVOrvMteK5IQDtJJIGh++PcX9iYwWjXK37+vP0WdYk0Ht99jtX8JywWFkQChw4tc+cZcvlF7rMze+ubbxN40fMalRMDP/6twaiUeK7wlZ0TD0a5hLTWxo2d45KKprqHKJslTsy209s2wnMFBTYNZjc/oLt9gPvLOx+hxVJIKS2YW5pCbSyJTGMK775O8VyBwDJd2LTDl/X5i8v3S7NVw9vJb51tITDEUwEGANCx2/rXEEFFAAAAAElFTkSuQmCC');background-repeat:no-repeat;background-size:contain}.ipfs-odt{background-image:url('data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAAepJREFUeNqMkz1II1EQx/+7Ca6JkqyYiJ8cKEpAQbBQFDm0sVOsFBS9wt5KOTgEG5twxVlZ+XEnKNiIghYKxx5nwEpIIXaiSAgKGmMi0d23u8+3T7OaZJEMLG9mmPnN/w1vBUopLPNNhRWXHOyDg0nx82TiJtZPlPVoNpftc2cTotcHtxx06kdXpSQ/BvzKESZzIDmAz6y+NojOjpDMZiqRPIgNoFyWM8DrKUV7axO+gcp4g7AzmquAdVNqOgL2z2I4id1B0wgeygOyt/rLL5buLwAIDgA9dY+L+DkuDQOCrkMgBsRglcMOqAGwIstMg8AkGsuZMNUMRMkLqE+QGloglvlA7uIOAKvZajR0qJkUj/XHe0BTIclVKKlrfKsj9qA8gA6wqSJzPaXlr7ky//tdLEUfawsBjExUFGVWbT7AxSa42H2LMfODmvd3wKb7RAMLYwM8nts8xJ/pEe7/3PmP2eGv3D+9usb35W0bINoA7RmjXSHsH0f5Z/mUSZ0Ir2JmsBtD80s8/rGyzWsLFTD5yUQCbfUBHl9d38LvkdDTXIuHVBo0k+bbt06qO+yAPGXwe/cA4wO9PN44jKDG70GougIzi2tQ00ms7/3lpwnBBgjZ37Kkd1Shht5XzBIFl/ufFtniT/lFgAEAU//g6kvdGBMAAAAASUVORK5CYII=');background-repeat:no-repeat;background-size:contain}.ipfs-otp{background-image:url('data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAAcJJREFUeNqMkssvA1EUxr+ZjkdbrfFKVD12ErYSRELY2fkH+BMsLcQaSwsrSzZi47EjJEQkEhYkFlhYSVtFpdqOqpk717l3jKZmiC+5mZlzv/s795wzCuccQncz3YeRBj4KHz0/RrOZe2NsZPP20o255zQ3EAxzEAC+6uzTw13G4TFQAakA/CWtIYbY0KBOrx7IvwDQqlHV1o3YxKTOvyAUvfQCfqmA3e4ikyS/zRAKvOot7eoSHEgZIHrCfQAfBqBaKQQDKScQAExd8emBANg+2U2CvNMkkgSqBmrCxFB8mujeoJBWwEqARcssKTAJEGrmaGrjqK1zvNknH4BtyxKl2VUpRxmj5W+x73q9AEaZrR/ND1EJluIpS3i9JQiA+a+hSq8HwJjTsLrRaWitPTCOlhEZn5N75sM1qigmlN+dB3u++Qao5W4TtbEXXIsiszGL4PA00itTsu6XnQWo0TjMTAJqfMDx/ryBJcaVzSNSH4fW0Q+rkIf5rsjRiid7yyN7uoXS3Zn0egE0NiORAN9bQ017D1Lri7CLlP2EDr3Rf7C/itzV2bfXA/igLDaRixfngFhSCooH2xVPCWBlwKcAAwBX1suA6te+hAAAAABJRU5ErkJggg==');background-repeat:no-repeat;background-size:contain}.ipfs-ots{background-image:url('data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAAfZJREFUeNqMUk1rE1EUPS8zmabJdDKB2glEwY9ExJYiBUEQpV25qgtBXfgbpEtXuujKf+AfEKRddOdOGHClbYVCvyKWaijT2mhjphk7Sd7Me76ZONp0EsiBYWbOvfe88+69hHOOAE9f3zTVnDKNHvhlsfqPw/rM0ovyWsRFdXJEpDIyRnSlVz0KSkmvabaJeXSJBEhgAJzTDNybmtUnS5Pmg/lrN07H5NM/f13FoMgpXDSuhiIiK3Qi6LUugX7FAbaPPsJqfIHHKCStqRsXVFPQuZgD9BBxjikSiRq41AAkgCQBzVf0+BWEBX7GBm0xgHHUqk1UbBuEcIydzyCZlOI9YEGuDxwduCCitS3Xh3viCZ4jrcq4PJ6DLHd67tjtuAAXib54dCPVEfQ5XIcik/0/2iDeOYz3ceCxrisMi904y0XiMQFfkB7lg6xFHwFxEqUMV0anUNBLWKm8xd3i4zBWOzmASx0UsiW831mA59Xjm+h7HCOygduXHqJatzA7Poey9QnXjTuoVD/j/sRcmDOWLgqnLC5A2wwST+Pn8T629lahSCo291bwu9XA7vcy3m2+gTaUR14thrk9BXasbdiOjSe3nmPpwys0xSi/HpbDd3bIQC6dx/q3ZbRb/j8BEi3Po5cTJpHI9CBNDEa++GyDBN9/BBgAwfDlCVUQaNAAAAAASUVORK5CYII=');background-repeat:no-repeat;background-size:contain}.ipfs-ott{background-image:url('data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAAdFJREFUeNqMU89r02AYfpJ0iVm7EqhVOxw7dDBEdpiCE1RoEZRddvUgbIex/Rs7eehppyF4LOzQu4MxwYp0HgShIuwwUVSCVtl0s13afl+SzzcpyZYmyF74eN583/s+PO+PSEIIeJZdrtQVI19Cgmk/Ph39bpllXq82g7sgLxVcyKNZpIx8Uj5u5zSjc9Gov8ZihCRC8D+7On4JczevGeTGSEIC4ctKJtB1DTPXi1iCCEkIm1EFlC2Em0iwtWfinXkIzjiO0jljtDC5TtflGIGUQMB+mfja/oPv2Rx9MMjpMdJxOXyXTwkcwIkewfqQ1QtQNB385zcI14FrtQexsSb6SRysZ4Fbf+F6eHwATc9gJGNAm5iCTL5n/LCVRGADNoeaGoHqyaXj5gqQlTODovcwNk5Aj6wXqV8eCo7EDhMonEHpW+dZC7gUG98D3geo7vkb01h9cAvPdt76OGy1xntUd3bjUxAk3+l2sHJ/FgtrT0MUJNfDSm0bjQ/72Hzxxo+NK+h3B7XRNO4UrwymQtMIkdTBU0m+sBOayLsn8Ka78mQDjx/e87HXPkb1+UsfP37+AmZ1fP/suknBb6nefVQXjl06TxMlJfWKNWr+Kv8TYAAkUueexJF47QAAAABJRU5ErkJggg==');background-repeat:no-repeat;background-size:contain}.ipfs-pdf{background-image:url('data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAAmhJREFUeNp0U0trU0EYPTP35qYxaW6TlDapNKWGbgo2FkF8rARB6rboXusf0F/hyq2U4krFqugqSBeuAyL4SERBstHa0iR9JKZJ7mvu+M0tqZGkH3x8987jzDnnm2FSSqh4ns0VU1ybFzj674Wa3uWiWbfsFQb+jrGj8Xvbm0HlvYVRxhJprpmTlGmum+OMm5uNPZNbtjk3l82ey8++8oW4Jv/H/wdA456g2kvH99FyHNiuAz2dwflbN8YW8zMK5Go/CMfQkAhpGsyQgRCtlpE4jIULyC9fHzu7MPPEl/5ib6WOE0JJNRiHHg6j86mMjw/2gG4bkbY4PW4Yj2j64skA5FTHdaEMPiAJszt1sK0d4suJmY4k0+IDDGRfqmh0u5gejQc+fG8eYCIahRQCEfgQnIuhEkgtONE+dGxYxEDj1DhiEycZ+1YXdUpHCqTMJIYyEES5aXXQsi2kYlGEia5GtHVKn+amPBeCutPgfLALPuVu+xDVPw2EQyFEjHDghbpYNm1yKVVnYjTOerepn4E6XQmLGSPkPkOXWATMSDcjQEkAaqOu6+i/rccALtFL53LI3r0Nq1ZD4/MXZJaWYFer+PXiJc6s3IEgY3+uPYZHTAcAHM+DTE8gnM1CSyaCulv+GrRy8uYyElcu4XfhLVpkpNtn/DGA5Uu0abFH36WnzzCayWAkmYJvWeCkfb9SwY+NDbSoOx4bYqJF8rZqVRRXV/HhzWtUSmWwmWl0RmN4v76OUqGASrmMOkntSHF8MOs954dT08W248wzYsJDOujRBAaqqikTpRo/qqd0/dv97c3Lat9fAQYA4z8bX9nTsb8AAAAASUVORK5CYII=');background-repeat:no-repeat;background-size:contain}.ipfs-php{background-image:url('data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAAhNJREFUeNqMkltrE0EUx//ZbDaXNrvZzdIkbYOXGgxYQlCK2IIY6EufxGdB8Av44AdR8AP44JOPBR+Ego0PClUKTTXQSmkTYtOkmubSJrQ1e3H2yJSEJNIDs3PmP+f89pyZcdm2DcdWvn7LzkxFHmCIra7nm9ulg8yLZ09yXON55Dgjt1PM2iPs0+aW/frdh8bzV2/SvQBnCLiEqcFxLKSSodlrU9leiGPihWePBkgeEZO6ShC2dCAZNuf6ADb+ldQ5PUPx4BCFcgXfdwq4Ph1Dtd5CZi4Nw7SQiMdCXkl6yVIy/QBWgcU+yx/XsLK2cdHndqlK/lZxH/OpJO7fnsWY3z/YAq+g0TmHpoUH2vB5PXi8RD9Fo10aAmDJTgWyIuOupmK38rsPcOvqJO33XWEvwLJsmKxHRVEwf/MKWl/yUMf8mIloWN8rw+sP0D6PHQmYuzGNgCRiMZVA17IQV4OIaTI8buH/AJMFd02Tkp05PO4jnWvc57EDAINt7u1X8Pb9KgI+Lxbv3cFR8xjx6AQ+b+Txs/qL9KePlih2CMBCq92hg2qzt1AoV7H5YxdhdqhHzRbgcpFeqdUplpvQW4FhmAixZ/sws4BoWCM/qmsE5XqE3dDQCrqGAYWdejqZgK6GUD8+IV9VghBFN1RZJv3sT5diBwC15gncggCPJKF0WCPN8dun55jQdVpz3Ynl9leAAQAJhiGatD9AOgAAAABJRU5ErkJggg==');background-repeat:no-repeat;background-size:contain}.ipfs-png{background-image:url('data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAAmtJREFUeNpsU9tOE1EUXXPp0CAUWmJbC04xBANNTF+kKhG8fID6aqL/gPEj9E0lIf6Dj30HL03wxQtVIC0QKrWxNG1Dk9Z2Oj1zxn1m0oIZTnIyZ8/ee+211z5Hsm0bYg29fLGpxWIJWBYGS5IA8ncKhT9Wvf4Yqprtu+w3q85X7f9QxseD/pmZMZsxN9fnc5JNw0ACGGv6tPSvyvEDKEoWZ5Y8OHHObKpucw4B0t3agnl4CJPs2YkQVu4s61ORaBqMJc8CDBiIRhhVM9bXYdVqYAcH8M3NgS0tQQsFcfdKHEbvlr6WyaR/V6uPKPy7B4DT7lUq4MUipMlJ2MPDUKtVfKZ2nn/5BoNbkONxXeb8LYXe/A9AJLNWCxgdhZJagDI9DZg9qIkEytRSkdqTSFQtGILSbgc8LViM+tc0yPfukzIyOJ359k9YR0eQdB2KmBbpwXoM3Dod1SkD+scpEapCI5DdpsJhIJcjajQZagcjI+5oLe4VkeQnyiZgdIH2X6BJ7dSqQLfrggjw0AQwP+/GegCIHppNoFAgEMO1RZKo7BQgRi3yN05cnwdA0BQMAgF3C6pnbuNg92M9AFT1diSCh6kb+FGvo2MxnBB9ocZxp4Mns1cde213B81e7xwAcl4jkaa0IUSjUdLJwkL0Ej6VSvArCt7l81iku6GrKnYEU89VJlSJRmR0Dax+fI9suYxSo4HlWIw6M3FBlnD9YhiXabyOsOeIqG7TzDeIYo6EDGp+ZPb2kKKqH8h+mkxiI5/D1/19J3bwYPvPWXq2skkiJVxesqt0XzghpKM8nRVV2Lv2q9eLIvSfAAMAaacnllcFBmYAAAAASUVORK5CYII=');background-repeat:no-repeat;background-size:contain}.ipfs-ppt{background-image:url('data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAAkhJREFUeNpsU11rE0EUPTM7ySZpmzT9DNamWAtFfSiCigr+AxF9zKtv/hvf/Aki+FEi6ov4ItWHPGiwiBUKoUqqTUJImmR3M7Mz3t0kNe1m4LIwc+65595zlxljEJzdR5uf5nLmsvZx6gSvtd9W9bjhF7jg5dH9nRc/wq8YXaTSJptb0xklx7IZoKUEz1zJ2DUU69/37vFYrDxegJ9U0lC+AoIIVGg9CL+vIObP48KDQn7x0sWiVnJrnEDg7KGk+i/Ac4iUM/R7BsmrSSxtXMfa3X7el8+Kjf3KfUJ+iRJQw4w0Tc8BRyWGRAZY3rBR/VlC+XED2ayDhZyXl03+hNA3TxNQshlGLAnE44zCIL1goXZwiMNvB1i6zbC0KuAsxNITWwgNMYPeLVJiFEO9ArjHAivrAjNzBr4f4vwIgdGD4YUACsZCE8AtYGWT5jCsGQw5wEYJzP/pj5RwYTA1b07eQmfZ8P0sgdaM2FlYwWkMgMpl6NQAO33GKM0wsQWflkh1uqGVmVWblsiDkQyqxwfag35SqcktaEWTUTHYNx4iGU/C29+BvX4Lpu/C7zYgFjegSY63WySsHyXwpYHU00ieu0bAOuJbBTArBkiXKiaAmTzcvRJUV9E8rOgqBwqlY8ASs/AadbRLb8CzeTjVClqft6FdB17tL7yeCbFRBYoLr6vR/PiSEl5BZJaBD0/R2nkOZqfQ2fsKt+0SEQ+GLSIEUvJm+6jbah2+pS2aon+4g/afd4SYJVuA7vvXdC/IHQtSoTnK+yfAAIEaId1m+vudAAAAAElFTkSuQmCC');background-repeat:no-repeat;background-size:contain}.ipfs-psd{background-image:url('data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAAqxJREFUeNpsU01ME0EYfbtdKKWGtoItRWgJHApCBE2I0YuoiSaaeDJeOJh41YN3TfTixcRwMfEk8eDJGA+Eg0YTTRRMg02KKFooCBbTlkJLS7f7P+u3K9Xo8iWT3Zn55s173/uGM00TVlwZfzJztD92iKO5ouvQGQPHcQDN380vlDPr65fdLj4Oa41i9sFt+ytgN7o7woGOrqgvvpLBaF8vWj1NUAwGTVNRM3mf5vU/zaU+XySQuTqIFXz9hxmGLkoS7r+YxvVnrzGzlgXPDOzUZPT4m3Dt/KlIuH9oUjXYEHZZ/wOgGQZi4TZcGI5hLb+FO++TSOSKcLtcMA0dI0EPrp4+HtnfG5skiUecDGwQE2MjAwiGWlFVNDz+tIyCokJhPKYSX7Gdz2I01hOJdnY9rJ/7UwPGTEiqjtbmJtw4MYx78S/4Wa3h5UoOYwPdIOp2Xi/t18rlFgcDw6o+ydiWVRwOBnCpL0oOAMmNEhLZIgSeoxwGSWcERon/M9DoBknTIdNQNAMnO4PIVGpIFXcwndlA2OtGc4MAxml27p4AIulWSIa9QVadiYSoJxhqBJivKgh5ad3k9gaw6JdlDaqq7q5wINY4F22HaLHSDZQkBW72O9cBYFEviBIURQH7a7MN0uDisUW12ZZcaGlmdq4DwCqeTo1zNtZuW7hUqGIw7MNqSUS2ImNsKEpSdEwt5lGhfQdAkQBEoub3NNrDJfAIeBuRrcrY5xGQ2RFJAjl00I8PCckJUCB9q1URBnk38XEJEuk41tmGwZAf66s1VOh2keqwoUnYpFxHH4iKIixkN3HzVQKP3iQR/5GDKMuYmE3h+fx3MHqh1sMafztHLuiCg0FAk0uFdLqcpGY5QEXbTC/j7mIaVjc18DxufUtBJ/vcggs+3ijVz/0SYABsJHPUtu/OYwAAAABJRU5ErkJggg==');background-repeat:no-repeat;background-size:contain}.ipfs-py{background-image:url('data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAAlVJREFUeNpsUktvEmEUPTPzTUFmgJK2UqXQFG3pA6OBLrQxamJcaYwuu3Dp0l9iXLvVtRuDpgt3JIYaTVSaxtRHsJq2xEJBHgXmifebMhECXzKZme+ee+65516h2+2Cn2cb2VwyHl12//vP2/zOQaF4uD7GWN69e/LogfNm7kUsPBFaXYwHMeK0OlpQEJApHJTuykzK98dE98O0bLM/UNgr4v32Dj1fwSQRt9dSsfmZcMa0rIv9ODaqYrPVxuPnL1Cu1aEbJu7fvIZUIo4bqeVYRzcyv/8c3SPYpwECt/dmu4ON3Ed4TymI+hQc1ZqoE+F+uQLDsnHlwkKMscJTgl4eJOi9fxZLePNhGx6ZQRRFqH4VjZaGSv0Y6cQcJLpra0ZguIWegqDiw7lYBBZV6xiGk9DQDLzK5bEyF4Hi9VLMsoYI7J6Es5PjeHjnOl5ubqHaaJGBEkzbxplQAKIgDmBHekDTgI+qKKqKLvNApgmEgyquLs1CoFn2Y4cIeLJpkjoCLkWnUSIF3JxISIUsCjAoxhWNJLBIJs3YeXj/08oYZkOKY65HllE/bkMmY504YUd40HUq2JSSyW6iVPmLiXE/ZMYQCU+hXK3h1toqdNN0sEObyKtqtDQ6kXDwcadDS2TBryp4nX2HxXjsJK6bDnZIAZem6Tp5YMMmicn5OC4lztNWtvB9cg+hQABtWjKL2jH/T3GgBcYDXEE6mcDM6SlaJAGMWkivLBC54ZgniZaDHSI4rNSqn7/t1vgkGJPwZXffSeCjk2iUWz9+nSTQN8e6ef8EGAClUi/qoiOc3wAAAABJRU5ErkJggg==');background-repeat:no-repeat;background-size:contain}.ipfs-qt{background-image:url('data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAAnVJREFUeNpsU8tu00AUPU5sp41NkzRxpfSZqi0VIIQqEEJUZYXECvbwCWxYsuBD+ABUFrDrCnWBQEJdIWigBSr6pqRJ1ebhxrE9M7aZmSrQ4o505fHMnXPPPWdGiaIIYrx89GKpNDdxmXkU3aEoCsT+z8W1Sm21+jCpJctQTvaerj+TX7WbnJ+0cpfuX8mQtn8GgJ4AZtIFY2Hz3foDVRcgyt+cRHcS0IARh+D/8G0PpmVi7smd0dLs+AIjwTVEiANEYYQwCHlEZyJgIQKfoX84g9uPZ0cHZ4YWmE9nuufU0wABCSSImMsWEgqSuoqA/39/swZFTWLy7vQo7dDnfPvWWQa8GuOV3IYLJXmyzDzG2/ChZ3pwbHdQ267BKJoYuj7SF2MQhiF8LuDK/Gf0DKTBKINz1IbTbEMzU1ANDW7LAfEIQKIgBsBFlAx6LYOz6MAcvoDCtAVGGPKlAiIu/F55F33FDA6W93EOAOMaMOl7biKPwRtD8Foetj5sYPfTDtxjl1f3Ubo5jkQieQ4ACSUD2iE4XDpAdbUiW9D7UsiN9WNkZgxajwbd0LGzt3keAJPUc1N5SVeENT0Ao2BKV6QzwlZeRBSKAYhe3aYHcZWn7l1EfjyPypcK9LQGa8qCvW9j9+MvaasQOHaRhGWdhsNLR8hwodYWf6B4tYjDjSOovRqq32rSYq/lytw4A77o1V2ERiAtzY5kkUrrsH+3QF2KY87ArTtQuQ6nAf4x6FCV1D001+vYersBM2vA4y1Rm2D7/Rac/TZIw4d/6MrcGAPf9htN0miJh7Lyuoyvr8rQeP9iVJcrSKgJ+TrFcyYebXTP/RFgAFQobmIOBxbsAAAAAElFTkSuQmCC');background-repeat:no-repeat;background-size:contain}.ipfs-rar{background-image:url('data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAAnpJREFUeNpsUktPE1EU/u68OgylZXi0hZACQU1LEKKCMcat7jTRnQsXxsQtv4E/4M74P1iriUaNCw1FgxpjCJQKKAU60+m8mJnrmSll4XCTc8+959zz3e88GOcc8aq9evChOHl/lvMoubvWX/z4+BwTlbvw7bXdg8b7h6LE1gGW+O88CRMt4XTlR6/rYxce5Xv3jlHH19fPkBu+gWy5mlcFb3Wn/umeKOEMJF5C7xCFbtA9dRXjFoYKGiTRAlPGUV1aKU9O3VwNQ74A8DQAIZxqAuAhBPIMFYpQVAVB4CPSZjEzv1weH5tbDQN+JQ2Abu488mnzIbAAA3o/VK2PwDJo7r5Fy7ZRuvi4PFS6+qIXdVYD8Jg6BUcuOD8BozSLlRWyicgVKkTMQWwUlFF0Ooe5FIPk57BD7G0SiywyjD8bCDyHsOkeeeR3SUxEkROmU6BfQYFJMHfhWXV8efkUrb13VPMTsrcTQSzxZ/+n0GVA6EGbSGdgG9vo15fg2nFgbO8k70SRdd+mahDT81vUxTZRlJBRMsjq89C0EXCvSf7TIBZ136YZUJEiE7LgJ2dN01BZuE0dkIhxE7KcQTK1QUj+cwAEyrPZ+IydzRoyah+mLy2isbWBweESJEnB9q+1RM9Ub9GQOWkABg8HjRr2d9Yh0hTlBlRsfn+D4vg0BvUC9rZqECUJuk7Tzr1zahCYlB6HJAREPwfbbMBzLBzsbUKVI0qBgQkc+SxgWUYaIAqOpKwKXJ6bgGlaaDV/YvHaFNrtDsKTfVSrJeqIg/bRNwjclFIALeP3saybhu8SC4VBHwnhBXXIKocYRXD9QzBi4Xgchmkd9+L+CTAAMqwy+ZzluBgAAAAASUVORK5CYII=');background-repeat:no-repeat;background-size:contain}.ipfs-rb{background-image:url('data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAAixJREFUeNqEUktvElEU/mag5f2yJhXLwxIt0kiqsVEXujP+A925cu1Pce3WtXVtYuJCF7KtTY0NrVQIpRVKeXTkMcO9F8+9ZVooJJ5kcmbmfOe733fO1YbDIWS8+/g1dycVX7W/xyO3vdsuVKqvnE7HZ230783rlyo7bVBicSGyfjsVwozomVbIPe/c+FmsPHfoRKJd1HT7hXHBZjVbA4aA14NnD9bC2VR8gwuxPi5Sx39Cp+M0XUP0ahhP1jLhW7HFD4zze3b93ILtXYyyVKlR8/5hFbnvO9gtlrGSjOF+OpXkYviWyo8mCS4R6bqO4p86vm3v4fC4DrPfw4unj1XN6JvBaQtjChzUXK43sVU4wNFJA43Tv/B73edQwTmfIhAjCVL6UdPAj1IVFSKhCdAcAI9rnjBiAjtBYEu3GEeh1sKJ0YXR68sVIujzIhzwY8DEBHZqiLRKkicQDfvABxaiQTc4Y/C65pCOXwcjcmlvJgHtlwi4epYifiQWgmoLZwPW6HQG07LgcOgKO0UglAKOTt/E+09fwAiUWU7QAE9xUK3jbvomsispZVHMVEDSZdHo9rCZ/4VIMKAu0XGjpU7d2S8hk0pCELHEzrjKnCQOYJoD+Dxu1RyiwUm5LaMDo9NFt2cqDLvY4oQFp/QpfT/MrmI5FkWebt+NpWto0j2QmQkOjZ9hpwhqjXZzM/+7LU+cc7lRrjXh8/lVLRK5ovLWXglOsiOxdt8/AQYAzv8qbmu6vgEAAAAASUVORK5CYII=');background-repeat:no-repeat;background-size:contain}.ipfs-rtf{background-image:url('data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAAe5JREFUeNqEU01PE0EYfnZmd5FSvgLYFuwWt9EgHyEaox68eDJevHvwJ/hTPHv1N/QgZ2NC4g3kUAQKFKGhjVKqRrvbnRlnht262FHfy+y8877PPM8z71pCCKh4/ebt+rJfXEz26Vjf2mnsN5rPKKWbVpx7+eK5Xu2kyMtNTd5d8MdhiJ9BOO7atFI9ajy1UyAqSPIRMR6ZmoNehNHMMB7fX/UWvEKFMbYKE8DfQnAhwRmmJkbx6M6S5+WmK2Evup2c9yUk2nnKA0XVcSiGXAe1k5beP1i+4RFCXqnPywB/AKVzK34RjHNYlgVKCH50w7EBBogbTa/AVM5SgBdn0gc2AMDjPsbFPz2xye9asweS6n+NTbG8BCCfUtLjff2WoVnVpAH6z6hMUtJE3EykYfpF4vUiL3QNS7FMeSAQRBHW3r1Hq91B+VoBQRji4+ExFsvz6Hz7jm7Yw5OH92AcJKW9G4SoHhzhy/lXbB98Qmm2oCXN5WawsV2TACEoJXqwTKOsb3BtR2ucmZxANpPB8JUhyPnHWDaDpfJ1eZFALzJJ4MKO5MEtv4TSXB7V/br8iQLMz+almRZWbvoo5q9qRlxwewCgeXbe3qrVO5ZkUD/9jJGRLPaOm6COi92TU1DbxYe9umRD0DrrtJO+XwIMABWp9nS+FgaoAAAAAElFTkSuQmCC');background-repeat:no-repeat;background-size:contain}.ipfs-sass{background-image:url('data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAAyJpVFh0WE1MOmNvbS5hZG9iZS54bXAAAAAAADw/eHBhY2tldCBiZWdpbj0i77u/IiBpZD0iVzVNME1wQ2VoaUh6cmVTek5UY3prYzlkIj8+IDx4OnhtcG1ldGEgeG1sbnM6eD0iYWRvYmU6bnM6bWV0YS8iIHg6eG1wdGs9IkFkb2JlIFhNUCBDb3JlIDUuMy1jMDExIDY2LjE0NTY2MSwgMjAxMi8wMi8wNi0xNDo1NjoyNyAgICAgICAgIj4gPHJkZjpSREYgeG1sbnM6cmRmPSJodHRwOi8vd3d3LnczLm9yZy8xOTk5LzAyLzIyLXJkZi1zeW50YXgtbnMjIj4gPHJkZjpEZXNjcmlwdGlvbiByZGY6YWJvdXQ9IiIgeG1sbnM6eG1wPSJodHRwOi8vbnMuYWRvYmUuY29tL3hhcC8xLjAvIiB4bWxuczp4bXBNTT0iaHR0cDovL25zLmFkb2JlLmNvbS94YXAvMS4wL21tLyIgeG1sbnM6c3RSZWY9Imh0dHA6Ly9ucy5hZG9iZS5jb20veGFwLzEuMC9zVHlwZS9SZXNvdXJjZVJlZiMiIHhtcDpDcmVhdG9yVG9vbD0iQWRvYmUgUGhvdG9zaG9wIENTNiAoV2luZG93cykiIHhtcE1NOkluc3RhbmNlSUQ9InhtcC5paWQ6MDNDMTBBM0JGMTE5MTFFMTg3N0NFOTIyMTQ2QzhBNkQiIHhtcE1NOkRvY3VtZW50SUQ9InhtcC5kaWQ6MDNDMTBBM0NGMTE5MTFFMTg3N0NFOTIyMTQ2QzhBNkQiPiA8eG1wTU06RGVyaXZlZEZyb20gc3RSZWY6aW5zdGFuY2VJRD0ieG1wLmlpZDowM0MxMEEzOUYxMTkxMUUxODc3Q0U5MjIxNDZDOEE2RCIgc3RSZWY6ZG9jdW1lbnRJRD0ieG1wLmRpZDowM0MxMEEzQUYxMTkxMUUxODc3Q0U5MjIxNDZDOEE2RCIvPiA8L3JkZjpEZXNjcmlwdGlvbj4gPC9yZGY6UkRGPiA8L3g6eG1wbWV0YT4gPD94cGFja2V0IGVuZD0iciI/Po72XUcAAAJcSURBVHjahFJdTxNBFD1bykc/ttvdtttWGgI0bYrUgDZoNYqRJ014kMRXHvwB/hQTH/wFhMREJfFBQxBjhMRIFEQSCAlQxKYGggiU3e3HbnfX2bFt1EU9k9m9mblz5p4zlzFNExYmpue/jmTSZw5PZAl1MAwDT0c7O72wvPdudeNakPNtOZ0tsM7cvzdOc5yN5LDAsTFRAJks/kC2PxFRVe39Si6f4byez62EpAEH/gNN18F53Ri/Ocxf7OtdLMpKT42s/ZPg1cISJp/P0tg0TBzLCoK8D7eHh4RkLLJ4cCz12AjMXwgez8yhqtVo3NbqRKlcxcSL16gZwJ2Ry8KVc8kZO0HdTKlURn+8G6PD2SZhLMQj96WAiMAh2RXFYKI78lcJcx9WYBCycICnpNbojUWpD5Y0C4Zh2D0w6hWc70uQZC+IWfQZrXF0IsHvY+meBd08haAhoVMMQFJKWF7PNZM+klhRyogGhbqxOIXAMOtEwGAqDqVcgbVkkE+5UsEAWavf0az2t0ZqvK2qabh6IU3joizDwTgwej1LdVfJXkdbK8mt2QkayO99A0/0trQ46I1lVcX+UREhnsP34yLp1AD1xibBMuntpzU8mJyi3Tc1O4+l9U06n7x8Q/8PHz1DrrALt8tlr0CrkbJMHTop9Sk5sLa1g8L+ARJdnShKClY3tunN69t5iGLYTlCtakjFY7gxNABdN3B37BaqqoYT8pyX0in4ORbRkIA46YlDRbUTbBZ2Jb/Pw4qiKFnapcpPo9pdbrg8DjAOBsFgELJmsGs7eWkkc5bu/xBgAHkWC6UPADTOAAAAAElFTkSuQmCC');background-repeat:no-repeat;background-size:contain}.ipfs-scss{background-image:url('data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAAyJpVFh0WE1MOmNvbS5hZG9iZS54bXAAAAAAADw/eHBhY2tldCBiZWdpbj0i77u/IiBpZD0iVzVNME1wQ2VoaUh6cmVTek5UY3prYzlkIj8+IDx4OnhtcG1ldGEgeG1sbnM6eD0iYWRvYmU6bnM6bWV0YS8iIHg6eG1wdGs9IkFkb2JlIFhNUCBDb3JlIDUuMy1jMDExIDY2LjE0NTY2MSwgMjAxMi8wMi8wNi0xNDo1NjoyNyAgICAgICAgIj4gPHJkZjpSREYgeG1sbnM6cmRmPSJodHRwOi8vd3d3LnczLm9yZy8xOTk5LzAyLzIyLXJkZi1zeW50YXgtbnMjIj4gPHJkZjpEZXNjcmlwdGlvbiByZGY6YWJvdXQ9IiIgeG1sbnM6eG1wPSJodHRwOi8vbnMuYWRvYmUuY29tL3hhcC8xLjAvIiB4bWxuczp4bXBNTT0iaHR0cDovL25zLmFkb2JlLmNvbS94YXAvMS4wL21tLyIgeG1sbnM6c3RSZWY9Imh0dHA6Ly9ucy5hZG9iZS5jb20veGFwLzEuMC9zVHlwZS9SZXNvdXJjZVJlZiMiIHhtcDpDcmVhdG9yVG9vbD0iQWRvYmUgUGhvdG9zaG9wIENTNiAoV2luZG93cykiIHhtcE1NOkluc3RhbmNlSUQ9InhtcC5paWQ6RkM4QjYyNDVGMTE4MTFFMTlBREZCNDNEM0ExMTk0MUIiIHhtcE1NOkRvY3VtZW50SUQ9InhtcC5kaWQ6RkM4QjYyNDZGMTE4MTFFMTlBREZCNDNEM0ExMTk0MUIiPiA8eG1wTU06RGVyaXZlZEZyb20gc3RSZWY6aW5zdGFuY2VJRD0ieG1wLmlpZDpGQzhCNjI0M0YxMTgxMUUxOUFERkI0M0QzQTExOTQxQiIgc3RSZWY6ZG9jdW1lbnRJRD0ieG1wLmRpZDpGQzhCNjI0NEYxMTgxMUUxOUFERkI0M0QzQTExOTQxQiIvPiA8L3JkZjpEZXNjcmlwdGlvbj4gPC9yZGY6UkRGPiA8L3g6eG1wbWV0YT4gPD94cGFja2V0IGVuZD0iciI/Pkf1yeMAAAJbSURBVHjahFNdTxNBFD0tLULpB91uodVWPmorUIxo0VSiNSExMYYHE33l0Ud/in+C+OSjYgjRGDBRCKJIUkIEWi0WKlja0ul22+5219lJ26gLeiezuXvn7rnnnrlrUFUVms3Mvd2bjIyezRVLBA0zGAzo6jhjm1te+7EU37rFO+w7JlMbtG+ePJ5mOaZmci/nsPl6ONBtw18WDQc9tZq0sp7YjTisXV/NFKRpRvzHpHodDqsF03djzuvDg6vHJWFAprF/Arxe/oins6+YryoqCiUBvNOO+7FrXMjnWc0WyIAOQP0N4Nn8IqqSzPx2swllsYqZl28gK8DDyRvcxKXQvB6gISYpiwgH+jEVi7YAfW4nEqk0PJwDofNejAX7Pae2sPhhHQoF63U5Gai2Bn1epoPWmmaKoug1UBoMrgwHabIVVCx2jdrKFwm67TZ2plldPQGg2cK5HheIUMbaZqKV9In6giDCy3MNYXECgKI2gICxoQAEsQItpNCHWKngMo01arTY/jFIzbutShJuXh1Fm9FImYiM7tTtKOtbO+toN9Nc+fQ5SGUOIVYl7HzPIH2YRZ0y2KZ+sVzBHn2v1mpMGx0DTaR3nzfwfGEJdybGkdo/wEigDyvxLzg4yiESvojZhfd49OAeLJ2degaSLIPOO6vwgiYaaRErTRREEdn8MeJbSVZ5M7nLdNExqFLaQwEfFfACQn1+HBWKSKb3MT4Sgstuh9vVDa+bQ4DORE6o6RlspzMk9TOPfr+fiLJCLFYr3TZSKNcI7+aJwWQmPM+TkqRg49tu65f/JcAAMwMas6WUKd8AAAAASUVORK5CYII=');background-repeat:no-repeat;background-size:contain}.ipfs-sql{background-image:url('data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAAh5JREFUeNp8kctrE1EUxr+ZyXMkoa1NBROaSkpTBE23PhZ25cql2y5duvAPUdGFS1FxIRRBXZlFQ9GVdDENIhGJxkDsw2mneZnM83ruNZlOmNoDhzlzz3d/9zv3Sowx8Ch/qlYK2XM3cEJsbH0+qjV/rd6/u6aN18b7RMFT+9aosP/Ex+0ae/puw7j36PlKEMAzctKJ3aGFamMHjV0d+wcGitkMrpWWp6hVIciEk2MAOwbUWjosx0UiFoWqJpGMx5DNzODq5aIPoa82AWBg/lyKLMH1PMp/a9XvLXLzG1cuFlBaWpiKxaIPSLY6CaC93ggQjyiQZRkeQSzLRovGaPciWLt5faSWEBoh6KBvOhiaNga0+Y9pwaFxvu7rfp8F5pWDt+qNMp2IijHGwddWCvN+33/CoAOP5nVdT9SdoQ1JkggiQ6Yvr7V60+9z7akA2gfH9cRF8hO5F5Ve4lQAF9uuK+qFsylkzsQxrcaQm04hdWkR83Mzfp9rQ3fAFzu9Ph6+WMfjl6/pGBdb2jbKmx8QlRjWy5vkyhUZBPgOeGNHN9AbDLGUz6He2hVj3Ll9C8/evsdgaMK0HV8bcmDTU0UUBYXcedR+NLGnH0I3jvDk1Rsy46FP4C/1BtrdntCGHNiOAzWZgEKQ5Qt5lIqLojbaXSQTcRy2OwT4SZqk0IYAOgkVWUE+lxX/zb0DpFNpkTzmZmfFtzewhHYcfwUYAMZmVaZQlLFHAAAAAElFTkSuQmCC');background-repeat:no-repeat;background-size:contain}.ipfs-tga{background-image:url('data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAAnxJREFUeNp0U89PE0EU/ra725K22ILRGipb22pMG6JcSEQTbUIwnozxpBcvepeEP0KPogcT/wlNT17kIKbEmChFUYKGVtL0R2gLtNCl3Z1Z3+zSAlonmezOe/O+973vvZEsy4JYnqdPMu6RkSQYQ29JEkB+PZcrslrtPhQl23VZc8/tr9I1yMHg0EA8HrBM04lVFAhoY38fSSDQVN3pfKV8G7KcxZHl6v1xblqU3eLc3p2VFZjr6+gQgwsnhzGTuq6Nhs6kYZqXjwL0GFhEl3U60OfnwWs1GGtrUKNRsKkpeIIBpKIRtI1J7cX7hXRhc/MOhXw5DkCZGG2zXAajzFIoBMvng1ypIKOqmP30GW3OIEcimovzlxRy5RgAFwDEAIODkCcmIMdiQLsNdWwMZdJlg8pzEUt1aBhKq3XinxKYqF9yQbqRIqsMy+0Gyy47bKgUWXSLtDENE5wdtuqQATm50F1VnPbRGeEw8HXZbiV8fsDvI9ldju9vADAyihLEbrWAZhOoVp3z6iqBUiB1A4nEfwCEsbkL/M4TgE5n5jDx+oTEzp1d8m9tC8H6MaAB0imzx0NU/WKUYE+loEyawDBo2ui6TGfT6ANAxrvx87gYCGCxXEKVJvCWFsG3eh1vN/J4OD6Od4UC8o0G3TX7TGLHwI9iEQmvF9X6Fh7F4/iYy+GcLOMSlfEgGsP0qdNOmX0BiGKpVkV1bw/1nW2b/gCpf1PTcI+Y7eg6ps+G4bG4PR99SjAVo9HE4q+fKNE0vl5awuSohjeijbRefVjAtUgEQRK7Yhi9OKn7nKWZxxlSPWl3QwgnaIrW8QMhD542vUbx/W49m7sq4v4IMABOqi3Ej7bAEAAAAABJRU5ErkJggg==');background-repeat:no-repeat;background-size:contain}.ipfs-tgz{background-image:url('data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAAnhJREFUeNpsU1trE0EYPbMzSTfdtInFtkkpiaXVWou2FRUEn/so6JugL/oH/Af+B1988if40jcFERQURNBSQdDWlLQN2lsue8neZsZvc7FoOrDszM75znfOmVmmtUYyvry++36yfOeS1qqzDtvH2P76ApPlW3Drb2sHex/uccHWAdbZX30kO2+B3siN3zhTnHuQ66+95i423jzFzOVljBdKOZNHazvVT7e5wF+SZBj9iZJ+3J11mbW2kR8T4LwFli5i4fqTUvnczTUp9RLtDhKgJx0q4dEwWAxrREKICHEsoYYXMXvlcWmquLgmY71yCkG/c0AkARgLMZpnMDMpGNzEYe0dGp6HwvmHpbHC1Wf9MnFCkHQOyYEPzSJwQ2B65Tm5NZG3Fshim6wbMNJn4bpHowMKtIqo2COgR2IcAptwjvcgo6i77igjEmVDqbY8xQJ1VwRULhiBI6+G9Zf3cbTziuzIDkmHSNqECTFgQScEcYuc2NA8TcdYwXD+GkK/TYVN+u72WrIudiAD8o6oAR2RRCmQMjis3CIy1iSpPySCXhFTXeyAgh4BR+JVw8pauLi0Cp4yCX9A90FQhnSBYtnF/k+Q+HYam9itfIZB3QvT8zj8XSW5EhNTs9ivbSLwPUzPLNPJBIMEKnaQYg6aB9+RGR5F5VsNgnNKXMI1NdJGG5WfHzFVLJ7k8c8xUngpVodlDSGbFYj8Y4yMpOG09lHf3yIFPzA3fwHZTAQVtU4JUTeFDrdgDdlI8wAz5Qy2KxswReI7QODZcOr0ZH3q2hIDBI7zq16tuk3FNPxAI4wN+pkoccYoE4YJU5EdUtM4Qst26v26PwIMAKj3P/2YUKgYAAAAAElFTkSuQmCC');background-repeat:no-repeat;background-size:contain}.ipfs-tiff{background-image:url('data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAAmRJREFUeNp0UktPE1EU/qYzHWstlrYJNcWUElyUJsaNGh9B0g1Lo0v9Ey78EbrVxBhXuHShm25YGBJRQpAYBDEWpaEPEhksdVpbyjzveO4MfZDCTWbauefc736PIziOA77OPH2yJCcSGdg2uksQAKofFou/7VrtASRpvVNynj13f6XOhjg8HAlMTIQdy/LO+v3uYUPTkAHCTb+cK+0pdyGK6+hbvu4/xiyHbncYAwfR19ZgbG/DoO9LsSgeTd9JXoxfyMG2rvQDdBlwIZauQ5ufh12twioU4E+nYU1NIRCNIDs+Bt28mXzx8VNuZ796j9q/DgAwomwqClilAmF0FE4wCInAlkjO4y+r0JgNX2os6XPYS2q/cQyAcQatFjA0BPH6NYipccAwIGUy2CVJFZInkKlyJAqx3T4/IMGmJkeWIWSz5KgI5pdhb3yDXS5DSCYh8rTID8s0wexeVD0GtMd85KkkefFxUfE47M1NokbJkByEQl6tL+ouAI+MUwbFhnYbaJKc/Sqg0x4H4eDRGDA56fUOABA9/GsCpaIHwr8FOhQ823O5RfW66tUGADhNy3RNRDjcN41HLxdQ8J6jYTsOQLfOJBK4f+s2/uoathoNGKT1MtFeVHZxdWTEZfEq/wMKl3rCJOIzTV6ADs2R5ulYDDNkYjp0DhrF+zCVgkw31+v1UxjQZkNV0SADd2o1MIuc9gmY+/kLxb0/UFoHePd9A1qzeUoKpilx9xcLWzgg+u/zeVfuQqkM9bCN1ysrWKXxdtPgvScwUAm58XZ52W16QyPtifRUzi588GbEi1ztHPsvwAC4uC9qhnsZvwAAAABJRU5ErkJggg==');background-repeat:no-repeat;background-size:contain}.ipfs-txt{background-image:url('data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAAeJJREFUeNp8UrtOG1EQPfsyXiyzBguIJSyChZBBEFCKpKHLo6egpErNn8CHgH8gkZIiTSIXLhJAWCgkoMgRMSiRBSK29z4y9+I1d/HCrFb3MTPnnjkzlpQSynY+fP70fGF2gQuByCz6lfdd9Uurfvrrjes6762eb3tzQ69uFJwPsqOPC+MBEmxxphi4tlU5OGmsOzaBWLc+O9oIIVhScidkyGZ8vH62nHtSKlaI4cse6TjAfSaFBBcco0EWqyvzubmpyQrj/FXk75cQaSEMeMXU8xykPA/Hjd/6/LRcyjEpt2i7HAe4A2TeLZWKUOJaVLxj27j813EHGKCXaAJExu/4BOdiAED08riQD2riOrexyRoYc3CvsAbLGAAjZga7vgZG23WMCdBvoxKJc36TRBlMiaa2JByjNqqD8qkYc1pjDK7abey+/YhrWlfKswhpiCR96aEU9o5+QE3g2ovVWDm2Sc22bBQm8vrVpbkS9r+doPr1EOWZaQ0yFoxg2PcREosEAI4uvZhJpzFMP+cSXRbq+043RManez+tNWKMI6GN0g0Z04HFR+NoNC/0yx717efZOSbzY3AcR4Op2AGA5p/W31r9e0vNgSrh9OwCrpeCkqvZuqTybnpRqx/r2CjvvwADAJC/7lzAzQmwAAAAAElFTkSuQmCC');background-repeat:no-repeat;background-size:contain}.ipfs-wav{background-image:url('data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAApFJREFUeNpsU1tPE0EYPXtpKbX0wqUQKVQMFdIXQBNCQBs06KP+B8ODGh+Mf4b/4IsGE54kxhcMBrkp7YOQgBRvSKG73fvsrt8Otoask0xmd+b7zpxzvm8E3/cRjPkniyulW0NFy2JoDkEAguOlpXJ9p3L8MBqVl4O9YHxae8pXuRlcGO7KPLhfTDVUqwUgigJMy4Whm6lEXHjxYf3XnByRN0QB/2KaH7btMlUxoRJAcyqKhdOaht7+DJ49n+2cvTnwynXcsb+kLwJ4rgfmMDDGWqvneXCZS9ND7mov5h9ND85M9y86Dpto5rUkuJ4Py3YDJpy6QGJPayqB+Njf+43XL220t0cwOZkfrNXsBUqZugDA6CbLdAiAwaek1ZU9LmP8Rh6S78GsGxjOp9FdzKJaVZIhBgGASzK21w/wbrnCk8euX+EMAjaaZuPHdwUdHVFYluuGPGCORwwYjg5rqOwccRk+3Ux0IEvntmsNG4ZmUayL/wAwKHUNfZfTKN0ZRaw9Cof8qJ/pMAyHy5KkAMTksSEJtnMenM7EMVMawbejMzJRh67bXEYiIXEAVTW50SEAhzqwfqrBcXx4VOhYm4RsNgHbsJFOyZTsQ1MN+hcohoUlkFiMT+TQFpMwXOjGpXgE+XwGk1N5pFJtKNCequgYGupCRBbCDOp0KBJc4VoP3dyBONW8uydBgBHUThqQKCk3mEZ/LoUG+RBioJO7VarAwEAntjYPiUUW9Hh4b2R7k9j98hN37xWx8fGAt3eIAdVMLn+uUv+b2KReSCZjZJiB9bV9jIz2ofr1BKvvd7G9dRC80lae0HzOt+cWVnrSKDrMJykifwNBpCgE/UAllEXufmDu8Zlffvvm8XSQ90eAAQA0pF7c08o4PAAAAABJRU5ErkJggg==');background-repeat:no-repeat;background-size:contain}.ipfs-xls{background-image:url('data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAAmxJREFUeNpsU0trFEEQ/mamZ3Y2+0zIC2MmITEkUYgERFQErx5E8KTi1b/h79A/4SW3nCNeYggBYZVEMU/y3N3Z7M7OTD/G6lk2ruw20zRdU/XV91VVG0mSQK/3n1a/jky6d6Xs3G8WXS+Pw5N6LXjLLGuna/78oZKerGsYKtrDE16uJGL1L9gEOOcYd2dL1fNwrbL//aXN7J1efPMmkUqEFAk0A0VZNbFEaQCBscIkXj975y3NLq9xye8PBkAniHOFph+j2eC4rsdoB4LsFubGl/Hq8RtvYWpxTQi52o1jvWiGYaRZL0/auDgOkC/Z8BYL2Pqxidp1FZkhoDxpeaXA/Ujuj/4HoOxKKjiOiek7RUShRNQWaNYFQuMafrYCxiw4ozZKfqbYJ0EvRdl1DQyyTs8XCNTA6UELMwvDyLpZWIZNNlNLlQOK2LMJRJ+5AkuZ1S7CFFzJzk56GnUjQWlYkqCoBWFbonEVYcLLA4dNnB624GQsDBWIgfZJEgxkoChzSFWvn4VpQemDm2VwXQsXJwF1h6c+gxlQ5jgSiEUEt0wdIe7tMES+nEG2aCLiJMOIIWIr9e0DEELAMUrwRuchVAyTKimUwO75Jm6VF3Bv7imOaj+xd7UFKVS/BPJF1b/E4tgTrE49J60O5kceoNqowiuuYKa8ghHXA48U9MT2AQgyRvTThE30bQiaSGa4yLMJNFo+Dq/2cHt4CYlwyFf2S6BHwwrMw/avDbR5C1k7h1YQ4KH3Amf+AcZyEbZPv9CItzQD1l9EbtYOjv74v/d3O9RMPTDrsEwGIWN8q2yk7XNYRs9JrRv3V4ABADSGR6eQ0/NQAAAAAElFTkSuQmCC');background-repeat:no-repeat;background-size:contain}.ipfs-xlsx{background-image:url('data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAAmlJREFUeNpsU8tqFEEUPVXdPY/ueWZIoiYZiSYKYhJc6EbduHOhgijo3t/wH1z6B0JAhOyMILhxo4kJGk1ASTAxwWF0Mpp5dHc9vFUzYwidaoqmq+8959xzbzGtNcx69PTS26ETmQtS9r4Hy/xv7MW7jV+th5yzVcaYPX/++It9u4NAv+CVR6tBUUTqMJsDcRzjZOZM8W9ZLKx+/XDb4e5/kH5In0lpIYWGUaC0YTZnBCAEKoVR3L36oDo7NbsglZwbqD6iQKOXFMcKUVfBkBAoQhlD5xxMDp/HrSv3q1JgYW3z0x0KXzkCYJaRZljru23aHWTzLiamAyytv0O9UYdf5PArqlppBfMUfu4oALErqZBKcUxMFRCHEp0DgW5Lo4N9NIN1dF0XXsVFOUyPJTzo+WBANDidjp8tgHGG3c0DnJ4uIRf4cOCBaW5KjY8xkZL72xpJ9QcFz5bVqHUJGHZL2YtNmKi06YCyiVFb4s/vEKMTAf1p4edOG6mMi1zR6wEpdUwX+vLDtkCzHoK7ptcM6ayLmGajvtex4PliyoIkFRjmUEASelB2rXQRSfjUCT9PlWpmW21iTGzCAyEkUixPRqXhe2V4zKczbdmybgkpJ0cGOuA6Y2MTCsKoi5HsNK7N3MN+uwYaWbxYfoLLkzdxcew6lrYWaZhm8PHHG3zffp1UwJSHz9vvkU8PodbcQYYYS5lxYkxTkGdVDQdV1Js1qPgYD6JIuIE7gsXVefIhIuM05k7dwMbeMmh87a18ufIMaVYyprrJLgje2Nr+1tzYXANnDnr3zRhHj37Vvy2wpXHtNAd5/wQYAD6WMuT2CwoVAAAAAElFTkSuQmCC');background-repeat:no-repeat;background-size:contain}.ipfs-xml{background-image:url('data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAAilJREFUeNqMks1PE0EYxh+g3W2t1G0sEqyISynUFJsSOShNwCamiYZED3LgIkcuxoN/iCZePZiYGD2aGD+i0F5KMChxlVaakAK2ykcAt+WzdLu7zkxo3WZL4pu8mXfmeeY3885ug67roPFh5nvc62m9hjoR+5LMp7MrkYf370qVtco+VtCUFpbj+jGR+JbWn76OyQ8ePwsZATQb8R/hanZgINgj9IqeuBFCw1Kt9OMBnNWCs24XwkG/QKYUEiGjVAPQof/rq0783pShET3ULQo8xz0iS5FaANmrHQH2DoqY+DSLSz6RzecWlnD9ymU47LYjd4O5BXqDTG4FM3NpTEkpdJ5rw0AowLRMbhUfp58gTOaD/UHmNQPI6YmvKWRX1zESHUJ/oBs2nmPa+Mgw0ZIM3tZyGoJwygzQNB2jNyJIZX7iB0lpPoM70UGmPX8zCU+rG8NDVxHwdiC5mKsPUFUN/gvtLLf39sFzVqaN3YrC6TjBauqhXhNA1TQoqloV7Da+pjZq1FsXUCamF29j6LvYhf3iISamZ3Fv9DZevouhRzzPfOG+3hpA9U9UyioOlTJ7pFeTCQS6RGzIebyf+oz5pSzWtmSW1EO9phvQ00slBRt/8qR3DoWdXbiczUiTzd52D+tdLmyTB14mx1rMAKVcRpEATjrsuElee/HXGmnFRyBOGD30C/nEDjNgs7CDpsYmnHG3YPegBCvHs9oYfm8nG9dJa5X4K8AAQzQX4KSN3wcAAAAASUVORK5CYII=');background-repeat:no-repeat;background-size:contain}.ipfs-yml{background-image:url('data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAAdxJREFUeNqMUl1rE0EUPbM7m5Y0Zptu21AwWwhYpfSDFh+kvvRd8N0Hf4I/xWdf/Q158F0QoQ+CVsFKaLSQpt/dpmvztTOzzky6cetOpWcZZvbO3MO5514SxzEU3r57/3GpWllM/tP4sL3TarROXuSo/SWJvX71Uu80Cfhlr/T4UdWFAVfdnmsTUtvdP35OUyQKVnJgXDBTcj9icAsTeLax7j/052qM81UjwW1QJXEhMF0qYnN90fdnvdogYmvJPU0/VBApD4hcDrWRcyikfB17srzgW7b9Rh1vEvxDlI4tVytaBSEEtmWh0xsUMwpwnWjqAlcxogiHd1wiQyCu87iI/+sJtf6+NXsgpd7FWCMB50KvkYMGMbLdZgLlfj+K9K4+FnFQ2x7WntIs50AbmiGwLILt+k+EvzvSNIHzdigdJ/AmXQRhiHv5POSwYmG+cqPVo0HqDxj8uTK2vn1Hfa+JmdIkvtZ/4fOPXU3WPDpFeNWVyUKryCiIGMN4zsH98gym3CIcOTwT+XHdXrdQQHAZotE8kBPpSqPNHtBOr48HUmLOcXRJT9dWNMGYJFby91pHOAvaykSaITg+bwefdhrteDRTMSwyrFCgI88E056Hy+4Ah2cXQZL3R4ABALUe7fqXWFN6AAAAAElFTkSuQmCC');background-repeat:no-repeat;background-size:contain}.ipfs-zip{background-image:url('data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAAm9JREFUeNpsk0tv00AUhc+MY6dOmgeFJg1FoVVpUWlFC0s2IFF1jxBbhKj4BSxYdscPYcEmQmIDq0gsERIViy4TpD7VFzF1Ho5je2a4thOqNhlp5Mz4zudzzp0wpRTC8fPrk0/TC6+fDtYicLH97T1Kc2vQDcs+rH3eUAxVznn0fn1DRM8E+iOdv5ct3XmZG6yVlNj6solUbgVTt0q5FGtX6vXqC6VklTE+KAO/OODHSIQPRQpsXC+kkEz2ELA0ystv84tLzyucsbWByisAGf+QAS2CCDRRLMJMmxC+i8C4jdLCm/zM7OOKFGptcO6/BTpJ0yeQB0Y+mfKQuZZG0jQgeRbW8Xdomobs9LN8scc+UPHNy4Dwq8IljotIIQEm59/RoSyM1CKkXKZNBm7kIVgyM6wgAnSgRK9vqQfHPiMFDHqyFVsLR9Cm0o4YzoAASrSjCelQfRPb1Vc4qn0EY5L2W9GEaBLcxQgFHpGbkMIDJ69e+wjJ8VXqRgKid0r7ftQdxkRs9SqA2kgAm14SSIQh9uhuLGPMnKJs/5KquL1x0N0RCsizigoDaLqBdHoMiyvrlBsHVx1wphD4BCewoqxGKKDwAgtOy8JufYuk+5golGGaGZwc1sIGoDz3AOPZSVLaHgVwydoJDM1H4DbQODughB3YpOD44HfoHgnu4e7So0uAi0stHLJ3Aud8B9bpHu6vPoSu9TtDl6tUuoFiIYOgu0+158MKmOxomtyD3Qi/3MTR7i8K0EDG1GHO5DE3X4DvNahZlJOwEkOATvdPc2//hx3mXJ5lFJaF8K8bStd0YGfnOJbMGex21x6c+yfAAOlIPDJzr7cLAAAAAElFTkSuQmCC');background-repeat:no-repeat;background-size:contain}
8 - .narrow {width: 0px;}
9 - .padding { margin: 100px;}
10 - #header {
11 - background: #000;
12 - }
13 - #logo {
14 - height: 25px;
15 - margin: 10px;
16 - }
17 - .ipfs-icon {
18 - width:16px;
19 - }
20 - </style>
21 - <title>{{ .Path }}</title>
22 -</head>
23 -<body>
24 - <div id="header" class="row">
25 - <div class="col-xs-2">
26 - <div id="logo" class="ipfs-logo">&nbsp;</div>
27 - </div>
28 - </div>
29 - <br/>
30 - <div class="col-xs-12">
31 - <div class="panel panel-default">
32 - <div class="panel-heading">
33 - <strong>Index of {{ .Path }}</strong>
34 - </div>
35 - <table class="table table-striped">
36 - <tr>
37 - <td class="narrow">
38 - <div class="ipfs-icon ipfs-_blank">&nbsp;</div>
39 - </td>
40 - <td class="padding">
41 - <a href="{{.BackLink}}">..</a>
42 - </td>
43 - <td></td>
44 - </tr>
45 - {{ range .Listing }}
46 - <tr>
47 - <td>
48 - <div class="ipfs-icon {{iconFromExt .Name}}">&nbsp;</div>
49 - </td>
50 - <td>
51 - <a href="{{ .Path }}">{{ .Name }}</a>
52 - </td>
53 - <td>{{ .Size }}</td>
54 - </tr>
55 - {{ end }}
56 - </table>
57 - </div>
58 - </div>
59 -</body>
60 -</html>
vendor/QmdDfkqDWheE4gsCXNrhixwTwSHnZMPT2cGLcNbiBNcMyU/dir-index-html/gw-assets/bootstrap.min.css deleted
-5
@@ -1,5 +0,0 @@
1 -/*!
2 - * Bootstrap v3.3.4 (http://getbootstrap.com)
3 - * Copyright 2011-2015 Twitter, Inc.
4 - * Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE)
5 - *//*! normalize.css v3.0.2 | MIT License | git.io/normalize */html{font-family:sans-serif;-webkit-text-size-adjust:100%;-ms-text-size-adjust:100%}body{margin:0}article,aside,details,figcaption,figure,footer,header,hgroup,main,menu,nav,section,summary{display:block}audio,canvas,progress,video{display:inline-block;vertical-align:baseline}audio:not([controls]){display:none;height:0}[hidden],template{display:none}a{background-color:transparent}a:active,a:hover{outline:0}abbr[title]{border-bottom:1px dotted}b,strong{font-weight:700}dfn{font-style:italic}h1{margin:.67em 0;font-size:2em}mark{color:#000;background:#ff0}small{font-size:80%}sub,sup{position:relative;font-size:75%;line-height:0;vertical-align:baseline}sup{top:-.5em}sub{bottom:-.25em}img{border:0}svg:not(:root){overflow:hidden}figure{margin:1em 40px}hr{height:0;-webkit-box-sizing:content-box;-moz-box-sizing:content-box;box-sizing:content-box}pre{overflow:auto}code,kbd,pre,samp{font-family:monospace,monospace;font-size:1em}button,input,optgroup,select,textarea{margin:0;font:inherit;color:inherit}button{overflow:visible}button,select{text-transform:none}button,html input[type=button],input[type=reset],input[type=submit]{-webkit-appearance:button;cursor:pointer}button[disabled],html input[disabled]{cursor:default}button::-moz-focus-inner,input::-moz-focus-inner{padding:0;border:0}input{line-height:normal}input[type=checkbox],input[type=radio]{-webkit-box-sizing:border-box;-moz-box-sizing:border-box;box-sizing:border-box;padding:0}input[type=number]::-webkit-inner-spin-button,input[type=number]::-webkit-outer-spin-button{height:auto}input[type=search]{-webkit-box-sizing:content-box;-moz-box-sizing:content-box;box-sizing:content-box;-webkit-appearance:textfield}input[type=search]::-webkit-search-cancel-button,input[type=search]::-webkit-search-decoration{-webkit-appearance:none}fieldset{padding:.35em .625em .75em;margin:0 2px;border:1px solid silver}legend{padding:0;border:0}textarea{overflow:auto}optgroup{font-weight:700}table{border-spacing:0;border-collapse:collapse}td,th{padding:0}/*! Source: https://github.com/h5bp/html5-boilerplate/blob/master/src/css/main.css */@media print{*,:after,:before{color:#000!important;text-shadow:none!important;background:0 0!important;-webkit-box-shadow:none!important;box-shadow:none!important}a,a:visited{text-decoration:underline}a[href]:after{content:" (" attr(href) ")"}abbr[title]:after{content:" (" attr(title) ")"}a[href^="javascript:"]:after,a[href^="#"]:after{content:""}blockquote,pre{border:1px solid #999;page-break-inside:avoid}thead{display:table-header-group}img,tr{page-break-inside:avoid}img{max-width:100%!important}h2,h3,p{orphans:3;widows:3}h2,h3{page-break-after:avoid}select{background:#fff!important}.navbar{display:none}.btn>.caret,.dropup>.btn>.caret{border-top-color:#000!important}.label{border:1px solid #000}.table{border-collapse:collapse!important}.table td,.table th{background-color:#fff!important}.table-bordered td,.table-bordered th{border:1px solid #ddd!important}}@font-face{font-family:'Glyphicons Halflings';src:url(../fonts/glyphicons-halflings-regular.eot);src:url(../fonts/glyphicons-halflings-regular.eot?#iefix) format('embedded-opentype'),url(../fonts/glyphicons-halflings-regular.woff2) format('woff2'),url(../fonts/glyphicons-halflings-regular.woff) format('woff'),url(../fonts/glyphicons-halflings-regular.ttf) format('truetype'),url(../fonts/glyphicons-halflings-regular.svg#glyphicons_halflingsregular) format('svg')}.glyphicon{position:relative;top:1px;display:inline-block;font-family:'Glyphicons Halflings';font-style:normal;font-weight:400;line-height:1;-webkit-font-smoothing:antialiased;-moz-osx-font-smoothing:grayscale}.glyphicon-asterisk:before{content:"\2a"}.glyphicon-plus:before{content:"\2b"}.glyphicon-eur:before,.glyphicon-euro:before{content:"\20ac"}.glyphicon-minus:before{content:"\2212"}.glyphicon-cloud:before{content:"\2601"}.glyphicon-envelope:before{content:"\2709"}.glyphicon-pencil:before{content:"\270f"}.glyphicon-glass:before{content:"\e001"}.glyphicon-music:before{content:"\e002"}.glyphicon-search:before{content:"\e003"}.glyphicon-heart:before{content:"\e005"}.glyphicon-star:before{content:"\e006"}.glyphicon-star-empty:before{content:"\e007"}.glyphicon-user:before{content:"\e008"}.glyphicon-film:before{content:"\e009"}.glyphicon-th-large:before{content:"\e010"}.glyphicon-th:before{content:"\e011"}.glyphicon-th-list:before{content:"\e012"}.glyphicon-ok:before{content:"\e013"}.glyphicon-remove:before{content:"\e014"}.glyphicon-zoom-in:before{content:"\e015"}.glyphicon-zoom-out:before{content:"\e016"}.glyphicon-off:before{content:"\e017"}.glyphicon-signal:before{content:"\e018"}.glyphicon-cog:before{content:"\e019"}.glyphicon-trash:before{content:"\e020"}.glyphicon-home:before{content:"\e021"}.glyphicon-file:before{content:"\e022"}.glyphicon-time:before{content:"\e023"}.glyphicon-road:before{content:"\e024"}.glyphicon-download-alt:before{content:"\e025"}.glyphicon-download:before{content:"\e026"}.glyphicon-upload:before{content:"\e027"}.glyphicon-inbox:before{content:"\e028"}.glyphicon-play-circle:before{content:"\e029"}.glyphicon-repeat:before{content:"\e030"}.glyphicon-refresh:before{content:"\e031"}.glyphicon-list-alt:before{content:"\e032"}.glyphicon-lock:before{content:"\e033"}.glyphicon-flag:before{content:"\e034"}.glyphicon-headphones:before{content:"\e035"}.glyphicon-volume-off:before{content:"\e036"}.glyphicon-volume-down:before{content:"\e037"}.glyphicon-volume-up:before{content:"\e038"}.glyphicon-qrcode:before{content:"\e039"}.glyphicon-barcode:before{content:"\e040"}.glyphicon-tag:before{content:"\e041"}.glyphicon-tags:before{content:"\e042"}.glyphicon-book:before{content:"\e043"}.glyphicon-bookmark:before{content:"\e044"}.glyphicon-print:before{content:"\e045"}.glyphicon-camera:before{content:"\e046"}.glyphicon-font:before{content:"\e047"}.glyphicon-bold:before{content:"\e048"}.glyphicon-italic:before{content:"\e049"}.glyphicon-text-height:before{content:"\e050"}.glyphicon-text-width:before{content:"\e051"}.glyphicon-align-left:before{content:"\e052"}.glyphicon-align-center:before{content:"\e053"}.glyphicon-align-right:before{content:"\e054"}.glyphicon-align-justify:before{content:"\e055"}.glyphicon-list:before{content:"\e056"}.glyphicon-indent-left:before{content:"\e057"}.glyphicon-indent-right:before{content:"\e058"}.glyphicon-facetime-video:before{content:"\e059"}.glyphicon-picture:before{content:"\e060"}.glyphicon-map-marker:before{content:"\e062"}.glyphicon-adjust:before{content:"\e063"}.glyphicon-tint:before{content:"\e064"}.glyphicon-edit:before{content:"\e065"}.glyphicon-share:before{content:"\e066"}.glyphicon-check:before{content:"\e067"}.glyphicon-move:before{content:"\e068"}.glyphicon-step-backward:before{content:"\e069"}.glyphicon-fast-backward:before{content:"\e070"}.glyphicon-backward:before{content:"\e071"}.glyphicon-play:before{content:"\e072"}.glyphicon-pause:before{content:"\e073"}.glyphicon-stop:before{content:"\e074"}.glyphicon-forward:before{content:"\e075"}.glyphicon-fast-forward:before{content:"\e076"}.glyphicon-step-forward:before{content:"\e077"}.glyphicon-eject:before{content:"\e078"}.glyphicon-chevron-left:before{content:"\e079"}.glyphicon-chevron-right:before{content:"\e080"}.glyphicon-plus-sign:before{content:"\e081"}.glyphicon-minus-sign:before{content:"\e082"}.glyphicon-remove-sign:before{content:"\e083"}.glyphicon-ok-sign:before{content:"\e084"}.glyphicon-question-sign:before{content:"\e085"}.glyphicon-info-sign:before{content:"\e086"}.glyphicon-screenshot:before{content:"\e087"}.glyphicon-remove-circle:before{content:"\e088"}.glyphicon-ok-circle:before{content:"\e089"}.glyphicon-ban-circle:before{content:"\e090"}.glyphicon-arrow-left:before{content:"\e091"}.glyphicon-arrow-right:before{content:"\e092"}.glyphicon-arrow-up:before{content:"\e093"}.glyphicon-arrow-down:before{content:"\e094"}.glyphicon-share-alt:before{content:"\e095"}.glyphicon-resize-full:before{content:"\e096"}.glyphicon-resize-small:before{content:"\e097"}.glyphicon-exclamation-sign:before{content:"\e101"}.glyphicon-gift:before{content:"\e102"}.glyphicon-leaf:before{content:"\e103"}.glyphicon-fire:before{content:"\e104"}.glyphicon-eye-open:before{content:"\e105"}.glyphicon-eye-close:before{content:"\e106"}.glyphicon-warning-sign:before{content:"\e107"}.glyphicon-plane:before{content:"\e108"}.glyphicon-calendar:before{content:"\e109"}.glyphicon-random:before{content:"\e110"}.glyphicon-comment:before{content:"\e111"}.glyphicon-magnet:before{content:"\e112"}.glyphicon-chevron-up:before{content:"\e113"}.glyphicon-chevron-down:before{content:"\e114"}.glyphicon-retweet:before{content:"\e115"}.glyphicon-shopping-cart:before{content:"\e116"}.glyphicon-folder-close:before{content:"\e117"}.glyphicon-folder-open:before{content:"\e118"}.glyphicon-resize-vertical:before{content:"\e119"}.glyphicon-resize-horizontal:before{content:"\e120"}.glyphicon-hdd:before{content:"\e121"}.glyphicon-bullhorn:before{content:"\e122"}.glyphicon-bell:before{content:"\e123"}.glyphicon-certificate:before{content:"\e124"}.glyphicon-thumbs-up:before{content:"\e125"}.glyphicon-thumbs-down:before{content:"\e126"}.glyphicon-hand-right:before{content:"\e127"}.glyphicon-hand-left:before{content:"\e128"}.glyphicon-hand-up:before{content:"\e129"}.glyphicon-hand-down:before{content:"\e130"}.glyphicon-circle-arrow-right:before{content:"\e131"}.glyphicon-circle-arrow-left:before{content:"\e132"}.glyphicon-circle-arrow-up:before{content:"\e133"}.glyphicon-circle-arrow-down:before{content:"\e134"}.glyphicon-globe:before{content:"\e135"}.glyphicon-wrench:before{content:"\e136"}.glyphicon-tasks:before{content:"\e137"}.glyphicon-filter:before{content:"\e138"}.glyphicon-briefcase:before{content:"\e139"}.glyphicon-fullscreen:before{content:"\e140"}.glyphicon-dashboard:before{content:"\e141"}.glyphicon-paperclip:before{content:"\e142"}.glyphicon-heart-empty:before{content:"\e143"}.glyphicon-link:before{content:"\e144"}.glyphicon-phone:before{content:"\e145"}.glyphicon-pushpin:before{content:"\e146"}.glyphicon-usd:before{content:"\e148"}.glyphicon-gbp:before{content:"\e149"}.glyphicon-sort:before{content:"\e150"}.glyphicon-sort-by-alphabet:before{content:"\e151"}.glyphicon-sort-by-alphabet-alt:before{content:"\e152"}.glyphicon-sort-by-order:before{content:"\e153"}.glyphicon-sort-by-order-alt:before{content:"\e154"}.glyphicon-sort-by-attributes:before{content:"\e155"}.glyphicon-sort-by-attributes-alt:before{content:"\e156"}.glyphicon-unchecked:before{content:"\e157"}.glyphicon-expand:before{content:"\e158"}.glyphicon-collapse-down:before{content:"\e159"}.glyphicon-collapse-up:before{content:"\e160"}.glyphicon-log-in:before{content:"\e161"}.glyphicon-flash:before{content:"\e162"}.glyphicon-log-out:before{content:"\e163"}.glyphicon-new-window:before{content:"\e164"}.glyphicon-record:before{content:"\e165"}.glyphicon-save:before{content:"\e166"}.glyphicon-open:before{content:"\e167"}.glyphicon-saved:before{content:"\e168"}.glyphicon-import:before{content:"\e169"}.glyphicon-export:before{content:"\e170"}.glyphicon-send:before{content:"\e171"}.glyphicon-floppy-disk:before{content:"\e172"}.glyphicon-floppy-saved:before{content:"\e173"}.glyphicon-floppy-remove:before{content:"\e174"}.glyphicon-floppy-save:before{content:"\e175"}.glyphicon-floppy-open:before{content:"\e176"}.glyphicon-credit-card:before{content:"\e177"}.glyphicon-transfer:before{content:"\e178"}.glyphicon-cutlery:before{content:"\e179"}.glyphicon-header:before{content:"\e180"}.glyphicon-compressed:before{content:"\e181"}.glyphicon-earphone:before{content:"\e182"}.glyphicon-phone-alt:before{content:"\e183"}.glyphicon-tower:before{content:"\e184"}.glyphicon-stats:before{content:"\e185"}.glyphicon-sd-video:before{content:"\e186"}.glyphicon-hd-video:before{content:"\e187"}.glyphicon-subtitles:before{content:"\e188"}.glyphicon-sound-stereo:before{content:"\e189"}.glyphicon-sound-dolby:before{content:"\e190"}.glyphicon-sound-5-1:before{content:"\e191"}.glyphicon-sound-6-1:before{content:"\e192"}.glyphicon-sound-7-1:before{content:"\e193"}.glyphicon-copyright-mark:before{content:"\e194"}.glyphicon-registration-mark:before{content:"\e195"}.glyphicon-cloud-download:before{content:"\e197"}.glyphicon-cloud-upload:before{content:"\e198"}.glyphicon-tree-conifer:before{content:"\e199"}.glyphicon-tree-deciduous:before{content:"\e200"}.glyphicon-cd:before{content:"\e201"}.glyphicon-save-file:before{content:"\e202"}.glyphicon-open-file:before{content:"\e203"}.glyphicon-level-up:before{content:"\e204"}.glyphicon-copy:before{content:"\e205"}.glyphicon-paste:before{content:"\e206"}.glyphicon-alert:before{content:"\e209"}.glyphicon-equalizer:before{content:"\e210"}.glyphicon-king:before{content:"\e211"}.glyphicon-queen:before{content:"\e212"}.glyphicon-pawn:before{content:"\e213"}.glyphicon-bishop:before{content:"\e214"}.glyphicon-knight:before{content:"\e215"}.glyphicon-baby-formula:before{content:"\e216"}.glyphicon-tent:before{content:"\26fa"}.glyphicon-blackboard:before{content:"\e218"}.glyphicon-bed:before{content:"\e219"}.glyphicon-apple:before{content:"\f8ff"}.glyphicon-erase:before{content:"\e221"}.glyphicon-hourglass:before{content:"\231b"}.glyphicon-lamp:before{content:"\e223"}.glyphicon-duplicate:before{content:"\e224"}.glyphicon-piggy-bank:before{content:"\e225"}.glyphicon-scissors:before{content:"\e226"}.glyphicon-bitcoin:before{content:"\e227"}.glyphicon-btc:before{content:"\e227"}.glyphicon-xbt:before{content:"\e227"}.glyphicon-yen:before{content:"\00a5"}.glyphicon-jpy:before{content:"\00a5"}.glyphicon-ruble:before{content:"\20bd"}.glyphicon-rub:before{content:"\20bd"}.glyphicon-scale:before{content:"\e230"}.glyphicon-ice-lolly:before{content:"\e231"}.glyphicon-ice-lolly-tasted:before{content:"\e232"}.glyphicon-education:before{content:"\e233"}.glyphicon-option-horizontal:before{content:"\e234"}.glyphicon-option-vertical:before{content:"\e235"}.glyphicon-menu-hamburger:before{content:"\e236"}.glyphicon-modal-window:before{content:"\e237"}.glyphicon-oil:before{content:"\e238"}.glyphicon-grain:before{content:"\e239"}.glyphicon-sunglasses:before{content:"\e240"}.glyphicon-text-size:before{content:"\e241"}.glyphicon-text-color:before{content:"\e242"}.glyphicon-text-background:before{content:"\e243"}.glyphicon-object-align-top:before{content:"\e244"}.glyphicon-object-align-bottom:before{content:"\e245"}.glyphicon-object-align-horizontal:before{content:"\e246"}.glyphicon-object-align-left:before{content:"\e247"}.glyphicon-object-align-vertical:before{content:"\e248"}.glyphicon-object-align-right:before{content:"\e249"}.glyphicon-triangle-right:before{content:"\e250"}.glyphicon-triangle-left:before{content:"\e251"}.glyphicon-triangle-bottom:before{content:"\e252"}.glyphicon-triangle-top:before{content:"\e253"}.glyphicon-console:before{content:"\e254"}.glyphicon-superscript:before{content:"\e255"}.glyphicon-subscript:before{content:"\e256"}.glyphicon-menu-left:before{content:"\e257"}.glyphicon-menu-right:before{content:"\e258"}.glyphicon-menu-down:before{content:"\e259"}.glyphicon-menu-up:before{content:"\e260"}*{-webkit-box-sizing:border-box;-moz-box-sizing:border-box;box-sizing:border-box}:after,:before{-webkit-box-sizing:border-box;-moz-box-sizing:border-box;box-sizing:border-box}html{font-size:10px;-webkit-tap-highlight-color:rgba(0,0,0,0)}body{font-family:"Helvetica Neue",Helvetica,Arial,sans-serif;font-size:14px;line-height:1.42857143;color:#333;background-color:#fff}button,input,select,textarea{font-family:inherit;font-size:inherit;line-height:inherit}a{color:#337ab7;text-decoration:none}a:focus,a:hover{color:#23527c;text-decoration:underline}a:focus{outline:thin dotted;outline:5px auto -webkit-focus-ring-color;outline-offset:-2px}figure{margin:0}img{vertical-align:middle}.carousel-inner>.item>a>img,.carousel-inner>.item>img,.img-responsive,.thumbnail a>img,.thumbnail>img{display:block;max-width:100%;height:auto}.img-rounded{border-radius:6px}.img-thumbnail{display:inline-block;max-width:100%;height:auto;padding:4px;line-height:1.42857143;background-color:#fff;border:1px solid #ddd;border-radius:4px;-webkit-transition:all .2s ease-in-out;-o-transition:all .2s ease-in-out;transition:all .2s ease-in-out}.img-circle{border-radius:50%}hr{margin-top:20px;margin-bottom:20px;border:0;border-top:1px solid #eee}.sr-only{position:absolute;width:1px;height:1px;padding:0;margin:-1px;overflow:hidden;clip:rect(0,0,0,0);border:0}.sr-only-focusable:active,.sr-only-focusable:focus{position:static;width:auto;height:auto;margin:0;overflow:visible;clip:auto}[role=button]{cursor:pointer}.h1,.h2,.h3,.h4,.h5,.h6,h1,h2,h3,h4,h5,h6{font-family:inherit;font-weight:500;line-height:1.1;color:inherit}.h1 .small,.h1 small,.h2 .small,.h2 small,.h3 .small,.h3 small,.h4 .small,.h4 small,.h5 .small,.h5 small,.h6 .small,.h6 small,h1 .small,h1 small,h2 .small,h2 small,h3 .small,h3 small,h4 .small,h4 small,h5 .small,h5 small,h6 .small,h6 small{font-weight:400;line-height:1;color:#777}.h1,.h2,.h3,h1,h2,h3{margin-top:20px;margin-bottom:10px}.h1 .small,.h1 small,.h2 .small,.h2 small,.h3 .small,.h3 small,h1 .small,h1 small,h2 .small,h2 small,h3 .small,h3 small{font-size:65%}.h4,.h5,.h6,h4,h5,h6{margin-top:10px;margin-bottom:10px}.h4 .small,.h4 small,.h5 .small,.h5 small,.h6 .small,.h6 small,h4 .small,h4 small,h5 .small,h5 small,h6 .small,h6 small{font-size:75%}.h1,h1{font-size:36px}.h2,h2{font-size:30px}.h3,h3{font-size:24px}.h4,h4{font-size:18px}.h5,h5{font-size:14px}.h6,h6{font-size:12px}p{margin:0 0 10px}.lead{margin-bottom:20px;font-size:16px;font-weight:300;line-height:1.4}@media (min-width:768px){.lead{font-size:21px}}.small,small{font-size:85%}.mark,mark{padding:.2em;background-color:#fcf8e3}.text-left{text-align:left}.text-right{text-align:right}.text-center{text-align:center}.text-justify{text-align:justify}.text-nowrap{white-space:nowrap}.text-lowercase{text-transform:lowercase}.text-uppercase{text-transform:uppercase}.text-capitalize{text-transform:capitalize}.text-muted{color:#777}.text-primary{color:#337ab7}a.text-primary:hover{color:#286090}.text-success{color:#3c763d}a.text-success:hover{color:#2b542c}.text-info{color:#31708f}a.text-info:hover{color:#245269}.text-warning{color:#8a6d3b}a.text-warning:hover{color:#66512c}.text-danger{color:#a94442}a.text-danger:hover{color:#843534}.bg-primary{color:#fff;background-color:#337ab7}a.bg-primary:hover{background-color:#286090}.bg-success{background-color:#dff0d8}a.bg-success:hover{background-color:#c1e2b3}.bg-info{background-color:#d9edf7}a.bg-info:hover{background-color:#afd9ee}.bg-warning{background-color:#fcf8e3}a.bg-warning:hover{background-color:#f7ecb5}.bg-danger{background-color:#f2dede}a.bg-danger:hover{background-color:#e4b9b9}.page-header{padding-bottom:9px;margin:40px 0 20px;border-bottom:1px solid #eee}ol,ul{margin-top:0;margin-bottom:10px}ol ol,ol ul,ul ol,ul ul{margin-bottom:0}.list-unstyled{padding-left:0;list-style:none}.list-inline{padding-left:0;margin-left:-5px;list-style:none}.list-inline>li{display:inline-block;padding-right:5px;padding-left:5px}dl{margin-top:0;margin-bottom:20px}dd,dt{line-height:1.42857143}dt{font-weight:700}dd{margin-left:0}@media (min-width:768px){.dl-horizontal dt{float:left;width:160px;overflow:hidden;clear:left;text-align:right;text-overflow:ellipsis;white-space:nowrap}.dl-horizontal dd{margin-left:180px}}abbr[data-original-title],abbr[title]{cursor:help;border-bottom:1px dotted #777}.initialism{font-size:90%;text-transform:uppercase}blockquote{padding:10px 20px;margin:0 0 20px;font-size:17.5px;border-left:5px solid #eee}blockquote ol:last-child,blockquote p:last-child,blockquote ul:last-child{margin-bottom:0}blockquote .small,blockquote footer,blockquote small{display:block;font-size:80%;line-height:1.42857143;color:#777}blockquote .small:before,blockquote footer:before,blockquote small:before{content:'\2014 \00A0'}.blockquote-reverse,blockquote.pull-right{padding-right:15px;padding-left:0;text-align:right;border-right:5px solid #eee;border-left:0}.blockquote-reverse .small:before,.blockquote-reverse footer:before,.blockquote-reverse small:before,blockquote.pull-right .small:before,blockquote.pull-right footer:before,blockquote.pull-right small:before{content:''}.blockquote-reverse .small:after,.blockquote-reverse footer:after,.blockquote-reverse small:after,blockquote.pull-right .small:after,blockquote.pull-right footer:after,blockquote.pull-right small:after{content:'\00A0 \2014'}address{margin-bottom:20px;font-style:normal;line-height:1.42857143}code,kbd,pre,samp{font-family:Menlo,Monaco,Consolas,"Courier New",monospace}code{padding:2px 4px;font-size:90%;color:#c7254e;background-color:#f9f2f4;border-radius:4px}kbd{padding:2px 4px;font-size:90%;color:#fff;background-color:#333;border-radius:3px;-webkit-box-shadow:inset 0 -1px 0 rgba(0,0,0,.25);box-shadow:inset 0 -1px 0 rgba(0,0,0,.25)}kbd kbd{padding:0;font-size:100%;font-weight:700;-webkit-box-shadow:none;box-shadow:none}pre{display:block;padding:9.5px;margin:0 0 10px;font-size:13px;line-height:1.42857143;color:#333;word-break:break-all;word-wrap:break-word;background-color:#f5f5f5;border:1px solid #ccc;border-radius:4px}pre code{padding:0;font-size:inherit;color:inherit;white-space:pre-wrap;background-color:transparent;border-radius:0}.pre-scrollable{max-height:340px;overflow-y:scroll}.container{padding-right:15px;padding-left:15px;margin-right:auto;margin-left:auto}@media (min-width:768px){.container{width:750px}}@media (min-width:992px){.container{width:970px}}@media (min-width:1200px){.container{width:1170px}}.container-fluid{padding-right:15px;padding-left:15px;margin-right:auto;margin-left:auto}.row{margin-right:-15px;margin-left:-15px}.col-lg-1,.col-lg-10,.col-lg-11,.col-lg-12,.col-lg-2,.col-lg-3,.col-lg-4,.col-lg-5,.col-lg-6,.col-lg-7,.col-lg-8,.col-lg-9,.col-md-1,.col-md-10,.col-md-11,.col-md-12,.col-md-2,.col-md-3,.col-md-4,.col-md-5,.col-md-6,.col-md-7,.col-md-8,.col-md-9,.col-sm-1,.col-sm-10,.col-sm-11,.col-sm-12,.col-sm-2,.col-sm-3,.col-sm-4,.col-sm-5,.col-sm-6,.col-sm-7,.col-sm-8,.col-sm-9,.col-xs-1,.col-xs-10,.col-xs-11,.col-xs-12,.col-xs-2,.col-xs-3,.col-xs-4,.col-xs-5,.col-xs-6,.col-xs-7,.col-xs-8,.col-xs-9{position:relative;min-height:1px;padding-right:15px;padding-left:15px}.col-xs-1,.col-xs-10,.col-xs-11,.col-xs-12,.col-xs-2,.col-xs-3,.col-xs-4,.col-xs-5,.col-xs-6,.col-xs-7,.col-xs-8,.col-xs-9{float:left}.col-xs-12{width:100%}.col-xs-11{width:91.66666667%}.col-xs-10{width:83.33333333%}.col-xs-9{width:75%}.col-xs-8{width:66.66666667%}.col-xs-7{width:58.33333333%}.col-xs-6{width:50%}.col-xs-5{width:41.66666667%}.col-xs-4{width:33.33333333%}.col-xs-3{width:25%}.col-xs-2{width:16.66666667%}.col-xs-1{width:8.33333333%}.col-xs-pull-12{right:100%}.col-xs-pull-11{right:91.66666667%}.col-xs-pull-10{right:83.33333333%}.col-xs-pull-9{right:75%}.col-xs-pull-8{right:66.66666667%}.col-xs-pull-7{right:58.33333333%}.col-xs-pull-6{right:50%}.col-xs-pull-5{right:41.66666667%}.col-xs-pull-4{right:33.33333333%}.col-xs-pull-3{right:25%}.col-xs-pull-2{right:16.66666667%}.col-xs-pull-1{right:8.33333333%}.col-xs-pull-0{right:auto}.col-xs-push-12{left:100%}.col-xs-push-11{left:91.66666667%}.col-xs-push-10{left:83.33333333%}.col-xs-push-9{left:75%}.col-xs-push-8{left:66.66666667%}.col-xs-push-7{left:58.33333333%}.col-xs-push-6{left:50%}.col-xs-push-5{left:41.66666667%}.col-xs-push-4{left:33.33333333%}.col-xs-push-3{left:25%}.col-xs-push-2{left:16.66666667%}.col-xs-push-1{left:8.33333333%}.col-xs-push-0{left:auto}.col-xs-offset-12{margin-left:100%}.col-xs-offset-11{margin-left:91.66666667%}.col-xs-offset-10{margin-left:83.33333333%}.col-xs-offset-9{margin-left:75%}.col-xs-offset-8{margin-left:66.66666667%}.col-xs-offset-7{margin-left:58.33333333%}.col-xs-offset-6{margin-left:50%}.col-xs-offset-5{margin-left:41.66666667%}.col-xs-offset-4{margin-left:33.33333333%}.col-xs-offset-3{margin-left:25%}.col-xs-offset-2{margin-left:16.66666667%}.col-xs-offset-1{margin-left:8.33333333%}.col-xs-offset-0{margin-left:0}@media (min-width:768px){.col-sm-1,.col-sm-10,.col-sm-11,.col-sm-12,.col-sm-2,.col-sm-3,.col-sm-4,.col-sm-5,.col-sm-6,.col-sm-7,.col-sm-8,.col-sm-9{float:left}.col-sm-12{width:100%}.col-sm-11{width:91.66666667%}.col-sm-10{width:83.33333333%}.col-sm-9{width:75%}.col-sm-8{width:66.66666667%}.col-sm-7{width:58.33333333%}.col-sm-6{width:50%}.col-sm-5{width:41.66666667%}.col-sm-4{width:33.33333333%}.col-sm-3{width:25%}.col-sm-2{width:16.66666667%}.col-sm-1{width:8.33333333%}.col-sm-pull-12{right:100%}.col-sm-pull-11{right:91.66666667%}.col-sm-pull-10{right:83.33333333%}.col-sm-pull-9{right:75%}.col-sm-pull-8{right:66.66666667%}.col-sm-pull-7{right:58.33333333%}.col-sm-pull-6{right:50%}.col-sm-pull-5{right:41.66666667%}.col-sm-pull-4{right:33.33333333%}.col-sm-pull-3{right:25%}.col-sm-pull-2{right:16.66666667%}.col-sm-pull-1{right:8.33333333%}.col-sm-pull-0{right:auto}.col-sm-push-12{left:100%}.col-sm-push-11{left:91.66666667%}.col-sm-push-10{left:83.33333333%}.col-sm-push-9{left:75%}.col-sm-push-8{left:66.66666667%}.col-sm-push-7{left:58.33333333%}.col-sm-push-6{left:50%}.col-sm-push-5{left:41.66666667%}.col-sm-push-4{left:33.33333333%}.col-sm-push-3{left:25%}.col-sm-push-2{left:16.66666667%}.col-sm-push-1{left:8.33333333%}.col-sm-push-0{left:auto}.col-sm-offset-12{margin-left:100%}.col-sm-offset-11{margin-left:91.66666667%}.col-sm-offset-10{margin-left:83.33333333%}.col-sm-offset-9{margin-left:75%}.col-sm-offset-8{margin-left:66.66666667%}.col-sm-offset-7{margin-left:58.33333333%}.col-sm-offset-6{margin-left:50%}.col-sm-offset-5{margin-left:41.66666667%}.col-sm-offset-4{margin-left:33.33333333%}.col-sm-offset-3{margin-left:25%}.col-sm-offset-2{margin-left:16.66666667%}.col-sm-offset-1{margin-left:8.33333333%}.col-sm-offset-0{margin-left:0}}@media (min-width:992px){.col-md-1,.col-md-10,.col-md-11,.col-md-12,.col-md-2,.col-md-3,.col-md-4,.col-md-5,.col-md-6,.col-md-7,.col-md-8,.col-md-9{float:left}.col-md-12{width:100%}.col-md-11{width:91.66666667%}.col-md-10{width:83.33333333%}.col-md-9{width:75%}.col-md-8{width:66.66666667%}.col-md-7{width:58.33333333%}.col-md-6{width:50%}.col-md-5{width:41.66666667%}.col-md-4{width:33.33333333%}.col-md-3{width:25%}.col-md-2{width:16.66666667%}.col-md-1{width:8.33333333%}.col-md-pull-12{right:100%}.col-md-pull-11{right:91.66666667%}.col-md-pull-10{right:83.33333333%}.col-md-pull-9{right:75%}.col-md-pull-8{right:66.66666667%}.col-md-pull-7{right:58.33333333%}.col-md-pull-6{right:50%}.col-md-pull-5{right:41.66666667%}.col-md-pull-4{right:33.33333333%}.col-md-pull-3{right:25%}.col-md-pull-2{right:16.66666667%}.col-md-pull-1{right:8.33333333%}.col-md-pull-0{right:auto}.col-md-push-12{left:100%}.col-md-push-11{left:91.66666667%}.col-md-push-10{left:83.33333333%}.col-md-push-9{left:75%}.col-md-push-8{left:66.66666667%}.col-md-push-7{left:58.33333333%}.col-md-push-6{left:50%}.col-md-push-5{left:41.66666667%}.col-md-push-4{left:33.33333333%}.col-md-push-3{left:25%}.col-md-push-2{left:16.66666667%}.col-md-push-1{left:8.33333333%}.col-md-push-0{left:auto}.col-md-offset-12{margin-left:100%}.col-md-offset-11{margin-left:91.66666667%}.col-md-offset-10{margin-left:83.33333333%}.col-md-offset-9{margin-left:75%}.col-md-offset-8{margin-left:66.66666667%}.col-md-offset-7{margin-left:58.33333333%}.col-md-offset-6{margin-left:50%}.col-md-offset-5{margin-left:41.66666667%}.col-md-offset-4{margin-left:33.33333333%}.col-md-offset-3{margin-left:25%}.col-md-offset-2{margin-left:16.66666667%}.col-md-offset-1{margin-left:8.33333333%}.col-md-offset-0{margin-left:0}}@media (min-width:1200px){.col-lg-1,.col-lg-10,.col-lg-11,.col-lg-12,.col-lg-2,.col-lg-3,.col-lg-4,.col-lg-5,.col-lg-6,.col-lg-7,.col-lg-8,.col-lg-9{float:left}.col-lg-12{width:100%}.col-lg-11{width:91.66666667%}.col-lg-10{width:83.33333333%}.col-lg-9{width:75%}.col-lg-8{width:66.66666667%}.col-lg-7{width:58.33333333%}.col-lg-6{width:50%}.col-lg-5{width:41.66666667%}.col-lg-4{width:33.33333333%}.col-lg-3{width:25%}.col-lg-2{width:16.66666667%}.col-lg-1{width:8.33333333%}.col-lg-pull-12{right:100%}.col-lg-pull-11{right:91.66666667%}.col-lg-pull-10{right:83.33333333%}.col-lg-pull-9{right:75%}.col-lg-pull-8{right:66.66666667%}.col-lg-pull-7{right:58.33333333%}.col-lg-pull-6{right:50%}.col-lg-pull-5{right:41.66666667%}.col-lg-pull-4{right:33.33333333%}.col-lg-pull-3{right:25%}.col-lg-pull-2{right:16.66666667%}.col-lg-pull-1{right:8.33333333%}.col-lg-pull-0{right:auto}.col-lg-push-12{left:100%}.col-lg-push-11{left:91.66666667%}.col-lg-push-10{left:83.33333333%}.col-lg-push-9{left:75%}.col-lg-push-8{left:66.66666667%}.col-lg-push-7{left:58.33333333%}.col-lg-push-6{left:50%}.col-lg-push-5{left:41.66666667%}.col-lg-push-4{left:33.33333333%}.col-lg-push-3{left:25%}.col-lg-push-2{left:16.66666667%}.col-lg-push-1{left:8.33333333%}.col-lg-push-0{left:auto}.col-lg-offset-12{margin-left:100%}.col-lg-offset-11{margin-left:91.66666667%}.col-lg-offset-10{margin-left:83.33333333%}.col-lg-offset-9{margin-left:75%}.col-lg-offset-8{margin-left:66.66666667%}.col-lg-offset-7{margin-left:58.33333333%}.col-lg-offset-6{margin-left:50%}.col-lg-offset-5{margin-left:41.66666667%}.col-lg-offset-4{margin-left:33.33333333%}.col-lg-offset-3{margin-left:25%}.col-lg-offset-2{margin-left:16.66666667%}.col-lg-offset-1{margin-left:8.33333333%}.col-lg-offset-0{margin-left:0}}table{background-color:transparent}caption{padding-top:8px;padding-bottom:8px;color:#777;text-align:left}th{text-align:left}.table{width:100%;max-width:100%;margin-bottom:20px}.table>tbody>tr>td,.table>tbody>tr>th,.table>tfoot>tr>td,.table>tfoot>tr>th,.table>thead>tr>td,.table>thead>tr>th{padding:8px;line-height:1.42857143;vertical-align:top;border-top:1px solid #ddd}.table>thead>tr>th{vertical-align:bottom;border-bottom:2px solid #ddd}.table>caption+thead>tr:first-child>td,.table>caption+thead>tr:first-child>th,.table>colgroup+thead>tr:first-child>td,.table>colgroup+thead>tr:first-child>th,.table>thead:first-child>tr:first-child>td,.table>thead:first-child>tr:first-child>th{border-top:0}.table>tbody+tbody{border-top:2px solid #ddd}.table .table{background-color:#fff}.table-condensed>tbody>tr>td,.table-condensed>tbody>tr>th,.table-condensed>tfoot>tr>td,.table-condensed>tfoot>tr>th,.table-condensed>thead>tr>td,.table-condensed>thead>tr>th{padding:5px}.table-bordered{border:1px solid #ddd}.table-bordered>tbody>tr>td,.table-bordered>tbody>tr>th,.table-bordered>tfoot>tr>td,.table-bordered>tfoot>tr>th,.table-bordered>thead>tr>td,.table-bordered>thead>tr>th{border:1px solid #ddd}.table-bordered>thead>tr>td,.table-bordered>thead>tr>th{border-bottom-width:2px}.table-striped>tbody>tr:nth-of-type(odd){background-color:#f9f9f9}.table-hover>tbody>tr:hover{background-color:#f5f5f5}table col[class*=col-]{position:static;display:table-column;float:none}table td[class*=col-],table th[class*=col-]{position:static;display:table-cell;float:none}.table>tbody>tr.active>td,.table>tbody>tr.active>th,.table>tbody>tr>td.active,.table>tbody>tr>th.active,.table>tfoot>tr.active>td,.table>tfoot>tr.active>th,.table>tfoot>tr>td.active,.table>tfoot>tr>th.active,.table>thead>tr.active>td,.table>thead>tr.active>th,.table>thead>tr>td.active,.table>thead>tr>th.active{background-color:#f5f5f5}.table-hover>tbody>tr.active:hover>td,.table-hover>tbody>tr.active:hover>th,.table-hover>tbody>tr:hover>.active,.table-hover>tbody>tr>td.active:hover,.table-hover>tbody>tr>th.active:hover{background-color:#e8e8e8}.table>tbody>tr.success>td,.table>tbody>tr.success>th,.table>tbody>tr>td.success,.table>tbody>tr>th.success,.table>tfoot>tr.success>td,.table>tfoot>tr.success>th,.table>tfoot>tr>td.success,.table>tfoot>tr>th.success,.table>thead>tr.success>td,.table>thead>tr.success>th,.table>thead>tr>td.success,.table>thead>tr>th.success{background-color:#dff0d8}.table-hover>tbody>tr.success:hover>td,.table-hover>tbody>tr.success:hover>th,.table-hover>tbody>tr:hover>.success,.table-hover>tbody>tr>td.success:hover,.table-hover>tbody>tr>th.success:hover{background-color:#d0e9c6}.table>tbody>tr.info>td,.table>tbody>tr.info>th,.table>tbody>tr>td.info,.table>tbody>tr>th.info,.table>tfoot>tr.info>td,.table>tfoot>tr.info>th,.table>tfoot>tr>td.info,.table>tfoot>tr>th.info,.table>thead>tr.info>td,.table>thead>tr.info>th,.table>thead>tr>td.info,.table>thead>tr>th.info{background-color:#d9edf7}.table-hover>tbody>tr.info:hover>td,.table-hover>tbody>tr.info:hover>th,.table-hover>tbody>tr:hover>.info,.table-hover>tbody>tr>td.info:hover,.table-hover>tbody>tr>th.info:hover{background-color:#c4e3f3}.table>tbody>tr.warning>td,.table>tbody>tr.warning>th,.table>tbody>tr>td.warning,.table>tbody>tr>th.warning,.table>tfoot>tr.warning>td,.table>tfoot>tr.warning>th,.table>tfoot>tr>td.warning,.table>tfoot>tr>th.warning,.table>thead>tr.warning>td,.table>thead>tr.warning>th,.table>thead>tr>td.warning,.table>thead>tr>th.warning{background-color:#fcf8e3}.table-hover>tbody>tr.warning:hover>td,.table-hover>tbody>tr.warning:hover>th,.table-hover>tbody>tr:hover>.warning,.table-hover>tbody>tr>td.warning:hover,.table-hover>tbody>tr>th.warning:hover{background-color:#faf2cc}.table>tbody>tr.danger>td,.table>tbody>tr.danger>th,.table>tbody>tr>td.danger,.table>tbody>tr>th.danger,.table>tfoot>tr.danger>td,.table>tfoot>tr.danger>th,.table>tfoot>tr>td.danger,.table>tfoot>tr>th.danger,.table>thead>tr.danger>td,.table>thead>tr.danger>th,.table>thead>tr>td.danger,.table>thead>tr>th.danger{background-color:#f2dede}.table-hover>tbody>tr.danger:hover>td,.table-hover>tbody>tr.danger:hover>th,.table-hover>tbody>tr:hover>.danger,.table-hover>tbody>tr>td.danger:hover,.table-hover>tbody>tr>th.danger:hover{background-color:#ebcccc}.table-responsive{min-height:.01%;overflow-x:auto}@media screen and (max-width:767px){.table-responsive{width:100%;margin-bottom:15px;overflow-y:hidden;-ms-overflow-style:-ms-autohiding-scrollbar;border:1px solid #ddd}.table-responsive>.table{margin-bottom:0}.table-responsive>.table>tbody>tr>td,.table-responsive>.table>tbody>tr>th,.table-responsive>.table>tfoot>tr>td,.table-responsive>.table>tfoot>tr>th,.table-responsive>.table>thead>tr>td,.table-responsive>.table>thead>tr>th{white-space:nowrap}.table-responsive>.table-bordered{border:0}.table-responsive>.table-bordered>tbody>tr>td:first-child,.table-responsive>.table-bordered>tbody>tr>th:first-child,.table-responsive>.table-bordered>tfoot>tr>td:first-child,.table-responsive>.table-bordered>tfoot>tr>th:first-child,.table-responsive>.table-bordered>thead>tr>td:first-child,.table-responsive>.table-bordered>thead>tr>th:first-child{border-left:0}.table-responsive>.table-bordered>tbody>tr>td:last-child,.table-responsive>.table-bordered>tbody>tr>th:last-child,.table-responsive>.table-bordered>tfoot>tr>td:last-child,.table-responsive>.table-bordered>tfoot>tr>th:last-child,.table-responsive>.table-bordered>thead>tr>td:last-child,.table-responsive>.table-bordered>thead>tr>th:last-child{border-right:0}.table-responsive>.table-bordered>tbody>tr:last-child>td,.table-responsive>.table-bordered>tbody>tr:last-child>th,.table-responsive>.table-bordered>tfoot>tr:last-child>td,.table-responsive>.table-bordered>tfoot>tr:last-child>th{border-bottom:0}}fieldset{min-width:0;padding:0;margin:0;border:0}legend{display:block;width:100%;padding:0;margin-bottom:20px;font-size:21px;line-height:inherit;color:#333;border:0;border-bottom:1px solid #e5e5e5}label{display:inline-block;max-width:100%;margin-bottom:5px;font-weight:700}input[type=search]{-webkit-box-sizing:border-box;-moz-box-sizing:border-box;box-sizing:border-box}input[type=checkbox],input[type=radio]{margin:4px 0 0;margin-top:1px \9;line-height:normal}input[type=file]{display:block}input[type=range]{display:block;width:100%}select[multiple],select[size]{height:auto}input[type=file]:focus,input[type=checkbox]:focus,input[type=radio]:focus{outline:thin dotted;outline:5px auto -webkit-focus-ring-color;outline-offset:-2px}output{display:block;padding-top:7px;font-size:14px;line-height:1.42857143;color:#555}.form-control{display:block;width:100%;height:34px;padding:6px 12px;font-size:14px;line-height:1.42857143;color:#555;background-color:#fff;background-image:none;border:1px solid #ccc;border-radius:4px;-webkit-box-shadow:inset 0 1px 1px rgba(0,0,0,.075);box-shadow:inset 0 1px 1px rgba(0,0,0,.075);-webkit-transition:border-color ease-in-out .15s,-webkit-box-shadow ease-in-out .15s;-o-transition:border-color ease-in-out .15s,box-shadow ease-in-out .15s;transition:border-color ease-in-out .15s,box-shadow ease-in-out .15s}.form-control:focus{border-color:#66afe9;outline:0;-webkit-box-shadow:inset 0 1px 1px rgba(0,0,0,.075),0 0 8px rgba(102,175,233,.6);box-shadow:inset 0 1px 1px rgba(0,0,0,.075),0 0 8px rgba(102,175,233,.6)}.form-control::-moz-placeholder{color:#999;opacity:1}.form-control:-ms-input-placeholder{color:#999}.form-control::-webkit-input-placeholder{color:#999}.form-control[disabled],.form-control[readonly],fieldset[disabled] .form-control{background-color:#eee;opacity:1}.form-control[disabled],fieldset[disabled] .form-control{cursor:not-allowed}textarea.form-control{height:auto}input[type=search]{-webkit-appearance:none}@media screen and (-webkit-min-device-pixel-ratio:0){input[type=date],input[type=time],input[type=datetime-local],input[type=month]{line-height:34px}.input-group-sm input[type=date],.input-group-sm input[type=time],.input-group-sm input[type=datetime-local],.input-group-sm input[type=month],input[type=date].input-sm,input[type=time].input-sm,input[type=datetime-local].input-sm,input[type=month].input-sm{line-height:30px}.input-group-lg input[type=date],.input-group-lg input[type=time],.input-group-lg input[type=datetime-local],.input-group-lg input[type=month],input[type=date].input-lg,input[type=time].input-lg,input[type=datetime-local].input-lg,input[type=month].input-lg{line-height:46px}}.form-group{margin-bottom:15px}.checkbox,.radio{position:relative;display:block;margin-top:10px;margin-bottom:10px}.checkbox label,.radio label{min-height:20px;padding-left:20px;margin-bottom:0;font-weight:400;cursor:pointer}.checkbox input[type=checkbox],.checkbox-inline input[type=checkbox],.radio input[type=radio],.radio-inline input[type=radio]{position:absolute;margin-top:4px \9;margin-left:-20px}.checkbox+.checkbox,.radio+.radio{margin-top:-5px}.checkbox-inline,.radio-inline{position:relative;display:inline-block;padding-left:20px;margin-bottom:0;font-weight:400;vertical-align:middle;cursor:pointer}.checkbox-inline+.checkbox-inline,.radio-inline+.radio-inline{margin-top:0;margin-left:10px}fieldset[disabled] input[type=checkbox],fieldset[disabled] input[type=radio],input[type=checkbox].disabled,input[type=checkbox][disabled],input[type=radio].disabled,input[type=radio][disabled]{cursor:not-allowed}.checkbox-inline.disabled,.radio-inline.disabled,fieldset[disabled] .checkbox-inline,fieldset[disabled] .radio-inline{cursor:not-allowed}.checkbox.disabled label,.radio.disabled label,fieldset[disabled] .checkbox label,fieldset[disabled] .radio label{cursor:not-allowed}.form-control-static{min-height:34px;padding-top:7px;padding-bottom:7px;margin-bottom:0}.form-control-static.input-lg,.form-control-static.input-sm{padding-right:0;padding-left:0}.input-sm{height:30px;padding:5px 10px;font-size:12px;line-height:1.5;border-radius:3px}select.input-sm{height:30px;line-height:30px}select[multiple].input-sm,textarea.input-sm{height:auto}.form-group-sm .form-control{height:30px;padding:5px 10px;font-size:12px;line-height:1.5;border-radius:3px}select.form-group-sm .form-control{height:30px;line-height:30px}select[multiple].form-group-sm .form-control,textarea.form-group-sm .form-control{height:auto}.form-group-sm .form-control-static{height:30px;min-height:32px;padding:5px 10px;font-size:12px;line-height:1.5}.input-lg{height:46px;padding:10px 16px;font-size:18px;line-height:1.3333333;border-radius:6px}select.input-lg{height:46px;line-height:46px}select[multiple].input-lg,textarea.input-lg{height:auto}.form-group-lg .form-control{height:46px;padding:10px 16px;font-size:18px;line-height:1.3333333;border-radius:6px}select.form-group-lg .form-control{height:46px;line-height:46px}select[multiple].form-group-lg .form-control,textarea.form-group-lg .form-control{height:auto}.form-group-lg .form-control-static{height:46px;min-height:38px;padding:10px 16px;font-size:18px;line-height:1.3333333}.has-feedback{position:relative}.has-feedback .form-control{padding-right:42.5px}.form-control-feedback{position:absolute;top:0;right:0;z-index:2;display:block;width:34px;height:34px;line-height:34px;text-align:center;pointer-events:none}.input-lg+.form-control-feedback{width:46px;height:46px;line-height:46px}.input-sm+.form-control-feedback{width:30px;height:30px;line-height:30px}.has-success .checkbox,.has-success .checkbox-inline,.has-success .control-label,.has-success .help-block,.has-success .radio,.has-success .radio-inline,.has-success.checkbox label,.has-success.checkbox-inline label,.has-success.radio label,.has-success.radio-inline label{color:#3c763d}.has-success .form-control{border-color:#3c763d;-webkit-box-shadow:inset 0 1px 1px rgba(0,0,0,.075);box-shadow:inset 0 1px 1px rgba(0,0,0,.075)}.has-success .form-control:focus{border-color:#2b542c;-webkit-box-shadow:inset 0 1px 1px rgba(0,0,0,.075),0 0 6px #67b168;box-shadow:inset 0 1px 1px rgba(0,0,0,.075),0 0 6px #67b168}.has-success .input-group-addon{color:#3c763d;background-color:#dff0d8;border-color:#3c763d}.has-success .form-control-feedback{color:#3c763d}.has-warning .checkbox,.has-warning .checkbox-inline,.has-warning .control-label,.has-warning .help-block,.has-warning .radio,.has-warning .radio-inline,.has-warning.checkbox label,.has-warning.checkbox-inline label,.has-warning.radio label,.has-warning.radio-inline label{color:#8a6d3b}.has-warning .form-control{border-color:#8a6d3b;-webkit-box-shadow:inset 0 1px 1px rgba(0,0,0,.075);box-shadow:inset 0 1px 1px rgba(0,0,0,.075)}.has-warning .form-control:focus{border-color:#66512c;-webkit-box-shadow:inset 0 1px 1px rgba(0,0,0,.075),0 0 6px #c0a16b;box-shadow:inset 0 1px 1px rgba(0,0,0,.075),0 0 6px #c0a16b}.has-warning .input-group-addon{color:#8a6d3b;background-color:#fcf8e3;border-color:#8a6d3b}.has-warning .form-control-feedback{color:#8a6d3b}.has-error .checkbox,.has-error .checkbox-inline,.has-error .control-label,.has-error .help-block,.has-error .radio,.has-error .radio-inline,.has-error.checkbox label,.has-error.checkbox-inline label,.has-error.radio label,.has-error.radio-inline label{color:#a94442}.has-error .form-control{border-color:#a94442;-webkit-box-shadow:inset 0 1px 1px rgba(0,0,0,.075);box-shadow:inset 0 1px 1px rgba(0,0,0,.075)}.has-error .form-control:focus{border-color:#843534;-webkit-box-shadow:inset 0 1px 1px rgba(0,0,0,.075),0 0 6px #ce8483;box-shadow:inset 0 1px 1px rgba(0,0,0,.075),0 0 6px #ce8483}.has-error .input-group-addon{color:#a94442;background-color:#f2dede;border-color:#a94442}.has-error .form-control-feedback{color:#a94442}.has-feedback label~.form-control-feedback{top:25px}.has-feedback label.sr-only~.form-control-feedback{top:0}.help-block{display:block;margin-top:5px;margin-bottom:10px;color:#737373}@media (min-width:768px){.form-inline .form-group{display:inline-block;margin-bottom:0;vertical-align:middle}.form-inline .form-control{display:inline-block;width:auto;vertical-align:middle}.form-inline .form-control-static{display:inline-block}.form-inline .input-group{display:inline-table;vertical-align:middle}.form-inline .input-group .form-control,.form-inline .input-group .input-group-addon,.form-inline .input-group .input-group-btn{width:auto}.form-inline .input-group>.form-control{width:100%}.form-inline .control-label{margin-bottom:0;vertical-align:middle}.form-inline .checkbox,.form-inline .radio{display:inline-block;margin-top:0;margin-bottom:0;vertical-align:middle}.form-inline .checkbox label,.form-inline .radio label{padding-left:0}.form-inline .checkbox input[type=checkbox],.form-inline .radio input[type=radio]{position:relative;margin-left:0}.form-inline .has-feedback .form-control-feedback{top:0}}.form-horizontal .checkbox,.form-horizontal .checkbox-inline,.form-horizontal .radio,.form-horizontal .radio-inline{padding-top:7px;margin-top:0;margin-bottom:0}.form-horizontal .checkbox,.form-horizontal .radio{min-height:27px}.form-horizontal .form-group{margin-right:-15px;margin-left:-15px}@media (min-width:768px){.form-horizontal .control-label{padding-top:7px;margin-bottom:0;text-align:right}}.form-horizontal .has-feedback .form-control-feedback{right:15px}@media (min-width:768px){.form-horizontal .form-group-lg .control-label{padding-top:14.33px}}@media (min-width:768px){.form-horizontal .form-group-sm .control-label{padding-top:6px}}.btn{display:inline-block;padding:6px 12px;margin-bottom:0;font-size:14px;font-weight:400;line-height:1.42857143;text-align:center;white-space:nowrap;vertical-align:middle;-ms-touch-action:manipulation;touch-action:manipulation;cursor:pointer;-webkit-user-select:none;-moz-user-select:none;-ms-user-select:none;user-select:none;background-image:none;border:1px solid transparent;border-radius:4px}.btn.active.focus,.btn.active:focus,.btn.focus,.btn:active.focus,.btn:active:focus,.btn:focus{outline:thin dotted;outline:5px auto -webkit-focus-ring-color;outline-offset:-2px}.btn.focus,.btn:focus,.btn:hover{color:#333;text-decoration:none}.btn.active,.btn:active{background-image:none;outline:0;-webkit-box-shadow:inset 0 3px 5px rgba(0,0,0,.125);box-shadow:inset 0 3px 5px rgba(0,0,0,.125)}.btn.disabled,.btn[disabled],fieldset[disabled] .btn{pointer-events:none;cursor:not-allowed;filter:alpha(opacity=65);-webkit-box-shadow:none;box-shadow:none;opacity:.65}.btn-default{color:#333;background-color:#fff;border-color:#ccc}.btn-default.active,.btn-default.focus,.btn-default:active,.btn-default:focus,.btn-default:hover,.open>.dropdown-toggle.btn-default{color:#333;background-color:#e6e6e6;border-color:#adadad}.btn-default.active,.btn-default:active,.open>.dropdown-toggle.btn-default{background-image:none}.btn-default.disabled,.btn-default.disabled.active,.btn-default.disabled.focus,.btn-default.disabled:active,.btn-default.disabled:focus,.btn-default.disabled:hover,.btn-default[disabled],.btn-default[disabled].active,.btn-default[disabled].focus,.btn-default[disabled]:active,.btn-default[disabled]:focus,.btn-default[disabled]:hover,fieldset[disabled] .btn-default,fieldset[disabled] .btn-default.active,fieldset[disabled] .btn-default.focus,fieldset[disabled] .btn-default:active,fieldset[disabled] .btn-default:focus,fieldset[disabled] .btn-default:hover{background-color:#fff;border-color:#ccc}.btn-default .badge{color:#fff;background-color:#333}.btn-primary{color:#fff;background-color:#337ab7;border-color:#2e6da4}.btn-primary.active,.btn-primary.focus,.btn-primary:active,.btn-primary:focus,.btn-primary:hover,.open>.dropdown-toggle.btn-primary{color:#fff;background-color:#286090;border-color:#204d74}.btn-primary.active,.btn-primary:active,.open>.dropdown-toggle.btn-primary{background-image:none}.btn-primary.disabled,.btn-primary.disabled.active,.btn-primary.disabled.focus,.btn-primary.disabled:active,.btn-primary.disabled:focus,.btn-primary.disabled:hover,.btn-primary[disabled],.btn-primary[disabled].active,.btn-primary[disabled].focus,.btn-primary[disabled]:active,.btn-primary[disabled]:focus,.btn-primary[disabled]:hover,fieldset[disabled] .btn-primary,fieldset[disabled] .btn-primary.active,fieldset[disabled] .btn-primary.focus,fieldset[disabled] .btn-primary:active,fieldset[disabled] .btn-primary:focus,fieldset[disabled] .btn-primary:hover{background-color:#337ab7;border-color:#2e6da4}.btn-primary .badge{color:#337ab7;background-color:#fff}.btn-success{color:#fff;background-color:#5cb85c;border-color:#4cae4c}.btn-success.active,.btn-success.focus,.btn-success:active,.btn-success:focus,.btn-success:hover,.open>.dropdown-toggle.btn-success{color:#fff;background-color:#449d44;border-color:#398439}.btn-success.active,.btn-success:active,.open>.dropdown-toggle.btn-success{background-image:none}.btn-success.disabled,.btn-success.disabled.active,.btn-success.disabled.focus,.btn-success.disabled:active,.btn-success.disabled:focus,.btn-success.disabled:hover,.btn-success[disabled],.btn-success[disabled].active,.btn-success[disabled].focus,.btn-success[disabled]:active,.btn-success[disabled]:focus,.btn-success[disabled]:hover,fieldset[disabled] .btn-success,fieldset[disabled] .btn-success.active,fieldset[disabled] .btn-success.focus,fieldset[disabled] .btn-success:active,fieldset[disabled] .btn-success:focus,fieldset[disabled] .btn-success:hover{background-color:#5cb85c;border-color:#4cae4c}.btn-success .badge{color:#5cb85c;background-color:#fff}.btn-info{color:#fff;background-color:#5bc0de;border-color:#46b8da}.btn-info.active,.btn-info.focus,.btn-info:active,.btn-info:focus,.btn-info:hover,.open>.dropdown-toggle.btn-info{color:#fff;background-color:#31b0d5;border-color:#269abc}.btn-info.active,.btn-info:active,.open>.dropdown-toggle.btn-info{background-image:none}.btn-info.disabled,.btn-info.disabled.active,.btn-info.disabled.focus,.btn-info.disabled:active,.btn-info.disabled:focus,.btn-info.disabled:hover,.btn-info[disabled],.btn-info[disabled].active,.btn-info[disabled].focus,.btn-info[disabled]:active,.btn-info[disabled]:focus,.btn-info[disabled]:hover,fieldset[disabled] .btn-info,fieldset[disabled] .btn-info.active,fieldset[disabled] .btn-info.focus,fieldset[disabled] .btn-info:active,fieldset[disabled] .btn-info:focus,fieldset[disabled] .btn-info:hover{background-color:#5bc0de;border-color:#46b8da}.btn-info .badge{color:#5bc0de;background-color:#fff}.btn-warning{color:#fff;background-color:#f0ad4e;border-color:#eea236}.btn-warning.active,.btn-warning.focus,.btn-warning:active,.btn-warning:focus,.btn-warning:hover,.open>.dropdown-toggle.btn-warning{color:#fff;background-color:#ec971f;border-color:#d58512}.btn-warning.active,.btn-warning:active,.open>.dropdown-toggle.btn-warning{background-image:none}.btn-warning.disabled,.btn-warning.disabled.active,.btn-warning.disabled.focus,.btn-warning.disabled:active,.btn-warning.disabled:focus,.btn-warning.disabled:hover,.btn-warning[disabled],.btn-warning[disabled].active,.btn-warning[disabled].focus,.btn-warning[disabled]:active,.btn-warning[disabled]:focus,.btn-warning[disabled]:hover,fieldset[disabled] .btn-warning,fieldset[disabled] .btn-warning.active,fieldset[disabled] .btn-warning.focus,fieldset[disabled] .btn-warning:active,fieldset[disabled] .btn-warning:focus,fieldset[disabled] .btn-warning:hover{background-color:#f0ad4e;border-color:#eea236}.btn-warning .badge{color:#f0ad4e;background-color:#fff}.btn-danger{color:#fff;background-color:#d9534f;border-color:#d43f3a}.btn-danger.active,.btn-danger.focus,.btn-danger:active,.btn-danger:focus,.btn-danger:hover,.open>.dropdown-toggle.btn-danger{color:#fff;background-color:#c9302c;border-color:#ac2925}.btn-danger.active,.btn-danger:active,.open>.dropdown-toggle.btn-danger{background-image:none}.btn-danger.disabled,.btn-danger.disabled.active,.btn-danger.disabled.focus,.btn-danger.disabled:active,.btn-danger.disabled:focus,.btn-danger.disabled:hover,.btn-danger[disabled],.btn-danger[disabled].active,.btn-danger[disabled].focus,.btn-danger[disabled]:active,.btn-danger[disabled]:focus,.btn-danger[disabled]:hover,fieldset[disabled] .btn-danger,fieldset[disabled] .btn-danger.active,fieldset[disabled] .btn-danger.focus,fieldset[disabled] .btn-danger:active,fieldset[disabled] .btn-danger:focus,fieldset[disabled] .btn-danger:hover{background-color:#d9534f;border-color:#d43f3a}.btn-danger .badge{color:#d9534f;background-color:#fff}.btn-link{font-weight:400;color:#337ab7;border-radius:0}.btn-link,.btn-link.active,.btn-link:active,.btn-link[disabled],fieldset[disabled] .btn-link{background-color:transparent;-webkit-box-shadow:none;box-shadow:none}.btn-link,.btn-link:active,.btn-link:focus,.btn-link:hover{border-color:transparent}.btn-link:focus,.btn-link:hover{color:#23527c;text-decoration:underline;background-color:transparent}.btn-link[disabled]:focus,.btn-link[disabled]:hover,fieldset[disabled] .btn-link:focus,fieldset[disabled] .btn-link:hover{color:#777;text-decoration:none}.btn-group-lg>.btn,.btn-lg{padding:10px 16px;font-size:18px;line-height:1.3333333;border-radius:6px}.btn-group-sm>.btn,.btn-sm{padding:5px 10px;font-size:12px;line-height:1.5;border-radius:3px}.btn-group-xs>.btn,.btn-xs{padding:1px 5px;font-size:12px;line-height:1.5;border-radius:3px}.btn-block{display:block;width:100%}.btn-block+.btn-block{margin-top:5px}input[type=button].btn-block,input[type=reset].btn-block,input[type=submit].btn-block{width:100%}.fade{opacity:0;-webkit-transition:opacity .15s linear;-o-transition:opacity .15s linear;transition:opacity .15s linear}.fade.in{opacity:1}.collapse{display:none}.collapse.in{display:block}tr.collapse.in{display:table-row}tbody.collapse.in{display:table-row-group}.collapsing{position:relative;height:0;overflow:hidden;-webkit-transition-timing-function:ease;-o-transition-timing-function:ease;transition-timing-function:ease;-webkit-transition-duration:.35s;-o-transition-duration:.35s;transition-duration:.35s;-webkit-transition-property:height,visibility;-o-transition-property:height,visibility;transition-property:height,visibility}.caret{display:inline-block;width:0;height:0;margin-left:2px;vertical-align:middle;border-top:4px dashed;border-right:4px solid transparent;border-left:4px solid transparent}.dropdown,.dropup{position:relative}.dropdown-toggle:focus{outline:0}.dropdown-menu{position:absolute;top:100%;left:0;z-index:1000;display:none;float:left;min-width:160px;padding:5px 0;margin:2px 0 0;font-size:14px;text-align:left;list-style:none;background-color:#fff;-webkit-background-clip:padding-box;background-clip:padding-box;border:1px solid #ccc;border:1px solid rgba(0,0,0,.15);border-radius:4px;-webkit-box-shadow:0 6px 12px rgba(0,0,0,.175);box-shadow:0 6px 12px rgba(0,0,0,.175)}.dropdown-menu.pull-right{right:0;left:auto}.dropdown-menu .divider{height:1px;margin:9px 0;overflow:hidden;background-color:#e5e5e5}.dropdown-menu>li>a{display:block;padding:3px 20px;clear:both;font-weight:400;line-height:1.42857143;color:#333;white-space:nowrap}.dropdown-menu>li>a:focus,.dropdown-menu>li>a:hover{color:#262626;text-decoration:none;background-color:#f5f5f5}.dropdown-menu>.active>a,.dropdown-menu>.active>a:focus,.dropdown-menu>.active>a:hover{color:#fff;text-decoration:none;background-color:#337ab7;outline:0}.dropdown-menu>.disabled>a,.dropdown-menu>.disabled>a:focus,.dropdown-menu>.disabled>a:hover{color:#777}.dropdown-menu>.disabled>a:focus,.dropdown-menu>.disabled>a:hover{text-decoration:none;cursor:not-allowed;background-color:transparent;background-image:none;filter:progid:DXImageTransform.Microsoft.gradient(enabled=false)}.open>.dropdown-menu{display:block}.open>a{outline:0}.dropdown-menu-right{right:0;left:auto}.dropdown-menu-left{right:auto;left:0}.dropdown-header{display:block;padding:3px 20px;font-size:12px;line-height:1.42857143;color:#777;white-space:nowrap}.dropdown-backdrop{position:fixed;top:0;right:0;bottom:0;left:0;z-index:990}.pull-right>.dropdown-menu{right:0;left:auto}.dropup .caret,.navbar-fixed-bottom .dropdown .caret{content:"";border-top:0;border-bottom:4px solid}.dropup .dropdown-menu,.navbar-fixed-bottom .dropdown .dropdown-menu{top:auto;bottom:100%;margin-bottom:2px}@media (min-width:768px){.navbar-right .dropdown-menu{right:0;left:auto}.navbar-right .dropdown-menu-left{right:auto;left:0}}.btn-group,.btn-group-vertical{position:relative;display:inline-block;vertical-align:middle}.btn-group-vertical>.btn,.btn-group>.btn{position:relative;float:left}.btn-group-vertical>.btn.active,.btn-group-vertical>.btn:active,.btn-group-vertical>.btn:focus,.btn-group-vertical>.btn:hover,.btn-group>.btn.active,.btn-group>.btn:active,.btn-group>.btn:focus,.btn-group>.btn:hover{z-index:2}.btn-group .btn+.btn,.btn-group .btn+.btn-group,.btn-group .btn-group+.btn,.btn-group .btn-group+.btn-group{margin-left:-1px}.btn-toolbar{margin-left:-5px}.btn-toolbar .btn-group,.btn-toolbar .input-group{float:left}.btn-toolbar>.btn,.btn-toolbar>.btn-group,.btn-toolbar>.input-group{margin-left:5px}.btn-group>.btn:not(:first-child):not(:last-child):not(.dropdown-toggle){border-radius:0}.btn-group>.btn:first-child{margin-left:0}.btn-group>.btn:first-child:not(:last-child):not(.dropdown-toggle){border-top-right-radius:0;border-bottom-right-radius:0}.btn-group>.btn:last-child:not(:first-child),.btn-group>.dropdown-toggle:not(:first-child){border-top-left-radius:0;border-bottom-left-radius:0}.btn-group>.btn-group{float:left}.btn-group>.btn-group:not(:first-child):not(:last-child)>.btn{border-radius:0}.btn-group>.btn-group:first-child:not(:last-child)>.btn:last-child,.btn-group>.btn-group:first-child:not(:last-child)>.dropdown-toggle{border-top-right-radius:0;border-bottom-right-radius:0}.btn-group>.btn-group:last-child:not(:first-child)>.btn:first-child{border-top-left-radius:0;border-bottom-left-radius:0}.btn-group .dropdown-toggle:active,.btn-group.open .dropdown-toggle{outline:0}.btn-group>.btn+.dropdown-toggle{padding-right:8px;padding-left:8px}.btn-group>.btn-lg+.dropdown-toggle{padding-right:12px;padding-left:12px}.btn-group.open .dropdown-toggle{-webkit-box-shadow:inset 0 3px 5px rgba(0,0,0,.125);box-shadow:inset 0 3px 5px rgba(0,0,0,.125)}.btn-group.open .dropdown-toggle.btn-link{-webkit-box-shadow:none;box-shadow:none}.btn .caret{margin-left:0}.btn-lg .caret{border-width:5px 5px 0;border-bottom-width:0}.dropup .btn-lg .caret{border-width:0 5px 5px}.btn-group-vertical>.btn,.btn-group-vertical>.btn-group,.btn-group-vertical>.btn-group>.btn{display:block;float:none;width:100%;max-width:100%}.btn-group-vertical>.btn-group>.btn{float:none}.btn-group-vertical>.btn+.btn,.btn-group-vertical>.btn+.btn-group,.btn-group-vertical>.btn-group+.btn,.btn-group-vertical>.btn-group+.btn-group{margin-top:-1px;margin-left:0}.btn-group-vertical>.btn:not(:first-child):not(:last-child){border-radius:0}.btn-group-vertical>.btn:first-child:not(:last-child){border-top-right-radius:4px;border-bottom-right-radius:0;border-bottom-left-radius:0}.btn-group-vertical>.btn:last-child:not(:first-child){border-top-left-radius:0;border-top-right-radius:0;border-bottom-left-radius:4px}.btn-group-vertical>.btn-group:not(:first-child):not(:last-child)>.btn{border-radius:0}.btn-group-vertical>.btn-group:first-child:not(:last-child)>.btn:last-child,.btn-group-vertical>.btn-group:first-child:not(:last-child)>.dropdown-toggle{border-bottom-right-radius:0;border-bottom-left-radius:0}.btn-group-vertical>.btn-group:last-child:not(:first-child)>.btn:first-child{border-top-left-radius:0;border-top-right-radius:0}.btn-group-justified{display:table;width:100%;table-layout:fixed;border-collapse:separate}.btn-group-justified>.btn,.btn-group-justified>.btn-group{display:table-cell;float:none;width:1%}.btn-group-justified>.btn-group .btn{width:100%}.btn-group-justified>.btn-group .dropdown-menu{left:auto}[data-toggle=buttons]>.btn input[type=checkbox],[data-toggle=buttons]>.btn input[type=radio],[data-toggle=buttons]>.btn-group>.btn input[type=checkbox],[data-toggle=buttons]>.btn-group>.btn input[type=radio]{position:absolute;clip:rect(0,0,0,0);pointer-events:none}.input-group{position:relative;display:table;border-collapse:separate}.input-group[class*=col-]{float:none;padding-right:0;padding-left:0}.input-group .form-control{position:relative;z-index:2;float:left;width:100%;margin-bottom:0}.input-group-lg>.form-control,.input-group-lg>.input-group-addon,.input-group-lg>.input-group-btn>.btn{height:46px;padding:10px 16px;font-size:18px;line-height:1.3333333;border-radius:6px}select.input-group-lg>.form-control,select.input-group-lg>.input-group-addon,select.input-group-lg>.input-group-btn>.btn{height:46px;line-height:46px}select[multiple].input-group-lg>.form-control,select[multiple].input-group-lg>.input-group-addon,select[multiple].input-group-lg>.input-group-btn>.btn,textarea.input-group-lg>.form-control,textarea.input-group-lg>.input-group-addon,textarea.input-group-lg>.input-group-btn>.btn{height:auto}.input-group-sm>.form-control,.input-group-sm>.input-group-addon,.input-group-sm>.input-group-btn>.btn{height:30px;padding:5px 10px;font-size:12px;line-height:1.5;border-radius:3px}select.input-group-sm>.form-control,select.input-group-sm>.input-group-addon,select.input-group-sm>.input-group-btn>.btn{height:30px;line-height:30px}select[multiple].input-group-sm>.form-control,select[multiple].input-group-sm>.input-group-addon,select[multiple].input-group-sm>.input-group-btn>.btn,textarea.input-group-sm>.form-control,textarea.input-group-sm>.input-group-addon,textarea.input-group-sm>.input-group-btn>.btn{height:auto}.input-group .form-control,.input-group-addon,.input-group-btn{display:table-cell}.input-group .form-control:not(:first-child):not(:last-child),.input-group-addon:not(:first-child):not(:last-child),.input-group-btn:not(:first-child):not(:last-child){border-radius:0}.input-group-addon,.input-group-btn{width:1%;white-space:nowrap;vertical-align:middle}.input-group-addon{padding:6px 12px;font-size:14px;font-weight:400;line-height:1;color:#555;text-align:center;background-color:#eee;border:1px solid #ccc;border-radius:4px}.input-group-addon.input-sm{padding:5px 10px;font-size:12px;border-radius:3px}.input-group-addon.input-lg{padding:10px 16px;font-size:18px;border-radius:6px}.input-group-addon input[type=checkbox],.input-group-addon input[type=radio]{margin-top:0}.input-group .form-control:first-child,.input-group-addon:first-child,.input-group-btn:first-child>.btn,.input-group-btn:first-child>.btn-group>.btn,.input-group-btn:first-child>.dropdown-toggle,.input-group-btn:last-child>.btn-group:not(:last-child)>.btn,.input-group-btn:last-child>.btn:not(:last-child):not(.dropdown-toggle){border-top-right-radius:0;border-bottom-right-radius:0}.input-group-addon:first-child{border-right:0}.input-group .form-control:last-child,.input-group-addon:last-child,.input-group-btn:first-child>.btn-group:not(:first-child)>.btn,.input-group-btn:first-child>.btn:not(:first-child),.input-group-btn:last-child>.btn,.input-group-btn:last-child>.btn-group>.btn,.input-group-btn:last-child>.dropdown-toggle{border-top-left-radius:0;border-bottom-left-radius:0}.input-group-addon:last-child{border-left:0}.input-group-btn{position:relative;font-size:0;white-space:nowrap}.input-group-btn>.btn{position:relative}.input-group-btn>.btn+.btn{margin-left:-1px}.input-group-btn>.btn:active,.input-group-btn>.btn:focus,.input-group-btn>.btn:hover{z-index:2}.input-group-btn:first-child>.btn,.input-group-btn:first-child>.btn-group{margin-right:-1px}.input-group-btn:last-child>.btn,.input-group-btn:last-child>.btn-group{margin-left:-1px}.nav{padding-left:0;margin-bottom:0;list-style:none}.nav>li{position:relative;display:block}.nav>li>a{position:relative;display:block;padding:10px 15px}.nav>li>a:focus,.nav>li>a:hover{text-decoration:none;background-color:#eee}.nav>li.disabled>a{color:#777}.nav>li.disabled>a:focus,.nav>li.disabled>a:hover{color:#777;text-decoration:none;cursor:not-allowed;background-color:transparent}.nav .open>a,.nav .open>a:focus,.nav .open>a:hover{background-color:#eee;border-color:#337ab7}.nav .nav-divider{height:1px;margin:9px 0;overflow:hidden;background-color:#e5e5e5}.nav>li>a>img{max-width:none}.nav-tabs{border-bottom:1px solid #ddd}.nav-tabs>li{float:left;margin-bottom:-1px}.nav-tabs>li>a{margin-right:2px;line-height:1.42857143;border:1px solid transparent;border-radius:4px 4px 0 0}.nav-tabs>li>a:hover{border-color:#eee #eee #ddd}.nav-tabs>li.active>a,.nav-tabs>li.active>a:focus,.nav-tabs>li.active>a:hover{color:#555;cursor:default;background-color:#fff;border:1px solid #ddd;border-bottom-color:transparent}.nav-tabs.nav-justified{width:100%;border-bottom:0}.nav-tabs.nav-justified>li{float:none}.nav-tabs.nav-justified>li>a{margin-bottom:5px;text-align:center}.nav-tabs.nav-justified>.dropdown .dropdown-menu{top:auto;left:auto}@media (min-width:768px){.nav-tabs.nav-justified>li{display:table-cell;width:1%}.nav-tabs.nav-justified>li>a{margin-bottom:0}}.nav-tabs.nav-justified>li>a{margin-right:0;border-radius:4px}.nav-tabs.nav-justified>.active>a,.nav-tabs.nav-justified>.active>a:focus,.nav-tabs.nav-justified>.active>a:hover{border:1px solid #ddd}@media (min-width:768px){.nav-tabs.nav-justified>li>a{border-bottom:1px solid #ddd;border-radius:4px 4px 0 0}.nav-tabs.nav-justified>.active>a,.nav-tabs.nav-justified>.active>a:focus,.nav-tabs.nav-justified>.active>a:hover{border-bottom-color:#fff}}.nav-pills>li{float:left}.nav-pills>li>a{border-radius:4px}.nav-pills>li+li{margin-left:2px}.nav-pills>li.active>a,.nav-pills>li.active>a:focus,.nav-pills>li.active>a:hover{color:#fff;background-color:#337ab7}.nav-stacked>li{float:none}.nav-stacked>li+li{margin-top:2px;margin-left:0}.nav-justified{width:100%}.nav-justified>li{float:none}.nav-justified>li>a{margin-bottom:5px;text-align:center}.nav-justified>.dropdown .dropdown-menu{top:auto;left:auto}@media (min-width:768px){.nav-justified>li{display:table-cell;width:1%}.nav-justified>li>a{margin-bottom:0}}.nav-tabs-justified{border-bottom:0}.nav-tabs-justified>li>a{margin-right:0;border-radius:4px}.nav-tabs-justified>.active>a,.nav-tabs-justified>.active>a:focus,.nav-tabs-justified>.active>a:hover{border:1px solid #ddd}@media (min-width:768px){.nav-tabs-justified>li>a{border-bottom:1px solid #ddd;border-radius:4px 4px 0 0}.nav-tabs-justified>.active>a,.nav-tabs-justified>.active>a:focus,.nav-tabs-justified>.active>a:hover{border-bottom-color:#fff}}.tab-content>.tab-pane{display:none}.tab-content>.active{display:block}.nav-tabs .dropdown-menu{margin-top:-1px;border-top-left-radius:0;border-top-right-radius:0}.navbar{position:relative;min-height:50px;margin-bottom:20px;border:1px solid transparent}@media (min-width:768px){.navbar{border-radius:4px}}@media (min-width:768px){.navbar-header{float:left}}.navbar-collapse{padding-right:15px;padding-left:15px;overflow-x:visible;-webkit-overflow-scrolling:touch;border-top:1px solid transparent;-webkit-box-shadow:inset 0 1px 0 rgba(255,255,255,.1);box-shadow:inset 0 1px 0 rgba(255,255,255,.1)}.navbar-collapse.in{overflow-y:auto}@media (min-width:768px){.navbar-collapse{width:auto;border-top:0;-webkit-box-shadow:none;box-shadow:none}.navbar-collapse.collapse{display:block!important;height:auto!important;padding-bottom:0;overflow:visible!important}.navbar-collapse.in{overflow-y:visible}.navbar-fixed-bottom .navbar-collapse,.navbar-fixed-top .navbar-collapse,.navbar-static-top .navbar-collapse{padding-right:0;padding-left:0}}.navbar-fixed-bottom .navbar-collapse,.navbar-fixed-top .navbar-collapse{max-height:340px}@media (max-device-width:480px)and (orientation:landscape){.navbar-fixed-bottom .navbar-collapse,.navbar-fixed-top .navbar-collapse{max-height:200px}}.container-fluid>.navbar-collapse,.container-fluid>.navbar-header,.container>.navbar-collapse,.container>.navbar-header{margin-right:-15px;margin-left:-15px}@media (min-width:768px){.container-fluid>.navbar-collapse,.container-fluid>.navbar-header,.container>.navbar-collapse,.container>.navbar-header{margin-right:0;margin-left:0}}.navbar-static-top{z-index:1000;border-width:0 0 1px}@media (min-width:768px){.navbar-static-top{border-radius:0}}.navbar-fixed-bottom,.navbar-fixed-top{position:fixed;right:0;left:0;z-index:1030}@media (min-width:768px){.navbar-fixed-bottom,.navbar-fixed-top{border-radius:0}}.navbar-fixed-top{top:0;border-width:0 0 1px}.navbar-fixed-bottom{bottom:0;margin-bottom:0;border-width:1px 0 0}.navbar-brand{float:left;height:50px;padding:15px 15px;font-size:18px;line-height:20px}.navbar-brand:focus,.navbar-brand:hover{text-decoration:none}.navbar-brand>img{display:block}@media (min-width:768px){.navbar>.container .navbar-brand,.navbar>.container-fluid .navbar-brand{margin-left:-15px}}.navbar-toggle{position:relative;float:right;padding:9px 10px;margin-top:8px;margin-right:15px;margin-bottom:8px;background-color:transparent;background-image:none;border:1px solid transparent;border-radius:4px}.navbar-toggle:focus{outline:0}.navbar-toggle .icon-bar{display:block;width:22px;height:2px;border-radius:1px}.navbar-toggle .icon-bar+.icon-bar{margin-top:4px}@media (min-width:768px){.navbar-toggle{display:none}}.navbar-nav{margin:7.5px -15px}.navbar-nav>li>a{padding-top:10px;padding-bottom:10px;line-height:20px}@media (max-width:767px){.navbar-nav .open .dropdown-menu{position:static;float:none;width:auto;margin-top:0;background-color:transparent;border:0;-webkit-box-shadow:none;box-shadow:none}.navbar-nav .open .dropdown-menu .dropdown-header,.navbar-nav .open .dropdown-menu>li>a{padding:5px 15px 5px 25px}.navbar-nav .open .dropdown-menu>li>a{line-height:20px}.navbar-nav .open .dropdown-menu>li>a:focus,.navbar-nav .open .dropdown-menu>li>a:hover{background-image:none}}@media (min-width:768px){.navbar-nav{float:left;margin:0}.navbar-nav>li{float:left}.navbar-nav>li>a{padding-top:15px;padding-bottom:15px}}.navbar-form{padding:10px 15px;margin-top:8px;margin-right:-15px;margin-bottom:8px;margin-left:-15px;border-top:1px solid transparent;border-bottom:1px solid transparent;-webkit-box-shadow:inset 0 1px 0 rgba(255,255,255,.1),0 1px 0 rgba(255,255,255,.1);box-shadow:inset 0 1px 0 rgba(255,255,255,.1),0 1px 0 rgba(255,255,255,.1)}@media (min-width:768px){.navbar-form .form-group{display:inline-block;margin-bottom:0;vertical-align:middle}.navbar-form .form-control{display:inline-block;width:auto;vertical-align:middle}.navbar-form .form-control-static{display:inline-block}.navbar-form .input-group{display:inline-table;vertical-align:middle}.navbar-form .input-group .form-control,.navbar-form .input-group .input-group-addon,.navbar-form .input-group .input-group-btn{width:auto}.navbar-form .input-group>.form-control{width:100%}.navbar-form .control-label{margin-bottom:0;vertical-align:middle}.navbar-form .checkbox,.navbar-form .radio{display:inline-block;margin-top:0;margin-bottom:0;vertical-align:middle}.navbar-form .checkbox label,.navbar-form .radio label{padding-left:0}.navbar-form .checkbox input[type=checkbox],.navbar-form .radio input[type=radio]{position:relative;margin-left:0}.navbar-form .has-feedback .form-control-feedback{top:0}}@media (max-width:767px){.navbar-form .form-group{margin-bottom:5px}.navbar-form .form-group:last-child{margin-bottom:0}}@media (min-width:768px){.navbar-form{width:auto;padding-top:0;padding-bottom:0;margin-right:0;margin-left:0;border:0;-webkit-box-shadow:none;box-shadow:none}}.navbar-nav>li>.dropdown-menu{margin-top:0;border-top-left-radius:0;border-top-right-radius:0}.navbar-fixed-bottom .navbar-nav>li>.dropdown-menu{margin-bottom:0;border-top-left-radius:4px;border-top-right-radius:4px;border-bottom-right-radius:0;border-bottom-left-radius:0}.navbar-btn{margin-top:8px;margin-bottom:8px}.navbar-btn.btn-sm{margin-top:10px;margin-bottom:10px}.navbar-btn.btn-xs{margin-top:14px;margin-bottom:14px}.navbar-text{margin-top:15px;margin-bottom:15px}@media (min-width:768px){.navbar-text{float:left;margin-right:15px;margin-left:15px}}@media (min-width:768px){.navbar-left{float:left!important}.navbar-right{float:right!important;margin-right:-15px}.navbar-right~.navbar-right{margin-right:0}}.navbar-default{background-color:#f8f8f8;border-color:#e7e7e7}.navbar-default .navbar-brand{color:#777}.navbar-default .navbar-brand:focus,.navbar-default .navbar-brand:hover{color:#5e5e5e;background-color:transparent}.navbar-default .navbar-text{color:#777}.navbar-default .navbar-nav>li>a{color:#777}.navbar-default .navbar-nav>li>a:focus,.navbar-default .navbar-nav>li>a:hover{color:#333;background-color:transparent}.navbar-default .navbar-nav>.active>a,.navbar-default .navbar-nav>.active>a:focus,.navbar-default .navbar-nav>.active>a:hover{color:#555;background-color:#e7e7e7}.navbar-default .navbar-nav>.disabled>a,.navbar-default .navbar-nav>.disabled>a:focus,.navbar-default .navbar-nav>.disabled>a:hover{color:#ccc;background-color:transparent}.navbar-default .navbar-toggle{border-color:#ddd}.navbar-default .navbar-toggle:focus,.navbar-default .navbar-toggle:hover{background-color:#ddd}.navbar-default .navbar-toggle .icon-bar{background-color:#888}.navbar-default .navbar-collapse,.navbar-default .navbar-form{border-color:#e7e7e7}.navbar-default .navbar-nav>.open>a,.navbar-default .navbar-nav>.open>a:focus,.navbar-default .navbar-nav>.open>a:hover{color:#555;background-color:#e7e7e7}@media (max-width:767px){.navbar-default .navbar-nav .open .dropdown-menu>li>a{color:#777}.navbar-default .navbar-nav .open .dropdown-menu>li>a:focus,.navbar-default .navbar-nav .open .dropdown-menu>li>a:hover{color:#333;background-color:transparent}.navbar-default .navbar-nav .open .dropdown-menu>.active>a,.navbar-default .navbar-nav .open .dropdown-menu>.active>a:focus,.navbar-default .navbar-nav .open .dropdown-menu>.active>a:hover{color:#555;background-color:#e7e7e7}.navbar-default .navbar-nav .open .dropdown-menu>.disabled>a,.navbar-default .navbar-nav .open .dropdown-menu>.disabled>a:focus,.navbar-default .navbar-nav .open .dropdown-menu>.disabled>a:hover{color:#ccc;background-color:transparent}}.navbar-default .navbar-link{color:#777}.navbar-default .navbar-link:hover{color:#333}.navbar-default .btn-link{color:#777}.navbar-default .btn-link:focus,.navbar-default .btn-link:hover{color:#333}.navbar-default .btn-link[disabled]:focus,.navbar-default .btn-link[disabled]:hover,fieldset[disabled] .navbar-default .btn-link:focus,fieldset[disabled] .navbar-default .btn-link:hover{color:#ccc}.navbar-inverse{background-color:#222;border-color:#080808}.navbar-inverse .navbar-brand{color:#9d9d9d}.navbar-inverse .navbar-brand:focus,.navbar-inverse .navbar-brand:hover{color:#fff;background-color:transparent}.navbar-inverse .navbar-text{color:#9d9d9d}.navbar-inverse .navbar-nav>li>a{color:#9d9d9d}.navbar-inverse .navbar-nav>li>a:focus,.navbar-inverse .navbar-nav>li>a:hover{color:#fff;background-color:transparent}.navbar-inverse .navbar-nav>.active>a,.navbar-inverse .navbar-nav>.active>a:focus,.navbar-inverse .navbar-nav>.active>a:hover{color:#fff;background-color:#080808}.navbar-inverse .navbar-nav>.disabled>a,.navbar-inverse .navbar-nav>.disabled>a:focus,.navbar-inverse .navbar-nav>.disabled>a:hover{color:#444;background-color:transparent}.navbar-inverse .navbar-toggle{border-color:#333}.navbar-inverse .navbar-toggle:focus,.navbar-inverse .navbar-toggle:hover{background-color:#333}.navbar-inverse .navbar-toggle .icon-bar{background-color:#fff}.navbar-inverse .navbar-collapse,.navbar-inverse .navbar-form{border-color:#101010}.navbar-inverse .navbar-nav>.open>a,.navbar-inverse .navbar-nav>.open>a:focus,.navbar-inverse .navbar-nav>.open>a:hover{color:#fff;background-color:#080808}@media (max-width:767px){.navbar-inverse .navbar-nav .open .dropdown-menu>.dropdown-header{border-color:#080808}.navbar-inverse .navbar-nav .open .dropdown-menu .divider{background-color:#080808}.navbar-inverse .navbar-nav .open .dropdown-menu>li>a{color:#9d9d9d}.navbar-inverse .navbar-nav .open .dropdown-menu>li>a:focus,.navbar-inverse .navbar-nav .open .dropdown-menu>li>a:hover{color:#fff;background-color:transparent}.navbar-inverse .navbar-nav .open .dropdown-menu>.active>a,.navbar-inverse .navbar-nav .open .dropdown-menu>.active>a:focus,.navbar-inverse .navbar-nav .open .dropdown-menu>.active>a:hover{color:#fff;background-color:#080808}.navbar-inverse .navbar-nav .open .dropdown-menu>.disabled>a,.navbar-inverse .navbar-nav .open .dropdown-menu>.disabled>a:focus,.navbar-inverse .navbar-nav .open .dropdown-menu>.disabled>a:hover{color:#444;background-color:transparent}}.navbar-inverse .navbar-link{color:#9d9d9d}.navbar-inverse .navbar-link:hover{color:#fff}.navbar-inverse .btn-link{color:#9d9d9d}.navbar-inverse .btn-link:focus,.navbar-inverse .btn-link:hover{color:#fff}.navbar-inverse .btn-link[disabled]:focus,.navbar-inverse .btn-link[disabled]:hover,fieldset[disabled] .navbar-inverse .btn-link:focus,fieldset[disabled] .navbar-inverse .btn-link:hover{color:#444}.breadcrumb{padding:8px 15px;margin-bottom:20px;list-style:none;background-color:#f5f5f5;border-radius:4px}.breadcrumb>li{display:inline-block}.breadcrumb>li+li:before{padding:0 5px;color:#ccc;content:"/\00a0"}.breadcrumb>.active{color:#777}.pagination{display:inline-block;padding-left:0;margin:20px 0;border-radius:4px}.pagination>li{display:inline}.pagination>li>a,.pagination>li>span{position:relative;float:left;padding:6px 12px;margin-left:-1px;line-height:1.42857143;color:#337ab7;text-decoration:none;background-color:#fff;border:1px solid #ddd}.pagination>li:first-child>a,.pagination>li:first-child>span{margin-left:0;border-top-left-radius:4px;border-bottom-left-radius:4px}.pagination>li:last-child>a,.pagination>li:last-child>span{border-top-right-radius:4px;border-bottom-right-radius:4px}.pagination>li>a:focus,.pagination>li>a:hover,.pagination>li>span:focus,.pagination>li>span:hover{color:#23527c;background-color:#eee;border-color:#ddd}.pagination>.active>a,.pagination>.active>a:focus,.pagination>.active>a:hover,.pagination>.active>span,.pagination>.active>span:focus,.pagination>.active>span:hover{z-index:2;color:#fff;cursor:default;background-color:#337ab7;border-color:#337ab7}.pagination>.disabled>a,.pagination>.disabled>a:focus,.pagination>.disabled>a:hover,.pagination>.disabled>span,.pagination>.disabled>span:focus,.pagination>.disabled>span:hover{color:#777;cursor:not-allowed;background-color:#fff;border-color:#ddd}.pagination-lg>li>a,.pagination-lg>li>span{padding:10px 16px;font-size:18px}.pagination-lg>li:first-child>a,.pagination-lg>li:first-child>span{border-top-left-radius:6px;border-bottom-left-radius:6px}.pagination-lg>li:last-child>a,.pagination-lg>li:last-child>span{border-top-right-radius:6px;border-bottom-right-radius:6px}.pagination-sm>li>a,.pagination-sm>li>span{padding:5px 10px;font-size:12px}.pagination-sm>li:first-child>a,.pagination-sm>li:first-child>span{border-top-left-radius:3px;border-bottom-left-radius:3px}.pagination-sm>li:last-child>a,.pagination-sm>li:last-child>span{border-top-right-radius:3px;border-bottom-right-radius:3px}.pager{padding-left:0;margin:20px 0;text-align:center;list-style:none}.pager li{display:inline}.pager li>a,.pager li>span{display:inline-block;padding:5px 14px;background-color:#fff;border:1px solid #ddd;border-radius:15px}.pager li>a:focus,.pager li>a:hover{text-decoration:none;background-color:#eee}.pager .next>a,.pager .next>span{float:right}.pager .previous>a,.pager .previous>span{float:left}.pager .disabled>a,.pager .disabled>a:focus,.pager .disabled>a:hover,.pager .disabled>span{color:#777;cursor:not-allowed;background-color:#fff}.label{display:inline;padding:.2em .6em .3em;font-size:75%;font-weight:700;line-height:1;color:#fff;text-align:center;white-space:nowrap;vertical-align:baseline;border-radius:.25em}a.label:focus,a.label:hover{color:#fff;text-decoration:none;cursor:pointer}.label:empty{display:none}.btn .label{position:relative;top:-1px}.label-default{background-color:#777}.label-default[href]:focus,.label-default[href]:hover{background-color:#5e5e5e}.label-primary{background-color:#337ab7}.label-primary[href]:focus,.label-primary[href]:hover{background-color:#286090}.label-success{background-color:#5cb85c}.label-success[href]:focus,.label-success[href]:hover{background-color:#449d44}.label-info{background-color:#5bc0de}.label-info[href]:focus,.label-info[href]:hover{background-color:#31b0d5}.label-warning{background-color:#f0ad4e}.label-warning[href]:focus,.label-warning[href]:hover{background-color:#ec971f}.label-danger{background-color:#d9534f}.label-danger[href]:focus,.label-danger[href]:hover{background-color:#c9302c}.badge{display:inline-block;min-width:10px;padding:3px 7px;font-size:12px;font-weight:700;line-height:1;color:#fff;text-align:center;white-space:nowrap;vertical-align:baseline;background-color:#777;border-radius:10px}.badge:empty{display:none}.btn .badge{position:relative;top:-1px}.btn-group-xs>.btn .badge,.btn-xs .badge{top:0;padding:1px 5px}a.badge:focus,a.badge:hover{color:#fff;text-decoration:none;cursor:pointer}.list-group-item.active>.badge,.nav-pills>.active>a>.badge{color:#337ab7;background-color:#fff}.list-group-item>.badge{float:right}.list-group-item>.badge+.badge{margin-right:5px}.nav-pills>li>a>.badge{margin-left:3px}.jumbotron{padding:30px 15px;margin-bottom:30px;color:inherit;background-color:#eee}.jumbotron .h1,.jumbotron h1{color:inherit}.jumbotron p{margin-bottom:15px;font-size:21px;font-weight:200}.jumbotron>hr{border-top-color:#d5d5d5}.container .jumbotron,.container-fluid .jumbotron{border-radius:6px}.jumbotron .container{max-width:100%}@media screen and (min-width:768px){.jumbotron{padding:48px 0}.container .jumbotron,.container-fluid .jumbotron{padding-right:60px;padding-left:60px}.jumbotron .h1,.jumbotron h1{font-size:63px}}.thumbnail{display:block;padding:4px;margin-bottom:20px;line-height:1.42857143;background-color:#fff;border:1px solid #ddd;border-radius:4px;-webkit-transition:border .2s ease-in-out;-o-transition:border .2s ease-in-out;transition:border .2s ease-in-out}.thumbnail a>img,.thumbnail>img{margin-right:auto;margin-left:auto}a.thumbnail.active,a.thumbnail:focus,a.thumbnail:hover{border-color:#337ab7}.thumbnail .caption{padding:9px;color:#333}.alert{padding:15px;margin-bottom:20px;border:1px solid transparent;border-radius:4px}.alert h4{margin-top:0;color:inherit}.alert .alert-link{font-weight:700}.alert>p,.alert>ul{margin-bottom:0}.alert>p+p{margin-top:5px}.alert-dismissable,.alert-dismissible{padding-right:35px}.alert-dismissable .close,.alert-dismissible .close{position:relative;top:-2px;right:-21px;color:inherit}.alert-success{color:#3c763d;background-color:#dff0d8;border-color:#d6e9c6}.alert-success hr{border-top-color:#c9e2b3}.alert-success .alert-link{color:#2b542c}.alert-info{color:#31708f;background-color:#d9edf7;border-color:#bce8f1}.alert-info hr{border-top-color:#a6e1ec}.alert-info .alert-link{color:#245269}.alert-warning{color:#8a6d3b;background-color:#fcf8e3;border-color:#faebcc}.alert-warning hr{border-top-color:#f7e1b5}.alert-warning .alert-link{color:#66512c}.alert-danger{color:#a94442;background-color:#f2dede;border-color:#ebccd1}.alert-danger hr{border-top-color:#e4b9c0}.alert-danger .alert-link{color:#843534}@-webkit-keyframes progress-bar-stripes{from{background-position:40px 0}to{background-position:0 0}}@-o-keyframes progress-bar-stripes{from{background-position:40px 0}to{background-position:0 0}}@keyframes progress-bar-stripes{from{background-position:40px 0}to{background-position:0 0}}.progress{height:20px;margin-bottom:20px;overflow:hidden;background-color:#f5f5f5;border-radius:4px;-webkit-box-shadow:inset 0 1px 2px rgba(0,0,0,.1);box-shadow:inset 0 1px 2px rgba(0,0,0,.1)}.progress-bar{float:left;width:0;height:100%;font-size:12px;line-height:20px;color:#fff;text-align:center;background-color:#337ab7;-webkit-box-shadow:inset 0 -1px 0 rgba(0,0,0,.15);box-shadow:inset 0 -1px 0 rgba(0,0,0,.15);-webkit-transition:width .6s ease;-o-transition:width .6s ease;transition:width .6s ease}.progress-bar-striped,.progress-striped .progress-bar{background-image:-webkit-linear-gradient(45deg,rgba(255,255,255,.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,.15) 50%,rgba(255,255,255,.15) 75%,transparent 75%,transparent);background-image:-o-linear-gradient(45deg,rgba(255,255,255,.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,.15) 50%,rgba(255,255,255,.15) 75%,transparent 75%,transparent);background-image:linear-gradient(45deg,rgba(255,255,255,.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,.15) 50%,rgba(255,255,255,.15) 75%,transparent 75%,transparent);-webkit-background-size:40px 40px;background-size:40px 40px}.progress-bar.active,.progress.active .progress-bar{-webkit-animation:progress-bar-stripes 2s linear infinite;-o-animation:progress-bar-stripes 2s linear infinite;animation:progress-bar-stripes 2s linear infinite}.progress-bar-success{background-color:#5cb85c}.progress-striped .progress-bar-success{background-image:-webkit-linear-gradient(45deg,rgba(255,255,255,.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,.15) 50%,rgba(255,255,255,.15) 75%,transparent 75%,transparent);background-image:-o-linear-gradient(45deg,rgba(255,255,255,.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,.15) 50%,rgba(255,255,255,.15) 75%,transparent 75%,transparent);background-image:linear-gradient(45deg,rgba(255,255,255,.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,.15) 50%,rgba(255,255,255,.15) 75%,transparent 75%,transparent)}.progress-bar-info{background-color:#5bc0de}.progress-striped .progress-bar-info{background-image:-webkit-linear-gradient(45deg,rgba(255,255,255,.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,.15) 50%,rgba(255,255,255,.15) 75%,transparent 75%,transparent);background-image:-o-linear-gradient(45deg,rgba(255,255,255,.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,.15) 50%,rgba(255,255,255,.15) 75%,transparent 75%,transparent);background-image:linear-gradient(45deg,rgba(255,255,255,.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,.15) 50%,rgba(255,255,255,.15) 75%,transparent 75%,transparent)}.progress-bar-warning{background-color:#f0ad4e}.progress-striped .progress-bar-warning{background-image:-webkit-linear-gradient(45deg,rgba(255,255,255,.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,.15) 50%,rgba(255,255,255,.15) 75%,transparent 75%,transparent);background-image:-o-linear-gradient(45deg,rgba(255,255,255,.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,.15) 50%,rgba(255,255,255,.15) 75%,transparent 75%,transparent);background-image:linear-gradient(45deg,rgba(255,255,255,.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,.15) 50%,rgba(255,255,255,.15) 75%,transparent 75%,transparent)}.progress-bar-danger{background-color:#d9534f}.progress-striped .progress-bar-danger{background-image:-webkit-linear-gradient(45deg,rgba(255,255,255,.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,.15) 50%,rgba(255,255,255,.15) 75%,transparent 75%,transparent);background-image:-o-linear-gradient(45deg,rgba(255,255,255,.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,.15) 50%,rgba(255,255,255,.15) 75%,transparent 75%,transparent);background-image:linear-gradient(45deg,rgba(255,255,255,.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,.15) 50%,rgba(255,255,255,.15) 75%,transparent 75%,transparent)}.media{margin-top:15px}.media:first-child{margin-top:0}.media,.media-body{overflow:hidden;zoom:1}.media-body{width:10000px}.media-object{display:block}.media-right,.media>.pull-right{padding-left:10px}.media-left,.media>.pull-left{padding-right:10px}.media-body,.media-left,.media-right{display:table-cell;vertical-align:top}.media-middle{vertical-align:middle}.media-bottom{vertical-align:bottom}.media-heading{margin-top:0;margin-bottom:5px}.media-list{padding-left:0;list-style:none}.list-group{padding-left:0;margin-bottom:20px}.list-group-item{position:relative;display:block;padding:10px 15px;margin-bottom:-1px;background-color:#fff;border:1px solid #ddd}.list-group-item:first-child{border-top-left-radius:4px;border-top-right-radius:4px}.list-group-item:last-child{margin-bottom:0;border-bottom-right-radius:4px;border-bottom-left-radius:4px}a.list-group-item{color:#555}a.list-group-item .list-group-item-heading{color:#333}a.list-group-item:focus,a.list-group-item:hover{color:#555;text-decoration:none;background-color:#f5f5f5}.list-group-item.disabled,.list-group-item.disabled:focus,.list-group-item.disabled:hover{color:#777;cursor:not-allowed;background-color:#eee}.list-group-item.disabled .list-group-item-heading,.list-group-item.disabled:focus .list-group-item-heading,.list-group-item.disabled:hover .list-group-item-heading{color:inherit}.list-group-item.disabled .list-group-item-text,.list-group-item.disabled:focus .list-group-item-text,.list-group-item.disabled:hover .list-group-item-text{color:#777}.list-group-item.active,.list-group-item.active:focus,.list-group-item.active:hover{z-index:2;color:#fff;background-color:#337ab7;border-color:#337ab7}.list-group-item.active .list-group-item-heading,.list-group-item.active .list-group-item-heading>.small,.list-group-item.active .list-group-item-heading>small,.list-group-item.active:focus .list-group-item-heading,.list-group-item.active:focus .list-group-item-heading>.small,.list-group-item.active:focus .list-group-item-heading>small,.list-group-item.active:hover .list-group-item-heading,.list-group-item.active:hover .list-group-item-heading>.small,.list-group-item.active:hover .list-group-item-heading>small{color:inherit}.list-group-item.active .list-group-item-text,.list-group-item.active:focus .list-group-item-text,.list-group-item.active:hover .list-group-item-text{color:#c7ddef}.list-group-item-success{color:#3c763d;background-color:#dff0d8}a.list-group-item-success{color:#3c763d}a.list-group-item-success .list-group-item-heading{color:inherit}a.list-group-item-success:focus,a.list-group-item-success:hover{color:#3c763d;background-color:#d0e9c6}a.list-group-item-success.active,a.list-group-item-success.active:focus,a.list-group-item-success.active:hover{color:#fff;background-color:#3c763d;border-color:#3c763d}.list-group-item-info{color:#31708f;background-color:#d9edf7}a.list-group-item-info{color:#31708f}a.list-group-item-info .list-group-item-heading{color:inherit}a.list-group-item-info:focus,a.list-group-item-info:hover{color:#31708f;background-color:#c4e3f3}a.list-group-item-info.active,a.list-group-item-info.active:focus,a.list-group-item-info.active:hover{color:#fff;background-color:#31708f;border-color:#31708f}.list-group-item-warning{color:#8a6d3b;background-color:#fcf8e3}a.list-group-item-warning{color:#8a6d3b}a.list-group-item-warning .list-group-item-heading{color:inherit}a.list-group-item-warning:focus,a.list-group-item-warning:hover{color:#8a6d3b;background-color:#faf2cc}a.list-group-item-warning.active,a.list-group-item-warning.active:focus,a.list-group-item-warning.active:hover{color:#fff;background-color:#8a6d3b;border-color:#8a6d3b}.list-group-item-danger{color:#a94442;background-color:#f2dede}a.list-group-item-danger{color:#a94442}a.list-group-item-danger .list-group-item-heading{color:inherit}a.list-group-item-danger:focus,a.list-group-item-danger:hover{color:#a94442;background-color:#ebcccc}a.list-group-item-danger.active,a.list-group-item-danger.active:focus,a.list-group-item-danger.active:hover{color:#fff;background-color:#a94442;border-color:#a94442}.list-group-item-heading{margin-top:0;margin-bottom:5px}.list-group-item-text{margin-bottom:0;line-height:1.3}.panel{margin-bottom:20px;background-color:#fff;border:1px solid transparent;border-radius:4px;-webkit-box-shadow:0 1px 1px rgba(0,0,0,.05);box-shadow:0 1px 1px rgba(0,0,0,.05)}.panel-body{padding:15px}.panel-heading{padding:10px 15px;border-bottom:1px solid transparent;border-top-left-radius:3px;border-top-right-radius:3px}.panel-heading>.dropdown .dropdown-toggle{color:inherit}.panel-title{margin-top:0;margin-bottom:0;font-size:16px;color:inherit}.panel-title>.small,.panel-title>.small>a,.panel-title>a,.panel-title>small,.panel-title>small>a{color:inherit}.panel-footer{padding:10px 15px;background-color:#f5f5f5;border-top:1px solid #ddd;border-bottom-right-radius:3px;border-bottom-left-radius:3px}.panel>.list-group,.panel>.panel-collapse>.list-group{margin-bottom:0}.panel>.list-group .list-group-item,.panel>.panel-collapse>.list-group .list-group-item{border-width:1px 0;border-radius:0}.panel>.list-group:first-child .list-group-item:first-child,.panel>.panel-collapse>.list-group:first-child .list-group-item:first-child{border-top:0;border-top-left-radius:3px;border-top-right-radius:3px}.panel>.list-group:last-child .list-group-item:last-child,.panel>.panel-collapse>.list-group:last-child .list-group-item:last-child{border-bottom:0;border-bottom-right-radius:3px;border-bottom-left-radius:3px}.panel-heading+.list-group .list-group-item:first-child{border-top-width:0}.list-group+.panel-footer{border-top-width:0}.panel>.panel-collapse>.table,.panel>.table,.panel>.table-responsive>.table{margin-bottom:0}.panel>.panel-collapse>.table caption,.panel>.table caption,.panel>.table-responsive>.table caption{padding-right:15px;padding-left:15px}.panel>.table-responsive:first-child>.table:first-child,.panel>.table:first-child{border-top-left-radius:3px;border-top-right-radius:3px}.panel>.table-responsive:first-child>.table:first-child>tbody:first-child>tr:first-child,.panel>.table-responsive:first-child>.table:first-child>thead:first-child>tr:first-child,.panel>.table:first-child>tbody:first-child>tr:first-child,.panel>.table:first-child>thead:first-child>tr:first-child{border-top-left-radius:3px;border-top-right-radius:3px}.panel>.table-responsive:first-child>.table:first-child>tbody:first-child>tr:first-child td:first-child,.panel>.table-responsive:first-child>.table:first-child>tbody:first-child>tr:first-child th:first-child,.panel>.table-responsive:first-child>.table:first-child>thead:first-child>tr:first-child td:first-child,.panel>.table-responsive:first-child>.table:first-child>thead:first-child>tr:first-child th:first-child,.panel>.table:first-child>tbody:first-child>tr:first-child td:first-child,.panel>.table:first-child>tbody:first-child>tr:first-child th:first-child,.panel>.table:first-child>thead:first-child>tr:first-child td:first-child,.panel>.table:first-child>thead:first-child>tr:first-child th:first-child{border-top-left-radius:3px}.panel>.table-responsive:first-child>.table:first-child>tbody:first-child>tr:first-child td:last-child,.panel>.table-responsive:first-child>.table:first-child>tbody:first-child>tr:first-child th:last-child,.panel>.table-responsive:first-child>.table:first-child>thead:first-child>tr:first-child td:last-child,.panel>.table-responsive:first-child>.table:first-child>thead:first-child>tr:first-child th:last-child,.panel>.table:first-child>tbody:first-child>tr:first-child td:last-child,.panel>.table:first-child>tbody:first-child>tr:first-child th:last-child,.panel>.table:first-child>thead:first-child>tr:first-child td:last-child,.panel>.table:first-child>thead:first-child>tr:first-child th:last-child{border-top-right-radius:3px}.panel>.table-responsive:last-child>.table:last-child,.panel>.table:last-child{border-bottom-right-radius:3px;border-bottom-left-radius:3px}.panel>.table-responsive:last-child>.table:last-child>tbody:last-child>tr:last-child,.panel>.table-responsive:last-child>.table:last-child>tfoot:last-child>tr:last-child,.panel>.table:last-child>tbody:last-child>tr:last-child,.panel>.table:last-child>tfoot:last-child>tr:last-child{border-bottom-right-radius:3px;border-bottom-left-radius:3px}.panel>.table-responsive:last-child>.table:last-child>tbody:last-child>tr:last-child td:first-child,.panel>.table-responsive:last-child>.table:last-child>tbody:last-child>tr:last-child th:first-child,.panel>.table-responsive:last-child>.table:last-child>tfoot:last-child>tr:last-child td:first-child,.panel>.table-responsive:last-child>.table:last-child>tfoot:last-child>tr:last-child th:first-child,.panel>.table:last-child>tbody:last-child>tr:last-child td:first-child,.panel>.table:last-child>tbody:last-child>tr:last-child th:first-child,.panel>.table:last-child>tfoot:last-child>tr:last-child td:first-child,.panel>.table:last-child>tfoot:last-child>tr:last-child th:first-child{border-bottom-left-radius:3px}.panel>.table-responsive:last-child>.table:last-child>tbody:last-child>tr:last-child td:last-child,.panel>.table-responsive:last-child>.table:last-child>tbody:last-child>tr:last-child th:last-child,.panel>.table-responsive:last-child>.table:last-child>tfoot:last-child>tr:last-child td:last-child,.panel>.table-responsive:last-child>.table:last-child>tfoot:last-child>tr:last-child th:last-child,.panel>.table:last-child>tbody:last-child>tr:last-child td:last-child,.panel>.table:last-child>tbody:last-child>tr:last-child th:last-child,.panel>.table:last-child>tfoot:last-child>tr:last-child td:last-child,.panel>.table:last-child>tfoot:last-child>tr:last-child th:last-child{border-bottom-right-radius:3px}.panel>.panel-body+.table,.panel>.panel-body+.table-responsive,.panel>.table+.panel-body,.panel>.table-responsive+.panel-body{border-top:1px solid #ddd}.panel>.table>tbody:first-child>tr:first-child td,.panel>.table>tbody:first-child>tr:first-child th{border-top:0}.panel>.table-bordered,.panel>.table-responsive>.table-bordered{border:0}.panel>.table-bordered>tbody>tr>td:first-child,.panel>.table-bordered>tbody>tr>th:first-child,.panel>.table-bordered>tfoot>tr>td:first-child,.panel>.table-bordered>tfoot>tr>th:first-child,.panel>.table-bordered>thead>tr>td:first-child,.panel>.table-bordered>thead>tr>th:first-child,.panel>.table-responsive>.table-bordered>tbody>tr>td:first-child,.panel>.table-responsive>.table-bordered>tbody>tr>th:first-child,.panel>.table-responsive>.table-bordered>tfoot>tr>td:first-child,.panel>.table-responsive>.table-bordered>tfoot>tr>th:first-child,.panel>.table-responsive>.table-bordered>thead>tr>td:first-child,.panel>.table-responsive>.table-bordered>thead>tr>th:first-child{border-left:0}.panel>.table-bordered>tbody>tr>td:last-child,.panel>.table-bordered>tbody>tr>th:last-child,.panel>.table-bordered>tfoot>tr>td:last-child,.panel>.table-bordered>tfoot>tr>th:last-child,.panel>.table-bordered>thead>tr>td:last-child,.panel>.table-bordered>thead>tr>th:last-child,.panel>.table-responsive>.table-bordered>tbody>tr>td:last-child,.panel>.table-responsive>.table-bordered>tbody>tr>th:last-child,.panel>.table-responsive>.table-bordered>tfoot>tr>td:last-child,.panel>.table-responsive>.table-bordered>tfoot>tr>th:last-child,.panel>.table-responsive>.table-bordered>thead>tr>td:last-child,.panel>.table-responsive>.table-bordered>thead>tr>th:last-child{border-right:0}.panel>.table-bordered>tbody>tr:first-child>td,.panel>.table-bordered>tbody>tr:first-child>th,.panel>.table-bordered>thead>tr:first-child>td,.panel>.table-bordered>thead>tr:first-child>th,.panel>.table-responsive>.table-bordered>tbody>tr:first-child>td,.panel>.table-responsive>.table-bordered>tbody>tr:first-child>th,.panel>.table-responsive>.table-bordered>thead>tr:first-child>td,.panel>.table-responsive>.table-bordered>thead>tr:first-child>th{border-bottom:0}.panel>.table-bordered>tbody>tr:last-child>td,.panel>.table-bordered>tbody>tr:last-child>th,.panel>.table-bordered>tfoot>tr:last-child>td,.panel>.table-bordered>tfoot>tr:last-child>th,.panel>.table-responsive>.table-bordered>tbody>tr:last-child>td,.panel>.table-responsive>.table-bordered>tbody>tr:last-child>th,.panel>.table-responsive>.table-bordered>tfoot>tr:last-child>td,.panel>.table-responsive>.table-bordered>tfoot>tr:last-child>th{border-bottom:0}.panel>.table-responsive{margin-bottom:0;border:0}.panel-group{margin-bottom:20px}.panel-group .panel{margin-bottom:0;border-radius:4px}.panel-group .panel+.panel{margin-top:5px}.panel-group .panel-heading{border-bottom:0}.panel-group .panel-heading+.panel-collapse>.list-group,.panel-group .panel-heading+.panel-collapse>.panel-body{border-top:1px solid #ddd}.panel-group .panel-footer{border-top:0}.panel-group .panel-footer+.panel-collapse .panel-body{border-bottom:1px solid #ddd}.panel-default{border-color:#ddd}.panel-default>.panel-heading{color:#333;background-color:#f5f5f5;border-color:#ddd}.panel-default>.panel-heading+.panel-collapse>.panel-body{border-top-color:#ddd}.panel-default>.panel-heading .badge{color:#f5f5f5;background-color:#333}.panel-default>.panel-footer+.panel-collapse>.panel-body{border-bottom-color:#ddd}.panel-primary{border-color:#337ab7}.panel-primary>.panel-heading{color:#fff;background-color:#337ab7;border-color:#337ab7}.panel-primary>.panel-heading+.panel-collapse>.panel-body{border-top-color:#337ab7}.panel-primary>.panel-heading .badge{color:#337ab7;background-color:#fff}.panel-primary>.panel-footer+.panel-collapse>.panel-body{border-bottom-color:#337ab7}.panel-success{border-color:#d6e9c6}.panel-success>.panel-heading{color:#3c763d;background-color:#dff0d8;border-color:#d6e9c6}.panel-success>.panel-heading+.panel-collapse>.panel-body{border-top-color:#d6e9c6}.panel-success>.panel-heading .badge{color:#dff0d8;background-color:#3c763d}.panel-success>.panel-footer+.panel-collapse>.panel-body{border-bottom-color:#d6e9c6}.panel-info{border-color:#bce8f1}.panel-info>.panel-heading{color:#31708f;background-color:#d9edf7;border-color:#bce8f1}.panel-info>.panel-heading+.panel-collapse>.panel-body{border-top-color:#bce8f1}.panel-info>.panel-heading .badge{color:#d9edf7;background-color:#31708f}.panel-info>.panel-footer+.panel-collapse>.panel-body{border-bottom-color:#bce8f1}.panel-warning{border-color:#faebcc}.panel-warning>.panel-heading{color:#8a6d3b;background-color:#fcf8e3;border-color:#faebcc}.panel-warning>.panel-heading+.panel-collapse>.panel-body{border-top-color:#faebcc}.panel-warning>.panel-heading .badge{color:#fcf8e3;background-color:#8a6d3b}.panel-warning>.panel-footer+.panel-collapse>.panel-body{border-bottom-color:#faebcc}.panel-danger{border-color:#ebccd1}.panel-danger>.panel-heading{color:#a94442;background-color:#f2dede;border-color:#ebccd1}.panel-danger>.panel-heading+.panel-collapse>.panel-body{border-top-color:#ebccd1}.panel-danger>.panel-heading .badge{color:#f2dede;background-color:#a94442}.panel-danger>.panel-footer+.panel-collapse>.panel-body{border-bottom-color:#ebccd1}.embed-responsive{position:relative;display:block;height:0;padding:0;overflow:hidden}.embed-responsive .embed-responsive-item,.embed-responsive embed,.embed-responsive iframe,.embed-responsive object,.embed-responsive video{position:absolute;top:0;bottom:0;left:0;width:100%;height:100%;border:0}.embed-responsive-16by9{padding-bottom:56.25%}.embed-responsive-4by3{padding-bottom:75%}.well{min-height:20px;padding:19px;margin-bottom:20px;background-color:#f5f5f5;border:1px solid #e3e3e3;border-radius:4px;-webkit-box-shadow:inset 0 1px 1px rgba(0,0,0,.05);box-shadow:inset 0 1px 1px rgba(0,0,0,.05)}.well blockquote{border-color:#ddd;border-color:rgba(0,0,0,.15)}.well-lg{padding:24px;border-radius:6px}.well-sm{padding:9px;border-radius:3px}.close{float:right;font-size:21px;font-weight:700;line-height:1;color:#000;text-shadow:0 1px 0 #fff;filter:alpha(opacity=20);opacity:.2}.close:focus,.close:hover{color:#000;text-decoration:none;cursor:pointer;filter:alpha(opacity=50);opacity:.5}button.close{-webkit-appearance:none;padding:0;cursor:pointer;background:0 0;border:0}.modal-open{overflow:hidden}.modal{position:fixed;top:0;right:0;bottom:0;left:0;z-index:1050;display:none;overflow:hidden;-webkit-overflow-scrolling:touch;outline:0}.modal.fade .modal-dialog{-webkit-transition:-webkit-transform .3s ease-out;-o-transition:-o-transform .3s ease-out;transition:transform .3s ease-out;-webkit-transform:translate(0,-25%);-ms-transform:translate(0,-25%);-o-transform:translate(0,-25%);transform:translate(0,-25%)}.modal.in .modal-dialog{-webkit-transform:translate(0,0);-ms-transform:translate(0,0);-o-transform:translate(0,0);transform:translate(0,0)}.modal-open .modal{overflow-x:hidden;overflow-y:auto}.modal-dialog{position:relative;width:auto;margin:10px}.modal-content{position:relative;background-color:#fff;-webkit-background-clip:padding-box;background-clip:padding-box;border:1px solid #999;border:1px solid rgba(0,0,0,.2);border-radius:6px;outline:0;-webkit-box-shadow:0 3px 9px rgba(0,0,0,.5);box-shadow:0 3px 9px rgba(0,0,0,.5)}.modal-backdrop{position:fixed;top:0;right:0;bottom:0;left:0;z-index:1040;background-color:#000}.modal-backdrop.fade{filter:alpha(opacity=0);opacity:0}.modal-backdrop.in{filter:alpha(opacity=50);opacity:.5}.modal-header{min-height:16.43px;padding:15px;border-bottom:1px solid #e5e5e5}.modal-header .close{margin-top:-2px}.modal-title{margin:0;line-height:1.42857143}.modal-body{position:relative;padding:15px}.modal-footer{padding:15px;text-align:right;border-top:1px solid #e5e5e5}.modal-footer .btn+.btn{margin-bottom:0;margin-left:5px}.modal-footer .btn-group .btn+.btn{margin-left:-1px}.modal-footer .btn-block+.btn-block{margin-left:0}.modal-scrollbar-measure{position:absolute;top:-9999px;width:50px;height:50px;overflow:scroll}@media (min-width:768px){.modal-dialog{width:600px;margin:30px auto}.modal-content{-webkit-box-shadow:0 5px 15px rgba(0,0,0,.5);box-shadow:0 5px 15px rgba(0,0,0,.5)}.modal-sm{width:300px}}@media (min-width:992px){.modal-lg{width:900px}}.tooltip{position:absolute;z-index:1070;display:block;font-family:"Helvetica Neue",Helvetica,Arial,sans-serif;font-size:12px;font-weight:400;line-height:1.4;filter:alpha(opacity=0);opacity:0}.tooltip.in{filter:alpha(opacity=90);opacity:.9}.tooltip.top{padding:5px 0;margin-top:-3px}.tooltip.right{padding:0 5px;margin-left:3px}.tooltip.bottom{padding:5px 0;margin-top:3px}.tooltip.left{padding:0 5px;margin-left:-3px}.tooltip-inner{max-width:200px;padding:3px 8px;color:#fff;text-align:center;text-decoration:none;background-color:#000;border-radius:4px}.tooltip-arrow{position:absolute;width:0;height:0;border-color:transparent;border-style:solid}.tooltip.top .tooltip-arrow{bottom:0;left:50%;margin-left:-5px;border-width:5px 5px 0;border-top-color:#000}.tooltip.top-left .tooltip-arrow{right:5px;bottom:0;margin-bottom:-5px;border-width:5px 5px 0;border-top-color:#000}.tooltip.top-right .tooltip-arrow{bottom:0;left:5px;margin-bottom:-5px;border-width:5px 5px 0;border-top-color:#000}.tooltip.right .tooltip-arrow{top:50%;left:0;margin-top:-5px;border-width:5px 5px 5px 0;border-right-color:#000}.tooltip.left .tooltip-arrow{top:50%;right:0;margin-top:-5px;border-width:5px 0 5px 5px;border-left-color:#000}.tooltip.bottom .tooltip-arrow{top:0;left:50%;margin-left:-5px;border-width:0 5px 5px;border-bottom-color:#000}.tooltip.bottom-left .tooltip-arrow{top:0;right:5px;margin-top:-5px;border-width:0 5px 5px;border-bottom-color:#000}.tooltip.bottom-right .tooltip-arrow{top:0;left:5px;margin-top:-5px;border-width:0 5px 5px;border-bottom-color:#000}.popover{position:absolute;top:0;left:0;z-index:1060;display:none;max-width:276px;padding:1px;font-family:"Helvetica Neue",Helvetica,Arial,sans-serif;font-size:14px;font-weight:400;line-height:1.42857143;text-align:left;white-space:normal;background-color:#fff;-webkit-background-clip:padding-box;background-clip:padding-box;border:1px solid #ccc;border:1px solid rgba(0,0,0,.2);border-radius:6px;-webkit-box-shadow:0 5px 10px rgba(0,0,0,.2);box-shadow:0 5px 10px rgba(0,0,0,.2)}.popover.top{margin-top:-10px}.popover.right{margin-left:10px}.popover.bottom{margin-top:10px}.popover.left{margin-left:-10px}.popover-title{padding:8px 14px;margin:0;font-size:14px;background-color:#f7f7f7;border-bottom:1px solid #ebebeb;border-radius:5px 5px 0 0}.popover-content{padding:9px 14px}.popover>.arrow,.popover>.arrow:after{position:absolute;display:block;width:0;height:0;border-color:transparent;border-style:solid}.popover>.arrow{border-width:11px}.popover>.arrow:after{content:"";border-width:10px}.popover.top>.arrow{bottom:-11px;left:50%;margin-left:-11px;border-top-color:#999;border-top-color:rgba(0,0,0,.25);border-bottom-width:0}.popover.top>.arrow:after{bottom:1px;margin-left:-10px;content:" ";border-top-color:#fff;border-bottom-width:0}.popover.right>.arrow{top:50%;left:-11px;margin-top:-11px;border-right-color:#999;border-right-color:rgba(0,0,0,.25);border-left-width:0}.popover.right>.arrow:after{bottom:-10px;left:1px;content:" ";border-right-color:#fff;border-left-width:0}.popover.bottom>.arrow{top:-11px;left:50%;margin-left:-11px;border-top-width:0;border-bottom-color:#999;border-bottom-color:rgba(0,0,0,.25)}.popover.bottom>.arrow:after{top:1px;margin-left:-10px;content:" ";border-top-width:0;border-bottom-color:#fff}.popover.left>.arrow{top:50%;right:-11px;margin-top:-11px;border-right-width:0;border-left-color:#999;border-left-color:rgba(0,0,0,.25)}.popover.left>.arrow:after{right:1px;bottom:-10px;content:" ";border-right-width:0;border-left-color:#fff}.carousel{position:relative}.carousel-inner{position:relative;width:100%;overflow:hidden}.carousel-inner>.item{position:relative;display:none;-webkit-transition:.6s ease-in-out left;-o-transition:.6s ease-in-out left;transition:.6s ease-in-out left}.carousel-inner>.item>a>img,.carousel-inner>.item>img{line-height:1}@media all and (transform-3d),(-webkit-transform-3d){.carousel-inner>.item{-webkit-transition:-webkit-transform .6s ease-in-out;-o-transition:-o-transform .6s ease-in-out;transition:transform .6s ease-in-out;-webkit-backface-visibility:hidden;backface-visibility:hidden;-webkit-perspective:1000;perspective:1000}.carousel-inner>.item.active.right,.carousel-inner>.item.next{left:0;-webkit-transform:translate3d(100%,0,0);transform:translate3d(100%,0,0)}.carousel-inner>.item.active.left,.carousel-inner>.item.prev{left:0;-webkit-transform:translate3d(-100%,0,0);transform:translate3d(-100%,0,0)}.carousel-inner>.item.active,.carousel-inner>.item.next.left,.carousel-inner>.item.prev.right{left:0;-webkit-transform:translate3d(0,0,0);transform:translate3d(0,0,0)}}.carousel-inner>.active,.carousel-inner>.next,.carousel-inner>.prev{display:block}.carousel-inner>.active{left:0}.carousel-inner>.next,.carousel-inner>.prev{position:absolute;top:0;width:100%}.carousel-inner>.next{left:100%}.carousel-inner>.prev{left:-100%}.carousel-inner>.next.left,.carousel-inner>.prev.right{left:0}.carousel-inner>.active.left{left:-100%}.carousel-inner>.active.right{left:100%}.carousel-control{position:absolute;top:0;bottom:0;left:0;width:15%;font-size:20px;color:#fff;text-align:center;text-shadow:0 1px 2px rgba(0,0,0,.6);filter:alpha(opacity=50);opacity:.5}.carousel-control.left{background-image:-webkit-linear-gradient(left,rgba(0,0,0,.5) 0,rgba(0,0,0,.0001) 100%);background-image:-o-linear-gradient(left,rgba(0,0,0,.5) 0,rgba(0,0,0,.0001) 100%);background-image:-webkit-gradient(linear,left top,right top,from(rgba(0,0,0,.5)),to(rgba(0,0,0,.0001)));background-image:linear-gradient(to right,rgba(0,0,0,.5) 0,rgba(0,0,0,.0001) 100%);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#80000000', endColorstr='#00000000', GradientType=1);background-repeat:repeat-x}.carousel-control.right{right:0;left:auto;background-image:-webkit-linear-gradient(left,rgba(0,0,0,.0001) 0,rgba(0,0,0,.5) 100%);background-image:-o-linear-gradient(left,rgba(0,0,0,.0001) 0,rgba(0,0,0,.5) 100%);background-image:-webkit-gradient(linear,left top,right top,from(rgba(0,0,0,.0001)),to(rgba(0,0,0,.5)));background-image:linear-gradient(to right,rgba(0,0,0,.0001) 0,rgba(0,0,0,.5) 100%);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#00000000', endColorstr='#80000000', GradientType=1);background-repeat:repeat-x}.carousel-control:focus,.carousel-control:hover{color:#fff;text-decoration:none;filter:alpha(opacity=90);outline:0;opacity:.9}.carousel-control .glyphicon-chevron-left,.carousel-control .glyphicon-chevron-right,.carousel-control .icon-next,.carousel-control .icon-prev{position:absolute;top:50%;z-index:5;display:inline-block}.carousel-control .glyphicon-chevron-left,.carousel-control .icon-prev{left:50%;margin-left:-10px}.carousel-control .glyphicon-chevron-right,.carousel-control .icon-next{right:50%;margin-right:-10px}.carousel-control .icon-next,.carousel-control .icon-prev{width:20px;height:20px;margin-top:-10px;font-family:serif;line-height:1}.carousel-control .icon-prev:before{content:'\2039'}.carousel-control .icon-next:before{content:'\203a'}.carousel-indicators{position:absolute;bottom:10px;left:50%;z-index:15;width:60%;padding-left:0;margin-left:-30%;text-align:center;list-style:none}.carousel-indicators li{display:inline-block;width:10px;height:10px;margin:1px;text-indent:-999px;cursor:pointer;background-color:#000 \9;background-color:rgba(0,0,0,0);border:1px solid #fff;border-radius:10px}.carousel-indicators .active{width:12px;height:12px;margin:0;background-color:#fff}.carousel-caption{position:absolute;right:15%;bottom:20px;left:15%;z-index:10;padding-top:20px;padding-bottom:20px;color:#fff;text-align:center;text-shadow:0 1px 2px rgba(0,0,0,.6)}.carousel-caption .btn{text-shadow:none}@media screen and (min-width:768px){.carousel-control .glyphicon-chevron-left,.carousel-control .glyphicon-chevron-right,.carousel-control .icon-next,.carousel-control .icon-prev{width:30px;height:30px;margin-top:-15px;font-size:30px}.carousel-control .glyphicon-chevron-left,.carousel-control .icon-prev{margin-left:-15px}.carousel-control .glyphicon-chevron-right,.carousel-control .icon-next{margin-right:-15px}.carousel-caption{right:20%;left:20%;padding-bottom:30px}.carousel-indicators{bottom:20px}}.btn-group-vertical>.btn-group:after,.btn-group-vertical>.btn-group:before,.btn-toolbar:after,.btn-toolbar:before,.clearfix:after,.clearfix:before,.container-fluid:after,.container-fluid:before,.container:after,.container:before,.dl-horizontal dd:after,.dl-horizontal dd:before,.form-horizontal .form-group:after,.form-horizontal .form-group:before,.modal-footer:after,.modal-footer:before,.nav:after,.nav:before,.navbar-collapse:after,.navbar-collapse:before,.navbar-header:after,.navbar-header:before,.navbar:after,.navbar:before,.pager:after,.pager:before,.panel-body:after,.panel-body:before,.row:after,.row:before{display:table;content:" "}.btn-group-vertical>.btn-group:after,.btn-toolbar:after,.clearfix:after,.container-fluid:after,.container:after,.dl-horizontal dd:after,.form-horizontal .form-group:after,.modal-footer:after,.nav:after,.navbar-collapse:after,.navbar-header:after,.navbar:after,.pager:after,.panel-body:after,.row:after{clear:both}.center-block{display:block;margin-right:auto;margin-left:auto}.pull-right{float:right!important}.pull-left{float:left!important}.hide{display:none!important}.show{display:block!important}.invisible{visibility:hidden}.text-hide{font:0/0 a;color:transparent;text-shadow:none;background-color:transparent;border:0}.hidden{display:none!important}.affix{position:fixed}@-ms-viewport{width:device-width}.visible-lg,.visible-md,.visible-sm,.visible-xs{display:none!important}.visible-lg-block,.visible-lg-inline,.visible-lg-inline-block,.visible-md-block,.visible-md-inline,.visible-md-inline-block,.visible-sm-block,.visible-sm-inline,.visible-sm-inline-block,.visible-xs-block,.visible-xs-inline,.visible-xs-inline-block{display:none!important}@media (max-width:767px){.visible-xs{display:block!important}table.visible-xs{display:table}tr.visible-xs{display:table-row!important}td.visible-xs,th.visible-xs{display:table-cell!important}}@media (max-width:767px){.visible-xs-block{display:block!important}}@media (max-width:767px){.visible-xs-inline{display:inline!important}}@media (max-width:767px){.visible-xs-inline-block{display:inline-block!important}}@media (min-width:768px)and (max-width:991px){.visible-sm{display:block!important}table.visible-sm{display:table}tr.visible-sm{display:table-row!important}td.visible-sm,th.visible-sm{display:table-cell!important}}@media (min-width:768px)and (max-width:991px){.visible-sm-block{display:block!important}}@media (min-width:768px)and (max-width:991px){.visible-sm-inline{display:inline!important}}@media (min-width:768px)and (max-width:991px){.visible-sm-inline-block{display:inline-block!important}}@media (min-width:992px)and (max-width:1199px){.visible-md{display:block!important}table.visible-md{display:table}tr.visible-md{display:table-row!important}td.visible-md,th.visible-md{display:table-cell!important}}@media (min-width:992px)and (max-width:1199px){.visible-md-block{display:block!important}}@media (min-width:992px)and (max-width:1199px){.visible-md-inline{display:inline!important}}@media (min-width:992px)and (max-width:1199px){.visible-md-inline-block{display:inline-block!important}}@media (min-width:1200px){.visible-lg{display:block!important}table.visible-lg{display:table}tr.visible-lg{display:table-row!important}td.visible-lg,th.visible-lg{display:table-cell!important}}@media (min-width:1200px){.visible-lg-block{display:block!important}}@media (min-width:1200px){.visible-lg-inline{display:inline!important}}@media (min-width:1200px){.visible-lg-inline-block{display:inline-block!important}}@media (max-width:767px){.hidden-xs{display:none!important}}@media (min-width:768px)and (max-width:991px){.hidden-sm{display:none!important}}@media (min-width:992px)and (max-width:1199px){.hidden-md{display:none!important}}@media (min-width:1200px){.hidden-lg{display:none!important}}.visible-print{display:none!important}@media print{.visible-print{display:block!important}table.visible-print{display:table}tr.visible-print{display:table-row!important}td.visible-print,th.visible-print{display:table-cell!important}}.visible-print-block{display:none!important}@media print{.visible-print-block{display:block!important}}.visible-print-inline{display:none!important}@media print{.visible-print-inline{display:inline!important}}.visible-print-inline-block{display:none!important}@media print{.visible-print-inline-block{display:inline-block!important}}@media print{.hidden-print{display:none!important}}
\ No newline at end of file
vendor/QmdDfkqDWheE4gsCXNrhixwTwSHnZMPT2cGLcNbiBNcMyU/dir-index-html/gw-assets/icons.css deleted
-384
@@ -1,384 +0,0 @@
1 -
2 -.ipfs-_blank {
3 - background-image: url('data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAAWBJREFUeNqEUj1LxEAQnd1MVA4lyIEWx6UIKEGUExGsbC3tLfwJ/hT/g7VlCnubqxXBwg/Q4hQP/LhKL5nZuBsvuGfW5MGyuzM7jzdvVuR5DgYnZ+f99ai7Vt5t9K9unu4HLweI3qWYxI6PDosdy0fhcntxO44CcOBzPA7mfEyuHwf7ntQk4jcnywOxIlfxOCNYaLVgb6cXbkTdhJXq2SIlNMC0xIqhHczDbi8OVzpLSUa0WebRfmigLHqj1EcPZnwf7gbDIrYVRyEinurj6jTBHyI7pqVrFQqEbt6TEmZ9v1NRAJNC1xTYxIQh/MmRUlmFQE3qWOW1nqB2TWk1/3tgJV0waVvkFIEeZbHq4ElyKzAmEXOx6gnEVJuWBzmkRJBRPYGZBDsVaOlpSgVJE2yVaAe/0kx/3azBRO0VsbMFZE3CDSZKweZfYIVg+DZ6v7h9GDVOwZPw/PoxKu/fAgwALbDAXf7DdQkAAAAASUVORK5CYII=');
4 - background-repeat: no-repeat;
5 - background-size: contain;
6 -}
7 -
8 -.ipfs-_page {
9 - background-image: url('data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAAmhJREFUeNpsUztv01AYPfdhOy/XTZ80VV1VoCqlA2zQqUgwMEErWBALv4GJDfEDmOEHsFTqVCTExAiiSI2QEKJKESVFFBWo04TESRzfy2c7LY/kLtf2d8+555zvM9NaI1ora5svby9OnbUEBxgDlIKiWjXQeLy19/X17sEtcPY2rtHS96/Hu0RvXXLz+cUzM87zShsI29DpHCYt4E6Box4IZzTnbDx7V74GjhOSfwgE0H2638K9h08A3iHGVbjTw7g6YmAyw/BgecHNGGJjvfQhIfmfIFDAXJpjuugi7djIFVI4P0plctgJQ0xnFe5eOO02OwEp2VkhSCnC8WOCdqgwnzFx4/IyppwRVN+XYXsecqZA1pB48ekAnw9/4GZx3L04N/GoTwEjX4cNH5vlPfjtAIYp8cWrQutxrC5Mod3VsXVTMFSqtaE+gl9dhaUxE2tXZiF7nYiiatJ3v5s8R/1yOCNLOuwjkELiTbmC9dJHpIaGASsDkoFQGJQwHWMcHWJYOmUj1OjvQotuytt5nHMLEGkCyx6QU384jwkUAd2sxJbS/QShZtg/8rHzzQOzSaFhxQrA6YgQMQHojCUlgnCAAvKFBoXXaHfArSCZDE0gyWJgFIKmvUFKO4MUNIk2a4+hODtDUVuJ/J732AKS6ZtImdTyAQQB3bZN8l9t75IFh0JMUdVKsohsUPqRgnka0tYgggYpCHkKGTsHI5NOMojB4iTICCepvX53AIEfQta1iUCmoTiBmdEri2RgddKFhuJoqb/af/yw/d3zTNM6UkaOfis62aUgddAbnz+rXuPY+Vnzjt9/CzAAbmLjCrfBiRgAAAAASUVORK5CYII=');
10 - background-repeat: no-repeat;
11 - background-size: contain;
12 -}
13 -
14 -.ipfs-aac {
15 - background-image: url('data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAAnhJREFUeNp0Uk1PE0EYftruVlvAUkhVEPoBcsEoLRJBY01MPHjCs3cvogcT/4qJJN5NvHhoohcOnPw4YEGIkCh+oLGBKm3Z7nZ3dme2vjOhTcjiJJvZzPvOM8/HG2q325Dr3kLp7Y1ibpIxjs4KhQBZfvV6s7K5Vb0bjeof5ZlcGysP1a51mifODybvzE8mzCbrAoTDIThMoGXZiZ4YSiurf+Z1XeuCqJ7Oj+sK3jQcNAmg8xkGQ71mYejcAB49vpmeuzJccl0+dUj6KIAvfHCPg3N+uAv4vg9BOxcCmfEzuP/genpmeqhEMgude10Jwm+DuUIyUdTlqu2byoMfX/dRermBeExHsTiWNi3+lMpzRwDki8zxCIATmzbevfmClukiP5NFhJgwkjeRTeLShdOoVJqnAgwkgCAZ6+UdLC9twjQZ8pdzioFkZBHY3q6B3l4dJEEEPOCeD4cYVH7Xsf15F+FImC775INAJBJSkVoWo0QY9YqgiR4ZZzRaGBkdwK3bFxGLRZUfB3Rm2x4x9CGtsUxH9QYkKICDFuLxKAozGZwdTqBRs2FbLlXbiPdECMCHadj/AaDXZNFqedCIvnRcS4UpRo7+hC5zUmw8Ope9wUFinvpmZ7NKt2RTmB4hKZo6n8qP4Oq1HBkKlVYAQBrUlziB0XQSif4YmQhksgNIJk9iaLhPaV9b/Um+uJSCdzyDbGZQRSkvjo+n4JNxubGUSsCj+ZCpODYjkGMAND2k7exUsfhkCd+29yguB88Wl7FW/o6tT7/gcXqAgGv7hhx1LWBireHVn79YP6ChQ3njb/eFlfWqGqT3H3ZlGIhGI2i2UO/U/wkwAAmoalcxlNA1AAAAAElFTkSuQmCC');
16 - background-repeat: no-repeat;
17 - background-size: contain;
18 -}
19 -
20 -.ipfs-ai {
21 - background-image: url('data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAAk5JREFUeNpsU01vElEUPTPzZqBAQaSFQiJYUmlKYhoTF41L3Tbu/Q/+AvsX3Bp/gPsuWLrqyqQ7TUxMtAvF1tYGoXwNw7wv7zwYgtKX3Lw379575p5z77O01ohW+/DVh8zj7aYKhflGdG9ZsGwLNydffgVfr19YHvsEa+Zu/nxndob5StQK+dyzvZzyw/gKlmMj7IygFM+xvNcanp4/t5dAomXHBy2UUBOO2MAl/B9/cPb6PULuoHx0WM0e3GvpUOxD3wZAJWutZqYUYmqpSg5OMgH3YQObL59W0/ullpryR3HegkKEqiWBSGV4R3vQ7sIhScTZFTpHx3A215B5sluVY/WWMg7+ATB/lcLsKpTonHzD+OMFEuTz8ikkt9Kwt9YJZB38cpBdoQAZJdLvCGByfoPB6Xdk90pYy6Xg3c/DaWwArg09DaG5lCsUFN0pckZAojdC8m4auBqaALuSgez7VB1RtDSUWOQvUaBLFUzJBMJ2DwmPgd1Jwm0WoSgJfjDvrTKxtwAIyEkAOQ5hU//Zdg5uowDlUNMnwZLW0sSuUuACYhwQRwFvJxupCjEYUUccOkoaKmdOlZnY1TkgAcXAhxhOwLsDsHoN3u4O5JTDfVCH6I9nfjId3gIgSUATFJk/hVevGtOMwS0XwQ3AzB/FrlKg8Q27I2javVoZrFgwD4qVipAEyMlnaFArzaj/D0DiMXlJAFQyK2r8fnMMRZp4lQ1MaSL5tU/1kqAkMCh2tYI+7+kh70cjPbr4bEZ51jZr8TJnB9PJXpz3V4ABAPOQVJn2Q60GAAAAAElFTkSuQmCC');
22 - background-repeat: no-repeat;
23 - background-size: contain;
24 -}
25 -
26 -.ipfs-aiff {
27 - background-image: url('data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAAohJREFUeNpkU9tqE1EUXZmZpE3aTBLbJFPTtFURtSCthr7UCyKKFJ/9An3og6Ag/oXfoUj7og9asCBYKT6UIPHaWtpq7NU2aZK5z5wZ9xxMpMwZDuewz9prr32ZiO/7CNaDx3OLt6fOjBqGg/aKRCIInp8+KzfKH7fudnVF58nE16el+/yU2mBFSWZKpWJKVc0OgUBo02K4NDmU6o75Mx+Wdu9IUXFeiOA/pn1xHeYaugVDdzpbp91qGlAKGTx8dC19/Wpxhjnsxj/RRwk85hGJC9d1O6fneWAuoztDYSSLe9OT6SuXB2ccx73Z9uukwDwfls1g0xZIY/Ad/Gnyt/XVfbyYrSDRE8PExHB6/8B6QuaxIwRBFMt0iIAiMx+LCys8jfGJEUik2WpZOD2SQf9oDtVqQwopCAiY66FS/om3b75CVS2MlU7AJ2WiJBCZjZ2dJuRkDJZFwFAR7UCBja3fNfxY2YEoCtRCj9em3Tpds6FpJseGCBxS0GgYGBzqw62p84gnYnAI2CSbSbPhEpFAaE2zODaUAlWWwDoS5DheGqbWpVE/0CmqCY9qkEyINBceb2uADRNQ8bSWAVVzIFKomCQim+0luS4yKYlsHlRyZo7EsSEC23K5vAsXh/H92zZkuRvxeBS5nEx2yp2KqhxPoV5TYS/8CtdApylM9sZQKKSQzyeRTseRV2QoAzIYY8jme5DN9fI0dQoUIjANGydP9VM7PZw9p/AiBpNYrdbw/t0yTJqRtdU9UrfJCUMpSJIgbWzsYe51BcViHzLHeqCRqhZ1YX1tFwNfZBxS9O3NWkAcHqR606k/n/3coKAoV/Y7vQ/OYCZevlrmv3c0GsFh06u3/f4KMABvSWfDHmbK2gAAAABJRU5ErkJggg==');
28 - background-repeat: no-repeat;
29 - background-size: contain;
30 -}
31 -
32 -.ipfs-avi {
33 - background-image: url('data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAAm1JREFUeNpsU8tu00AUPXZcN0nzTpq2KQ3pAwkIAnWHqCoeexBb+AQ+ABZ8A2s+AIkdm266QUJIFWKBkHg1KpRHi5omJGkbJ3bGHj+4M1EQrTvSyGPPueeec++1EgQBxHp+/9mbyuriRZdxjJaiKBD3W+u1+p9a856max+gDO8ebT+WT20Ezi9NZi/crqadvn2MQBAGfpCOpqNru2937vxPIpY6Onjccx3Twck9MBiSU0ncfHirXFmZX3Md9wqCUwiEVN/zaQfHt0vfbBe5uQyuPVgpl5Zn11ybL4/i/lkICOw5niQRGQShoiqI6Bo43W2ub8n3hRtLZT7gTynk6gkCX9gAOxpAnxhHZDwC1/aI1EViJolu/QhKRMHZ1UX0Gr1USIEn5FPWHy+/wTokkrQOq2vBaHZBN4hmY9Jwfr4An/teiEB45ZZDwDiMhoExT0N+sYDCuUkkplLIlXP4/XEXdo+RUhdhBSSfUwtVTUG8MIHK9QVqI7D/uY6vr2pwmCPrkz+Tk9gwARWQ9WxppbXZhNnpw+ya4A5HZi6L4lIR8WyCcL6sTZiAWjWgAmpxkn5+kqTamK6WkCwmERmLDLvjB0ML9ikWXPLFuozYOap3L8HYN6DHdbS/d5CeTVBndBz87FCBLYkNTyIjBQemnIEsSY5lYrK1+UoWcToLMjEHAyIQ2BCBSx/NVh+ZUhrqmEqBebS3WyhdLg0zt/ugAaIklsSGLHCLa6zDMGhZ2HjyGsnpFPqNHnY2fmHv3R5SMymYbROszSQ2ROAY9qHiofvlxSc5xsKKqqnY3diRE9h4X5d/pzg7lnM4ivsrwADe9Wg/CQJgFAAAAABJRU5ErkJggg==');
34 - background-repeat: no-repeat;
35 - background-size: contain;
36 -}
37 -
38 -.ipfs-bmp {
39 - background-image: url('data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAAmZJREFUeNp0U+1rUlEY/13v9YV0vq2wttI5CdpL9aEGBZUDv0df668I6n+or0UQ/RuuD0EgVDAZrsKF4AR1a6COKW5qXvXec27PuVeda3bgcF6e8/ye5/d7niMZhgExnK9fbTrm5pbBGMZDkgCyq+VyhTUaT6Eo2ZHJePPWXJXRhez3B1yxmM/QdctXUSCgtV4Py4CvY3cky4e1x5DlLCaGbbzjXDcousG5OQe5HPRSCQPK4PpsEM/XH4WvhS4noeu3JwHGGRiULhsMoKZS4I0GtEIB9mgULJGA0+9DPBpBT7sffvf1W/Lg6OgJufw8C0CRGEXWazUwiiyFQjA8bsjVKjaJzovMD/Q5gxyJhG2cvyeXe2cAuADQNGBmBvLaGuTFRaDfh31lBTWi9pumjbK0B4JQul3vOQpM8JdskOLrdCvDcDjAsjtg5TIkoiKLaokMNR2cnZbqNAMycqG7XbHKR2fMzwO/dsxSwu0BiBJsNsv2LwAJAJCI5ux2gXYbqNetcz5PoORI1cDS0n8AxGW7A+zvEYBKZ2ZlcsEtJLbedMjePBaCTQMghx45ulyWkzxMVUQ2RMQhLfFO16YAqCrixPnm6iqKrRb2W23EfF4cUNSrHg90cr7hDyB33MTnSmUKALVs4uIlROjxg+AsPhGVl3fuIl2tIOB0Ya91gkOi9mxhAal0ekork1ic/kGLBORMxy2K1qS9V1ZQbNThIj2EGh+2tsyOnSai8r1UxMNIBB+LRTTULr4Uds0K1tU/uOLxIrmbNz8XXSrnASSpubG9fbKRyVh1n/zSw29t9oC1b47MfwUYAAUsLiWr4QUJAAAAAElFTkSuQmCC');
40 - background-repeat: no-repeat;
41 - background-size: contain;
42 -}
43 -
44 -.ipfs-c {
45 - background-image: url('data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAAcxJREFUeNqEUk1rE0EYfmZnkgoJCaGNCehuJTalhJZSUZB66a0HwXsP/Qn+FM+9+hty0LNYCr2I7UVLIW0Fc0hpQpSS7O7MrO9MspuvVV8YMnk/nn2e5x0WRRFMvP/w6WSz5jbi/9NxfP693Wp3DrJCnMW5d28P7a+IE15lufR8o1ZEStwPhkWHsWbrZ+eNEPxsuubEF6m0TBv2Q4liPofXuzveulttSqW2UwH+GjqC0horpSL2njU89+FyMwjlTlxOJMTa9ZQHzDQIjgwdom9zLzfXPc75kbnOAswBJTlC2XrqQRMLxhi442DgB4UFBhgPpm3B5pgBHNUUxQKAHs8pHf3TEuFMetM9IKr/i2mWMwC0SnuSFTG2YKyppwKYVdGO7TFhzBqGIenVeLCUtfURgErucx5ECKREKBU4d3B718PHz6cICGT/1Qs8qpQtGOdyhtGEARWDQFqQJSeDL98u4VbLaKw9IRAJPwjtoJGlVAoDQ800+fRFTTYXcjlcXN2g++s36p5Lzzlve1iEROa8BGH1EbrSAeqrjxEqicHQt8/YSDHMpaNs7wJAp9vvfb287idboAVkRAa5fBYXP9rxO4Mgf0xvPPdHgAEA8OoGd40i1j0AAAAASUVORK5CYII=');
46 - background-repeat: no-repeat;
47 - background-size: contain;
48 -}
49 -
50 -.ipfs-cpp {
51 - background-image: url('data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAAfJJREFUeNqEUs9PE0EU/mZ2WgqpXX+QIDFdalVslh8NlAOQaOKFAwfvHvwT/FM8e/U/MOnBmwcj8WD0ACEGghIkbU0baaEthe3OTJ0ZWV26q37JZt68ee/b9733yGAwgMbL12/fz+azbnAPY2Nrt7Zfqz9JMrYZ+J4/e2pOFjiciRvXlgp5GzHonXk2o6S8V6k/TjBrM/xGA4MLyeOSPZ8jkx7D+uqCU3Amy1yIYizB36AlCSkwfjWDR4uu40yMl/s+XwjeWThQQ4Z6QNSnSkYykcDXasP4lmfvOZTSF9q8TDBEFPbN5bOqCglCCCxK0TvvZyIV4CIxbgpC+4gm/PUmFCIE8iJPyME/e8Lon9j4HvyHYLjKSwRCSEUgf9+15mFbx8QS6CZJMzJ9SlBCwX3fJDLG4PX7ykcwkmQmJtpEhWa7g1dvNlSwjwelebz7tAXLolh0p/Fxe9fErK2WDFGEgKjxfNjegX0lDTc/heNuF99/HGEslcKXwyoazWNDdlCr6+DoJgrBzdI0T9rYO6yg2zszMlaKM3Dv5OBzbuyZuzm1B16U4Nzz2f3cFOx0Gq12F9cztpExncsqYoaHpSIKtx0zJdVIFpHQ6py29muNk1uTN829o/6SHEnh80HFaE6NjmLnWxUJy1LyTltB3k8BBgBeEeQTiWRskAAAAABJRU5ErkJggg==');
52 - background-repeat: no-repeat;
53 - background-size: contain;
54 -}
55 -
56 -.ipfs-css {
57 - background-image: url('data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAAk1JREFUeNpsUktvUlEQ/u5DoCLl/RAKKKUvWmIxjYntQtcu3LvwJ/hTXLt16coFC2PsojEaMKZtCqFaTdGmjbS0CG3By+vei3OOBSGXSU7uzNyZ78z3zRF6vR6YvXzzPrMUCyf68bB9zO+VfpROn5hkOdfPPX/2lH/lfiLidztX5mN2jLGG0rKLENIE8liWpdzwP7HvqJqujmvudFU4bFY8Wk1FZsOBtKppd8YCDNu77CZevd3gflfTUFcUhP0ePLibiIR9rjSBpgwAfe4dVcV6dhtep4PH5msylGYLrzeybErcT85FYiH/CyPAf74gObC2vMhzsiRhPhpC6eQUM+EA1pJzILEnjRSuJsju7MJqsUCSRei6Dp3yXqcdGlHZ/rLPazQWGCn8+6YW4pAkEW0SjzUzanWlCa/LgcR0lNfovTEi6lcIkzesnM/R8RlN0INGp3h4DHoDsE5YRvQyiKiRSMzikRAOS2WoqoZWu41K7RwzlOOAVDMMMHhIGvFlRxJFrKYW0ep0IYgC3SDh4b1lTJjNfENsrazOAMAw680mPuW+8lFno1P4XDigRhOiwQAyJK7TbsNS/PaA7giAIAhYz2yRgBIfsVA8wIetPG6FAqhdNrC5u0f+TUyHgyMTDDToEt/ftQsEvW4EPG5OZcrvw0mlimarTXkPfpXPcNlQoGtjACgpryQXsPNtH/nvRXqBJpoKHMzGNkNB0Odls7LNyAYKpUq1dt1iuvB7fRDp9kr9D1xOFwkpoksXusmXaZWFn0coV89r/b6/AgwAkUENaQaRxswAAAAASUVORK5CYII=');
58 - background-repeat: no-repeat;
59 - background-size: contain;
60 -}
61 -
62 -.ipfs-dat {
63 - background-image: url('data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAAfVJREFUeNqMU01PE1EUPe/Na0uptmlASg3MoiZgCA3hQ8PHAjbqwsS9C3+CP8W1W/+BSReyYUPwI4QAVkAgUEgIbVIg1FZb2pl5b3zv2cHBjsaTTOa+e989OffcGeK6LhTevFv+OJoZHPHOfrz/sl86KpWfhxnLe7lXL1/oN/MSZqonOXU/k0AA6lfNhEFIrlAsP2PMyPtr1AscLpyg5pbtIHErhqez4+awmc45nI8FEvwNaiQuBHqTcSxMjJhmX0/Osp1xr878FxWEzwMinxAzEA4xFIpnOjedHTKpYbxW4U2CP4j8uWxmUKsghMCgFI2mFe9QgHZj0Ba4yhFF+KvGJToIRLuPC/efnjD6+26wB1Lq/xgbSCBXKeWJG/OTdky8cWTdT3C9RmWSGk2XCLlWo4xTNbfN5qh7PpXM72GjZeHt0gpq9QbmH4whGb+NpU/reDQ7hcWVVXxvXOHxzCQopQEKXKEbL6o1ZIcy+LC5g62DY2zsHeC0fA4zndIrHOjvg2XbAQRSfsuy9XxC2qzi/H5B6/68W0AsGkW0KyJPBLbDO0fg3JX/CUM81i0bD6WKe6j9qOPJ3EMcF0tSNsFA6g6alqW+VtZBUL78Vtk+Oqne7U9rs5qOQCjSheJFBeFIFOfVujSUYu3rIc4uqxWv76cAAwCwbvRb3SgYxQAAAABJRU5ErkJggg==');
64 - background-repeat: no-repeat;
65 - background-size: contain;
66 -}
67 -
68 -.ipfs-dmg {
69 - background-image: url('data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAAn9JREFUeNpsU01rE1EUPe9lkk47yWTStCmtNhFSWxos2EXVhSsRcasuxYV05V8Qf4DgD/AvCK5EV1oFI7iUBqmCNdDvppq2mWSSzEzy3vPOpFFq+uDNfR/3nnvueXeYUgrBWH1/9/NE7k5BKRnuRcfF2qdnmJq9DeF9tQ+2isuMsxXGWHh/a1mEVsPJSI5fSU3OPEj291IIlN49RXz0KqzEQjIeZS/L5Y/3wPGhDxIM/i/A7fZWgVG0t5EaG0ZUa0JGM8gvPrZmLt58QYwv91mfAqCIE0sAqgumBFITGQzpUYhuF0KfRa7waDyXXXolpVrsh/0tgSLDr5I+wUZo1UHCSkAficPzY6juFSmbRPrC/azjq+fkcO00gAqoU7B0ETKkfWbuCTjTYeq5oESAauexcTScX+ZACWFm0YQSLZKhHdr67+/wW0e0dgjYo3sCEXXybYtBDVSHLp2es3IpsILS24c42lkBg6DzRjgRzCDZ/xr0GNRJwwYiWgzt+hYMawleu0V3wbkT+kUirOc7IGJAz68R/Qak1BAlx3hqASPGBJRXpXOv58dkz3eAgQoOm4hyj57NgZm0MHvpBmK6QdUdg/DAg9cRkhicBSDaKJdeo1bdxmR2DtWDDUxl51HZ+QHTysD3XdQO95Gfv06aeGcAdBrY3Chi8lwO3768QWX7J5q1XWyVSxgajiOXLyBG2hzurRKV9lmt7ISNkkjo6HhNyjoK+2gXRsKE57ZIE2ot10Z1fz0Ue4ABVw3NMjnW14rInh8jTYywoTg3EOFpOM4mXNfH9PQUfGlrAwBOs3I8ljbtuMWhRWzIIPrkn+GcYcgIWEowbZ+0qB334/4IMADESjqbnHbH0gAAAABJRU5ErkJggg==');
70 - background-repeat: no-repeat;
71 - background-size: contain;
72 -}
73 -
74 -.ipfs-doc {
75 - background-image: url('data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAAppJREFUeNpsU79PFEEU/mZ39vZu77g7DokcP04BBSUmiEKCSCxs7Ei00JAYO2NlTKyMrX+CJhaGwopSQ0dMtFEsbDRBgiZEQIF4IHcg+2t2Z8eZ5QDlnM1mZ9+8973vfe8NEUJArfSNhzPG0VIfeIiDRSDkw1cWVt3N8rhG6SdSO2Gvn8dfuueqZwuNZqk3Jxg7iNcIfBbgXD6ZC8u5qffzX8eoYeyDxC77uygKhcouovgVUQj1H4YB2ovNuD9+tTTU0zMVBmG/+C8AIYh8F361DL/yE5HnADKYlVdg6MDAmW7cuz5WGuw+PsWDYGAvbL8ECFUt4K7/AHd/I9c7BLaxinD2Ld5Zo7g78RLuRhlBS2cpWbGfStfhfwCEpK0nUjCbWuGsLciSOELPhkq/YgdY3l6HsLfRcLYf+pHNbH0JigEPkLAyMsiEJ7NrqQzM1i7wyhoMZqOhvQs6Z0ovXgdAJACRoulEg5HOwrOroKk0zOY2BDtVpTF0CU6kLkQJXa+BNEoG0lMSsBBKQXWNQktmoGcaYeSaQCIVWOvUYQAiWZFQtk5mSMoSzEILtBrTfEcviC5bwVwQmoh96wA0ic5dB57ngeoaTIPCdb34zDITYNLOOIeVSsW+dQC+7+NSWx6jJ4tY/rWNV7PfcGv0tBoPTM7M4eKJVgx2FTE9u4QPS6x+kHzfw/mOAjarW2hJG3hy8zIceweuY+PRtREMdzbjzcd5WBqPB6xeRGUMGRzHjWvMmxQ7tiOF1JBN6FiTd6Sy9RuFbHpX7MMMqOD088Ii+op5OUAO7jyeRGfBwrF8Cg8mXuDL4neMXzgFwhwZz+hf7a9d5yu3Z6DTPjVQIY9k7erO7Y63Lvc8ErEeyq6JaM6efjai4v4IMABI0DEPqPKkigAAAABJRU5ErkJggg==');
76 - background-repeat: no-repeat;
77 - background-size: contain;
78 -}
79 -
80 -.ipfs-dotx {
81 - background-image: url('data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAAndJREFUeNpsU01rE1EUPTPzJk0y+WhMStW2qdVWxUVEQUF0I+4ELQiC7lz4N9z0T+hG9wrdZKUgLqulhrbSag1CKpT0g7RpYjqZmffle5NEKdMHlzfvvXvPPffcO4aUEno9f3Vt4dTp+BXOe+fB0u/NbVpv7h89NU1j1TCM8H7+xY9wJwPHZMbOjRadLAvE/2gToJTiTPx89k+OlVd/LT+0TPIPpO/SzyQk40xCMxBSZ9Z3CoAx5DOjeHT7SbE0XSpzwa8OWB9jINELolQg8AR0EgUKn1PIlIWpkUt4cPNxkTOU12trs8p95RiAXpqaztqou8q6SKQJJmZSqGwsodFsIJk1kcyLYv7IeafcLx4HUNkFF4jFTExMZ0B9DrfD4HUEusYhWs4GPEJg5wly/tBYRIOeDhpEwlS34xcyajdQr3UwOT2MlJOEBRuGNHWp9AQRVXDfQiFV/U5GBSiQ5p6ngBEa5z3fiIhC6g6IMDBwOdoHPkYnHPVyhN0tF7E4QSpr94CEOKELffq+y9Bq+DCJ7rWBoQQBVbPR2O6G4OlsLASJMtCZfQqm0NP5IVWnamdAkUxbyuIYtD7wWegb0YAzAVMkkI6NwPM9xEwHloyDGAmk7AKS9rAS0FKOdugbYeAHPu7OPEM+MY7q3hIKqTFQHmC3XcONc/fxdfMDrk/ew/edzyhvvTmBAddocVRqH3Frahau56qpZDho7+PnTgXffi/gbHYmLEvPSIQBp5JU62sYz13G609zKBXvoOMdYn2zgm7Xg2MVML/4Eu3uPgxhk2gXmNl8v/i2pcXTP8tKdTEcbWLZqDQXwu/l6pfwbEnSGsT9FWAA4mdHv2/9YJ4AAAAASUVORK5CYII=');
82 - background-repeat: no-repeat;
83 - background-size: contain;
84 -}
85 -
86 -.ipfs-dwg {
87 - background-image: url('data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAAoFJREFUeNpsU0tPE2EUPfOg006hD4rQh8WgbCSwkKgbF2owujaCiQsXxpX+D6MmbtXEsHCLmIAbE6NLo8YlGIxREIshIqVl+mQ6j8/zFVCb4UtuZua795577rl3FCEE5Bl79vPd5LHYiOP7cH1AUWi85ytmvlas1bJ9E5ryBntH3BpuP/X9i7ovkluuiE8N9SDepaLpCcRCCqa/VDCaMuIjSWP25Upl6n+QDoCz6Yh7KKzh3sI2LuUimPtRRyaqodj0MDloYiITSTi+mH29Wu0AUf9CsZPJoW5czJl48LmCc5kIKo5Al67B9gUGYxrun+5NnMlFZ+GKiQADj2a7AquseLIvjMv5KMaSBu4sWVir+3i8VIVKYSby0UTdFU8Znu8AYBHQgVOJEN5uOXi4UsdawwU0FSf6TaSoyw6DRvukPkgGWpDKy4F8a3jImCrqFDFn6rhKPR4VGnhvOTAY3WLcjifcQAsqRfhUc/Gq1MKNbBh9nIAMDjEppocxs9HCMktfGTCwP/oOBkUKNk/qF3pDYC6Ktk8RfWzyaaoKrqdDaBDwya8W1m0/CPCR3kFy7CcnmWQRUJqcRJFUKtTnPCeR71LwoeYF92CYyVnCFZpCTrRtCv5to2St8SOrKxiPqEEA4fkYT+mI0rdoeUiH1XZVuQPpsIKqw2QmfifTsnOABiWySlH9uU0Hh2MqjsZV5LtpPSoGeN9rKnhBX7ehoOSLIIPfnGONXGMMWN7xUfVldYDbjM3mrh5HCDgS17DhHgDQcIU+XbBxnDTn1x1UuQcJ9iv7l5Q5e1zLGri92EDJFnoAgHtcfr6wbbVXUqq193+0z97n3UJt1+d51n7aHwEGAAHXJoAuZNlzAAAAAElFTkSuQmCC');
88 - background-repeat: no-repeat;
89 - background-size: contain;
90 -}
91 -
92 -.ipfs-dxf {
93 - background-image: url('data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAAo5JREFUeNpsU0trE1EYPfNMmtdoH2kDNmJbaVFcaBVFpAsREQpFwY0bu3HjQnTj1mVd+ANcuC3qQixmry6E0kWFVIQ+bKy2tbFJm3emyXTujGca+4DkwsedfLnn3POd77uS67rw1vC79ek7fZEzpu3AYUqS9tKQGZPLpa3VXP0uFCmJ/8t9OLC3q/uJbcs5bkIybvdHoMsSbLKENRmvU2WcNnTjRFD7ML1WGSPJHI6sA4KRWMAWVDPxLYex3iCmfpuIh1QsFSyMxQO4GvXHHwOJ6XWSyIck8v6HQsnjAxFc7vTj2VwBg4aG78VdBHQFCk+dbVcxMdwev9gTSEC455sIBOu2KLsoJFzqasP9vjCeDBlYqzn4VXXwarGKZN7Crd5QfLDT/7KpBM84c9fFUFjFp2wdk6smflRsKKqMa7EgfJJ3Ac2OKlit2pEmBTQfngdpnupoU7BUtRGiiTe7fXiRqmK+KuDn6TpvYogmBRJcrOwIJLIWxmM+dOsyLKryQAaJpjJ1/AxrGO3SqdZt7kKZJrzJWBg5piHENuY8vV6e0UOye1TyftvC5l+gZB8SHJTwpSx4q4JeTUKaxhXoR57h7Rn+3iFolJ3xvPhab6HgJG/pJ7jsNP4sUX+jZiCgEsWd/DjH5IrSYpBUAr0yHpzSoXKOP25a6OBhndh0zcX1qIYM2RIbu6i0KiHD5B/GTMHG03kTGpEL7H80wHFOWwhqDZ+SpkBOtCDYJDhZE4gRcKNbYynAqbCMbXpwpVPFbEng0aKJGbYzK1p4wIegLlcEPmdt+DjXbzcsxFlCynRwwVAwW6hjqeg0Zt521SYCWCJvbe0Un29UDx7Hgrs3IEitHXkw3jOv2fl92D8BBgAJeyqBh90ENQAAAABJRU5ErkJggg==');
94 - background-repeat: no-repeat;
95 - background-size: contain;
96 -}
97 -
98 -.ipfs-eps {
99 - background-image: url('data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAAmlJREFUeNp0U01vElEUPfMFCEVArdoSqEA0KV246UJdUJM2Lo2JK/9FjXu3utJqTNz4D9worrsQExbFpAFT0TYp0CZ8pIAiyMfMvBnvm2Foa9uX3Lw7c98979x77hNM0wRf7ufPsq7Z2SQYw2QJAkDxQalUZa3WI8hy3gmZr15bu+z8kILBkCeRCJi6bufKMji0NhwiCQR6iitdatTvQ5LyOLLEiWcYukm3m4Zhmbq1BX13FyoxuH7xAlbvpqKRK1fT0PWbRwEmDEyiy1QVg/V1GO02tO1tKLEY2PIy3KEAlmJRDLXb0TeZL+n9g4MHlLJ5HIBuYnSzXq+DlcsQLk/D9Hoh1WrIUjlPcpsYGQzS3LWoaBhvKeXWMQCDA1D9pt8PaXERUjwOjEZQFhZQp9L2yERiqYRCkPt/z58ogTGqHQLE1BLgUmC6XGD5AlipBIFKkbhanKHGYLBDqQ4ZED0OAbfLlo8OIxwGvhVgyTHlA3xkomjH/gegBgDURMv6faDbBZpN+/tHkUApkdTA/PwZAPxntwdUyjYA/+ZMqJHjLgM9iv/6zRt2GgMaIE21aVIjnSm0DGPfmhzyde0UAE2Dj+p7urKCPvkZku9eJILOSMUnkvVhIo7GYIB3xSKYdhoA1erXGVKXpvFxZwdBonnD68PQ7YEwM4O4xwMPxc8RYE87g4FIcz+kvfmnA0YzIJIy77/m0OCqsTkkCTysKPjJG3viLei63Gm3kCO6UWqcMejjxecMPmxsoFKtYop6UNirYL9Wtc5OHqzznIXHq1na7OfMJROcK8a6O7MjW7nfzZdrd7jzT4ABACh3NGsh3GcdAAAAAElFTkSuQmCC');
100 - background-repeat: no-repeat;
101 - background-size: contain;
102 -}
103 -
104 -.ipfs-exe {
105 - background-image: url('data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAAo1JREFUeNp0k8tPE1EUxr+ZzvRJO62lUAQaKIQ0FVJFjBBdoIkrDDHuXJi4NnHtX+HCjW408Q/QmHTRaCRRohIJifgiiBICTQu29mHfnc7MHc+MlECKdxZz595zf+c737nD6boOYzxJLC6Nhwej7e/24HkO779s7G6mMjcEwfKZ21+/d+em+RbagaFev28qEpZwzKg3ZckqCPH1nfS8hScIdyhBe6JqTG3PfyTTeLrwFhvbKdy9/xi5QglXL0yGJsKDccZY7LDIAwWHpSferWBh+RN8ni4UylVER8MY6PHj0uSpUK0hxzfTmWsUtnoEwO3rer64jEyxim6/Hy67DXaHExvJX3jw7CX8XjfORUdDlOohhU4fAVjILCPbm9V1yIqK2FgYt+ZmsZcv4lH8Nb5upXD7+hVMjIRQa8qeDg8UTYPU5cTcxSk4nS709XTD53ZhpD+IYMAPj+TBz93fZiz5oHV4AP1fGdlyHZIkIZkrI7GyhnK9CZXy+Aig6p1+HQAY003AcF8AVtGGfLWG9XTO4MLZ5cL0WAixoT4zVmPHADSiMo3hzHA/xgeDWFjbNg8H3A7kKnX0koEcPdTu/ylgRGZgOjNv38zoSXC8BZJDRKOlwGEV0VJVGM0y4joAPO1spXbx6sNHeD1uRIYGUCxVSRlDt1fC8rfvcDnsmJ+dOaLgoAs6AVLZPJJ7WdhEkUyT8GJpBflSBcVKDTvpDBw2GzQqQT1OgaZqUOhtFQUTUKnVTVWNpgy51YLVKph7sqKYkA4A1ScEfT66vm5kC3+ofh6Xz59FQ5bpkvE4QW3M5Apoyorhl9ABIKnFgNdTOh2NkJG6WSf9eRBJtmFwLDJmriUzeaOkYvvcXwEGAIVNH6cDA1DkAAAAAElFTkSuQmCC');
106 - background-repeat: no-repeat;
107 - background-size: contain;
108 -}
109 -
110 -.ipfs-flv {
111 - background-image: url('data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAAmtJREFUeNpsUl1PE0EUPbssLYUCXdpaC9gWoSTgAyFigiRGY+KjvuuTr/4A44MP/gx/gMYfwIsan0RjIjGiJIZgSIGFIoXSD0t3Z3dnd70zpITazuZmJzP3nnvumaMEQQCx3jx69SV3a3KWMxetpSgKxP3m242Do43SQy2k/YRydvds67n8a63k+FRSn7l/bdg5tdsAuM3he/5weDC8vLdqPLgIIpba2niux52mg//DqlsYSg3iztO7mczN3DJ3+ByCLgCBH4hOFEF7cDpzPCRyOpaeLGXSc2PL3HbnW3XaRQCPEgWI2MsRVAVqrwbX9bHxbhOKpiJ/bzpDOr2k68V2BtRNzMtqDEqPejY/4zSGjb54BM0mQ8k4xsDoIMauXxnqYOD7PmwScP31d0SS/eAuh1lrolFpIBQNQw2pqJdqsAlIceB1AJCIkkE/FZskXDQVRXw6IYHiE0nBEcaPXSSvJnGwWkQXAE4acAhbxPMJpOdHweoMhc9b2F8zwKizbdlyPLVH7QLg+JKBYzoorxzjz3oRzUoToaEw9KyO8XQW5AE5jrFT6AbAYVVNxCZ0Ka3So+DSTAoDiej5ywTySbls1OEDobhFlMcXxrHw+AbINEjNXgb7y6BndLhk8cRkHHbD7g4gEhiJFxsdhrDqaamBaDKKerGGSKwPI9kR9EZCaNA5ubE7A5s8IFhsrxQkgJhZoa/06xC5xRz2v+3BOjFlbqcGlquxsondT9vY+2pAJdeZR6fI355CgQCN2A4O1w7gkQ7cdLUOAKdhV6uFSv3kd/n8mT68eC8dKWLnY4FsfeZQh7nVVt0/AQYAsf5g+SvepeQAAAAASUVORK5CYII=');
112 - background-repeat: no-repeat;
113 - background-size: contain;
114 -}
115 -
116 -.ipfs-gif {
117 - background-image: url('data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAAmVJREFUeNp0U0tPE1EU/trplAqlL0laiw40xASByEJIZFGVnSvj1j+gWxNXJq7VrbrwF7h10cSNhMRHojEuACVBKmH6SJQyJeXRxzzv9dyZPiCtN5lMe8853znf953xcc4hztDzZ1+C6fQMHAfd4/MBFG+p6h/n4OAeAoGNToi/eOm+A50LKRaLh6amoty2vVpZdotNXccMEK3LwZxa2bsDSdrAqePv/mLM5tSdMwYBYqyvw9zdhUn/L59P4OGtG8qlZCoH254/DdCdQBCxqZu+ugqnWoW9swN5ehp2NotgIo6bGQWGtaS8+vQ5V9a0u5S+1gfABEilAqdUgm98HDwUQkDT8JXoPPq+BoM5kCYmFT9jryn1+hkAt7heBx8dhbSwACmTAUwTgdlZ/CVKJaLnI1GD8TikZiPSR8Gxib8chH95mZTxgwWHwH7+gFMswqcokIRbjMO2HDCnZ1VvArpjEmnKZc8+cZJJYGsLsMiZ8AgwEqaY6Mb6RQR33JFhGECzCRyfAFXNu9v+RVNRZWIMuDJNuYMAaDycUFGhCOgtuAtFVDA83G5A8TrFDw+F5QMAxAKJJxz2xnW3RPJGbm+rCyjotZetH4DGzaSSeDA3h4Zl4R0JOEZWTpIzF4n/m995bNdqZwB6m0gFft3Ak6vz+KYWwFsGlqIxXItEcDt1ARMEtKdVgZb+fwA0G2C2hXM0ZTZNRcSf0b1pmXi7uYnjI+Lfanm5fRQsK8BIxKcrK7i/uIgP+Tw+FlREqHN5fx/vyU4uHBE6UO4gDWqk/JFaLuMxcXeFk6TuJ90V0HOk1in7J8AAjmgkPfjU+isAAAAASUVORK5CYII=');
118 - background-repeat: no-repeat;
119 - background-size: contain;
120 -}
121 -
122 -.ipfs-h {
123 - background-image: url('data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAAbRJREFUeNqMUk1Lw0AQnf0woK0ttVqp0hwqVCl+UBERT94F7x78Cf4Uz179DT14F8WbYHtRkBYRLNqDtdaPZLObuLs1NGlXcWDJZGbey+x7QUEQgIqT07PL5WKhHL5H46J+22q22vsWpbWwdnR4oJ80LNiz2czGUjENhvj4ctIE4Wrj8XmPUlKL9nCYcOFzE9j1OKSTCdjdrtiLdr7KhVgzEvwW6krC92E6k4Kd9bJt57JV5vFK2KfRQRV+RAMkzxglYI1RaDy2dW1rpWRjQo5VGicYIorWVooFvQVCCAjG8Omw1MgG8AM0uSBUDSnCfk/IGCHwf3DCD/7UhOLBrFkDuep/hDUSSCv1iYo4rIfqGwmUSNJjfYbBcQKhZw0aBMA4B48LwBhBt/cON80HmM9NQ6fXg/Wlku4TwmNWDzaQqzHG+0PSKod5cH5Vh2RiAhYKc8DlV1UPSyuFMGygVlMg1/P6BC6DqXQK8jNZDXAYA1f21V34wMXYFaiyVw0rJyzLgs3VMkxOjGtix/V0XWChZ0cI2i/dzvXdfTd0Qf91BMPrhyNzgKfOmxaWypqaDXHfAgwAtCL8XOfF47gAAAAASUVORK5CYII=');
124 - background-repeat: no-repeat;
125 - background-size: contain;
126 -}
127 -
128 -.ipfs-hpp {
129 - background-image: url('data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAAehJREFUeNqEUk1v00AUHK/XKf1yZdESVRBXjRSRFqMQVBA5Ic5I3DnwE/gpnLnyG3LgXglx4UDDLZS0RWkDLiRxSusk9u6GXSembmLgWZbX7+2bnZl92mg0goo3b3ffO/ncdvyfjHef6q2Dlvs8Q2ktzr16+SL60jhhZ69bO8X8ClLC7w9XdKJVG8fuM0r1WrJG4gXjgqU1D0MGc2kBTytl+7a9XmWcl1IB/hZKEhccq5aJJ/e3bTu7Wg1CVo7rNLlRhUh4oMnXoDoyhoHGyWmUe+QUbELIa7W8CjAFlMzdzeckCwFN06ATAn8QmDMMMGlMuwWucpoCHNe4jBkAMenjYvRPTyi53JvuwX8AplleAeBcRFrH6rXIxLim9I/pi3QA1RhKaYxdjkN8IwalCMIwWs9ljMkh0wzk+9M7w179C3LZNXxve2h+c3Hu91HeKmD/6zHOLnw83ilB1/V0CeqU3Q81LC/O41b2Btx2N2JVP2riR8eTUxmi0TzBwrKZMsqMoz8MsDh/DWuWhUBKURLKxQIeOMWoptYPnS1c+INZBkwISomOSsmBZS7B+3WOzZvrKGzkMAiGqNy7g+LmRkRfekBnANy2163PZXrSbrQ6vch19Xz8fPDHyL39QzkHBKedXjfu+y3AAGU37INBJto1AAAAAElFTkSuQmCC');
130 - background-repeat: no-repeat;
131 - background-size: contain;
132 -}
133 -
134 -.ipfs-html {
135 - background-image: url('data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAAmBJREFUeNqEUktPE1EU/mY605a+hhZTBNKRDApNrWIRA4nEBUZdmCgLNi4MK5f+FNdu3bFv1J1EXODCR1JJSMTwpqUP6NiCpe10Zjz3hj5Mm3iSybl37jnf+c53jmDbNpi9eb+6Ftcisea909bWNzNb6dwzSXKkhIt/r14+515qBqmDA8HpqKagh53XaopblpIbe+knDpFAhPab2Dw0TKvRK7lmNODzePBgZlK9oUWSpmVNdpIU8T+jaMsyMaD4MDcZVa+NhJMN00w0n6V2nN3yQgdHWZag+LzYPTomIAtT0THVtPGanmb/BbjwLFkvn2IttYGYplKyDzsHh7gdmyAWfh5zVq0Guhg4RAHFUhmfvq3j134aXo8bd+ITnMFOOovU5jbGRoZwNxFn1cxuAIcDW/sZDjA/c4u+BNxOJyxqaenpI3z88gMfPn9Hv98HQZS6RazW6kjExvFi8TGdDSy/W0Emf4LS6R8sv11BmfzSwkPcm74Jo9Ei0GZgmkw8QCOao8OXcaz/5vSZnPdnp3ApqBBLkWJE0Ci7ASzbIhCLLQ1E0iOkBDh9NpUgiUejo8oNuJwyn0YPABtn51UYFFivG3yBGCNZkuDtc/MW+ZQI3OrYpBaARCKufk3B5XIiWyhiL5ODp8+FfFHH+KiKSqWKUL8fC/NznGlPBmz+24dZjKnD0CJDcMoyW0SqXuMtHBFw7rhIAD1ErNUNafxKBNevapwu65NpEQ4FqXIA+RMd6VwBP3cPSERb6gLIFIq61+UqGWaFdcrVt/lmAuWjAi2aiMFwmOYuIJ/N6M28vwIMAMoNDyg4rcU9AAAAAElFTkSuQmCC');
136 - background-repeat: no-repeat;
137 - background-size: contain;
138 -}
139 -
140 -.ipfs-ics {
141 - background-image: url('data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAAhRJREFUeNqEUkFPE0EU/mZ2dra7bLNpi2AxQFKalkJrohICiYkXPagXrx78Df4K48GDBzmQePLMhUODNxQ5ciEkJVqDtJGmMWrCATRbd2ecoS5u3aovmezsvu9973vfPiKlhI4XL7c2r5YL81LIELEghLA3u/udxmHnPmfGW/Wuv+LpwwdneRYBx7PeWK0wOYYhcXxyckGV1fdbnbuMsXcklqPRJQxFMKz4RxDCtVO4s3xlRjWoB0FYjlQPEEBieChwKCRGMx5uLtaKs1P5ei8IKlGa/YkXMXYtlTEDlsnw/mMXhBJcqxSK6vlcpa4PEpCooUyIqs5M6hG1o2CUwqA091cFcYLf/sjzcX75EiQIojI9779CTYR4jwTBf+r7GAwh0AxCiL6JMT/04vQ79u8aI2O/7Jzg69o6Go8ewycUahtBpADhHKLnK/eVbkMdtROWIv80NQ2sPhncA9Htwn+9hZG0rY6DzFwJl+7dhs0ZstUy8rduwPS/wd/ehmi3kwq4zTHiWUgXp+EuL8FvNvFl5Rn4xAS86iyI2kY3n0Mv48ByrOQmancdi8I0Kcj3U5iuA29xAelKCUHrEIayzltagG2E4IwkFaQgSC6lYI09iN0d8It5uNV5nG5sgJdKYC0G8WoTOZvBISFNEBxnsuzD3GX4vfDsszzqAu0jkJQDedCGbB6AWg54pYbPo+NGVPdTgAEAqQq70PytIL0AAAAASUVORK5CYII=');
142 - background-repeat: no-repeat;
143 - background-size: contain;
144 -}
145 -
146 -.ipfs-iso {
147 - background-image: url('data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAAjlJREFUeNp0kstrU0EUxr/k5qbJzdPYpGkpsUJoA2q1oLjTdiGiIC5cuXHlxv9BEOrStTvBnQvRrSAIsejCrlqpsURq2hCJNQ+TNLm5uc/x3MmzJh34mDNnvvnNzOE4GGOwx8+t9XQkfn0VE0Y5/7Z+kHm+dvOhtd3P9c/xwNZh7nWaMYtNUmX/Fct/vlN7/8J5aRRgyzm8xzpRDjGE2aVH4VTqdnoUYg/XkEhmy+Cx3DhA5tMzdFolvg5Mx3Fx9SmH0JIg79Zo3j4GADMIokJTKtjbfAKXU4Y/2NvSfyH75TFOxa9Cmr0XnlPFl5ReOQ6wNMDsoFX6AElqQlNV1KsOuNwS/AGFjEUIDhmn5+/DMM16/9igBowAzFKIswPJr6MjlxFP3sV04gaP7RzMPe6xvWM1gNUBM2UKYlBau3QghGphg29J3gDlLLilWNdD3gkvIIDRhD9yGe2mCV0V4HFXuCxT5Dlv8Dz3sIkAs03FalDxBMQSt9BRBMhNncuO7dyU28c9tnf8C/Q0ZtR4GImeQSj8APLRH772BWcgiFODffCv/t8H9tO0v3RjV7VqkeeXLlzDfvYjj88uXhl4JwIsrYxmLY/M1gYclIvGE9jZfNPrSCD3/QgLyeWTADV6wW9AryIcCkB0u1Aq/oCPumlufoF72vIheaLDr4wCLIOqrYnULA14PSoqpSJEAUilZrD77Sv3LK+cI0+Be8cAbbmAOrob0agtD491LYfkoqvnyZLsWRkA/gkwABL4S3L78XYyAAAAAElFTkSuQmCC');
148 - background-repeat: no-repeat;
149 - background-size: contain;
150 -}
151 -
152 -.ipfs-java {
153 - background-image: url('data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAAjxJREFUeNp8U01v00AUnNiOEyepQyhQobRBSlVIoRCBEPTAjQsSEneE+An8FM5cuXLNoQduIAE3qopKNJAIIppA2jrOR93aa6/N8yZuUxyxkrXr3ffmzczbTQRBgHC83nj3ca28dD36nx6fvnzrNNrdp4oibyUmey9fPBezEgWVFuYLdyvlPGaMY4fl1aRS+9pqP5ElAkmcnknRwuO+Nyt5u/ETYfyj9WrpZnmpxn2/Ok1Swn/GvtnH5k4TLue4kNfxoFoprRQv1TzOb8cAIu3+ZD7oD/Hm7XuxzqRUNDtdkuLiTmW5tFxceBXlnXgQTAORSMt2oGezUJJJrK9dFWdEH7Ik4dB29LiESeUEJXd7/dAT3L+1ivlCHr8NEzutXTBvbJPPSdO/AH5wysChwM/1HzCGlmAzOrKxu2eCud6Z2Jke2MwThpUXL6Nn2ZAVFTlNw70bK0iRnGAq9qwHtOmTRpsx1NsHyKRVnNPnoMoK9kc2BjbD4vk5JGV5NkBoEPM4FFnCteJFWOS4ntHEfphQyKaFTWFLw704AJ26ZFx/ZEEi3YyY0O1Dmr4EKTUHA8hUnS6siI0DEHLYog+b28RCRuNXR/iQUpPUEQ+NVht6Lodnjx+GXYgDSFRnq97Ed2pXSlXhUSeGhxYc5sKlNXM5DGLR2TMwfZVPAIi+otGNWy1fEZUKeo4qc4ysI+F8VksLIJfYcD9QYgB/DNPMptWBlsnBIS86xmDMTBo/PWd0LB6VZfdEbJT3V4ABAA5HIzlv9dtdAAAAAElFTkSuQmCC');
154 - background-repeat: no-repeat;
155 - background-size: contain;
156 -}
157 -
158 -.ipfs-jpg {
159 - background-image: url('data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAAmlJREFUeNpsU8luUlEY/s4dmMpkWxRopGJNNbiwhk1tItbGtXHr0hcwmvgOdWld6Bu4coXumtREE3ZKu8FgOlC1kIoXtC3jPfdc/8PUIpzkBM7wf+f/hsts24YczuerGUc0moBlYTAYA+i8sbdXtAzjITRtq39kr73s/Gr9DTUYPOeamwvYnHdrdR0SnDebuCbswJGqpX+Uf92Hqm7hzFAG/4TgNr1uCwEJ0trcBC8U0Kb1/PQkHt9JxSLnL6TB+Y2zAIMOJBGLXmtsbEAYBsx8HnqCGKVScAX8uHf5EpqmGXv18VO6VDEe0PXsKABN8+AAgiabmYFNNJTDQ2RUFc8+Z9G0OPR4PKYwvKari0MAgiY/OQGCAajhMNR4nDZMaInrKBGl70SPMScck1NQG3X/CAWLE3/dAWV5hRRVIJxOWNksrP19sFgMqqAebUGYHMI6teq0A9oTVAhqu2sfbYYjsL7lCZ3683gA70T3TK7/B4BNoO020GwB9TpwfAz8LgMtWn/NkV8EHgoB81c7nYwCyBZlEVkHcqMTKFnkmehJTOPvEfCnKi0fAyADJKfXC/h83TaZTJjaa5lANLpOFqAXtlEAorAwO9u5syT5UxLfU0e3o1FMu1x4u7ODYq02BKAMAVSrSNLrK1MhLPj8mNF0vFm+C1ZvwKBwXXE4AGn1WAASazESwUW3BzUSMeJ2o1Aq4sPurvQYSRLwlhRR6mSaYyi0WlpAJrFRx3ouh5/lMt5lv8BLwXp0M4lSpYL17e2uK5wP6lj/c2ZPn2RI+YT8fDvqoyegVLyfG5kBKaQQOfvF2pLc+ifAABiQH3PEc1i/AAAAAElFTkSuQmCC');
160 - background-repeat: no-repeat;
161 - background-size: contain;
162 -}
163 -
164 -.ipfs-js {
165 - background-image: url('data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAAyJpVFh0WE1MOmNvbS5hZG9iZS54bXAAAAAAADw/eHBhY2tldCBiZWdpbj0i77u/IiBpZD0iVzVNME1wQ2VoaUh6cmVTek5UY3prYzlkIj8+IDx4OnhtcG1ldGEgeG1sbnM6eD0iYWRvYmU6bnM6bWV0YS8iIHg6eG1wdGs9IkFkb2JlIFhNUCBDb3JlIDUuMy1jMDExIDY2LjE0NTY2MSwgMjAxMi8wMi8wNi0xNDo1NjoyNyAgICAgICAgIj4gPHJkZjpSREYgeG1sbnM6cmRmPSJodHRwOi8vd3d3LnczLm9yZy8xOTk5LzAyLzIyLXJkZi1zeW50YXgtbnMjIj4gPHJkZjpEZXNjcmlwdGlvbiByZGY6YWJvdXQ9IiIgeG1sbnM6eG1wPSJodHRwOi8vbnMuYWRvYmUuY29tL3hhcC8xLjAvIiB4bWxuczp4bXBNTT0iaHR0cDovL25zLmFkb2JlLmNvbS94YXAvMS4wL21tLyIgeG1sbnM6c3RSZWY9Imh0dHA6Ly9ucy5hZG9iZS5jb20veGFwLzEuMC9zVHlwZS9SZXNvdXJjZVJlZiMiIHhtcDpDcmVhdG9yVG9vbD0iQWRvYmUgUGhvdG9zaG9wIENTNiAoV2luZG93cykiIHhtcE1NOkluc3RhbmNlSUQ9InhtcC5paWQ6RUQ5ODY5Q0NGMTE4MTFFMTlDRjlDN0VBQTY3QTk0MTEiIHhtcE1NOkRvY3VtZW50SUQ9InhtcC5kaWQ6RUQ5ODY5Q0RGMTE4MTFFMTlDRjlDN0VBQTY3QTk0MTEiPiA8eG1wTU06RGVyaXZlZEZyb20gc3RSZWY6aW5zdGFuY2VJRD0ieG1wLmlpZDpFRDk4NjlDQUYxMTgxMUUxOUNGOUM3RUFBNjdBOTQxMSIgc3RSZWY6ZG9jdW1lbnRJRD0ieG1wLmRpZDpFRDk4NjlDQkYxMTgxMUUxOUNGOUM3RUFBNjdBOTQxMSIvPiA8L3JkZjpEZXNjcmlwdGlvbj4gPC9yZGY6UkRGPiA8L3g6eG1wbWV0YT4gPD94cGFja2V0IGVuZD0iciI/PoT8zQ8AAAJdSURBVHjadFNbTxNREP52t7S0bktbKFAvTUVaw60YqkExUTD6oD74qC/yD/wp/gh885XEEI0RAyYQUiMpIBGMkYR6o23abi+73e2uc04v1LROMtnZPTPffvPNHMGyLDB7sbJ2ciUSli3U35smkK9t7x9v7n2dD/g8KUkUwWqeP3vKz23NxJGzgwOx0RC6mSgIo+WKuvP56MeUzy2nJEk8PWsGJVVTuhWbpgmHw47FB7d98Wg4mVWK52o1sxOg3Va3PmFp+Q2PdUquaFUM9/vw+O6cP3bxwm46Xwh1ALR3/vL1e+hGjcc9koScUsTSq3coVDQsXJ3wzo5HEs3clgZNMTVdx1T0Ep7cn6//QRQwMhzA6uZHLD5cIFEFSKIU+G8LK+tb0KsGZKcTJoEyP08AbpcLy6sbPKdQrigdAGaDwWxsDH1uGbliCYIgcM8WFPg8Mq5Pjzdyu4jYbCE44EepXMHuwXe+A8x3KKYxYsjvbUzmlPGpBmYdgI1oYjSMbL4Ao1YXMkcM2Dd2xnbAamPQAqg1GORLZdycmYTdJqFKk2DPR3fmwI4zBDrg9RADqxPAbPBif2WTSB584/3/TGegEOit+DRcvQ4OZJi1LgwIQKVCg2i6nb1I7H3Br3QWqT9pBAP9uDY5xjdSM3RqxeoUkfVnEOW8UkLykERTNXjkM7h3Iw6NNvHw6JjuhAhVrba0+QeALozcI9nQR0VvNxJc/ZmxCNGvIBQcpDG6udA22kyW29HC72wu8yG579ZoiSYuR/ly2+y9CA4NceWLmo717T1i5ULqJNtapL8CDACskxPFZRxLwQAAAABJRU5ErkJggg==');
166 - background-repeat: no-repeat;
167 - background-size: contain;
168 -}
169 -
170 -.ipfs-key {
171 - background-image: url('data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAAlZJREFUeNpsU11PE0EUPbM7u/2AtJUWU6qiiSYYo5EmmPDCD9AH46sx8cEnja/+CB989z+Y+MKPgMiDsYQACcbaWBBogYD92t2Zud7ZlQZsbzKZ3bl3zj3n3IwgItjYeDO3MlWme0bjUth8e8/fO2tHzx3XqUEk50uft+Ndnhdmc3SlfNPkVZT8Cy600DoIISvVfKYtlvfX1p66XmoIYsMZdjJQWvEFbbsC/S5g2QhSkKUK7rx6OzvzqLpsovAhaAxA3DUBQn2TUFsl7KwTfm4Z9DoO5LW7uPXi9Wxpfn7ZKF09vyPxX2iWcNRkKGZz0mQWKoNs8AVB6x1yRY2pYnc2LLofuXTxMgAlmlXIfngCxNxEzM+DPv6NQa2BygLgZyX6JT83ngHTN5GAL0WSoUQkSQnXkyBh/k0GegTAaldM20sTKvet+yyhIZApECamL0jUSe3oFChx3TopM4TeEQP2gc6BgGIwb4KGNXRhCkMGxgg2kJeybRiZM45D8W61qEAknSmpHStBhywu0nFVupSCTAcM4ECwqapv+NQ6LS9JGALoMIIoPYDjZiEL1xHtbyO39AQUDaA7R1AH23DSeSA4hv5RG/VAhxomPYP8sw9A4TaC9iHkjUWmrtGvbyC18BLe3GP0m3WW4I5hEBEnPIStXzyuFIxb4EkMEJ79Qa/xHbKxCdM7xeCwzUZOjgEwnuzt7qLz6T3cySmQP43uzjeIiTJM6io6W19B/NLCKMVGCzkCoLR/0lrfOI2fNy/huKC1FTsK/rbGNeMRC8dHpHByfu+vAAMAL/0jvAVZQl0AAAAASUVORK5CYII=');
172 - background-repeat: no-repeat;
173 - background-size: contain;
174 -}
175 -
176 -.ipfs-less {
177 - background-image: url('data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAAyJpVFh0WE1MOmNvbS5hZG9iZS54bXAAAAAAADw/eHBhY2tldCBiZWdpbj0i77u/IiBpZD0iVzVNME1wQ2VoaUh6cmVTek5UY3prYzlkIj8+IDx4OnhtcG1ldGEgeG1sbnM6eD0iYWRvYmU6bnM6bWV0YS8iIHg6eG1wdGs9IkFkb2JlIFhNUCBDb3JlIDUuMy1jMDExIDY2LjE0NTY2MSwgMjAxMi8wMi8wNi0xNDo1NjoyNyAgICAgICAgIj4gPHJkZjpSREYgeG1sbnM6cmRmPSJodHRwOi8vd3d3LnczLm9yZy8xOTk5LzAyLzIyLXJkZi1zeW50YXgtbnMjIj4gPHJkZjpEZXNjcmlwdGlvbiByZGY6YWJvdXQ9IiIgeG1sbnM6eG1wPSJodHRwOi8vbnMuYWRvYmUuY29tL3hhcC8xLjAvIiB4bWxuczp4bXBNTT0iaHR0cDovL25zLmFkb2JlLmNvbS94YXAvMS4wL21tLyIgeG1sbnM6c3RSZWY9Imh0dHA6Ly9ucy5hZG9iZS5jb20veGFwLzEuMC9zVHlwZS9SZXNvdXJjZVJlZiMiIHhtcDpDcmVhdG9yVG9vbD0iQWRvYmUgUGhvdG9zaG9wIENTNiAoV2luZG93cykiIHhtcE1NOkluc3RhbmNlSUQ9InhtcC5paWQ6RjZERjZENTJGMTE4MTFFMUIwOEVERjQ5MTZEMkVBREUiIHhtcE1NOkRvY3VtZW50SUQ9InhtcC5kaWQ6RjZERjZENTNGMTE4MTFFMUIwOEVERjQ5MTZEMkVBREUiPiA8eG1wTU06RGVyaXZlZEZyb20gc3RSZWY6aW5zdGFuY2VJRD0ieG1wLmlpZDpGNkRGNkQ1MEYxMTgxMUUxQjA4RURGNDkxNkQyRUFERSIgc3RSZWY6ZG9jdW1lbnRJRD0ieG1wLmRpZDpGNkRGNkQ1MUYxMTgxMUUxQjA4RURGNDkxNkQyRUFERSIvPiA8L3JkZjpEZXNjcmlwdGlvbj4gPC9yZGY6UkRGPiA8L3g6eG1wbWV0YT4gPD94cGFja2V0IGVuZD0iciI/Pl1w97IAAAJhSURBVHjahJNLbxJRFMf/wPAIMIxMkUI7tS0VYqlGDLGhjdKkqyZ24cJFN925de+XcONHaHRj4k7TND6SGo1VWwmp2kSLhlqMDbQ87gzPYcY7k4GgoJ6bmdw598zvnvM/95pUVYVma+svcovx8yMnFZHAMJPJBJfDzq5vpX6+/vD5qo/z7DOMBdo/d26t6jFMJ3iY51jBz4M+LP6wxEw40Gy23qYzB3HO7fpmpZCOmfEfa7Xb4NxOrC4lvbPToe2yKE3K1PdPwNOtHdx79ESfq4qKkijB5/XgevIyHxEC24USmewDqD2ABxubaLRkfW6zMqjWGlh7/ByyAtxYnOPnL0Q2+gGGmKRaw8zUBJaTiS5QOO1FJnuIAM8hciaIWHgi8NcSNt+loVDY8JBXh2ojJAR1HbTSNFMUpV8Dxcjg0nSYBrtBxdLbqI1iheCUh9XXNGurAwCdEkb9QyBSFam9TDfoPZ1LUg1BH28IiwEARTVAQOzcFKRaHZpLoa9avY6L1Gfs0c32t4PU6W2lWsV8LAorw0Cs1nXftYWE3qZGqwWHzYp2zzlgetuolVFvtiDLbRRKFTAWCxx2G/KlMtXFhWPqOzsWHJwBx7rxKv2R7mwFz3lw9/5DLC/M4Us2RwV0g3U58XJnF7dvrsBOoX0Abbej/DFKRMKI30fTVGC32WA2m5H9cQQvhYi0vE/7Wdgczn6ARA9QPBrBszcp/XvpyqxebzQ0Tlsq6llxLhe9bD4cFMr9XdjLHpLv+SLGBYHAYiVu1kNOpAaRTWbCejgiw0zGhFGSK1aw+zXbvfK/BBgAPwADAs5GpGsAAAAASUVORK5CYII=');
178 - background-repeat: no-repeat;
179 - background-size: contain;
180 -}
181 -
182 -.ipfs-logo {
183 - background-image: url('data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAoAAAAEACAYAAAAjlcdmAAAABGdBTUEAALGPC/xhBQAAAAlwSFlzAAALEwAACxMBAJqcGAAABCZpVFh0WE1MOmNvbS5hZG9iZS54bXAAAAAAADx4OnhtcG1ldGEgeG1sbnM6eD0iYWRvYmU6bnM6bWV0YS8iIHg6eG1wdGs9IlhNUCBDb3JlIDUuNC4wIj4KICAgPHJkZjpSREYgeG1sbnM6cmRmPSJodHRwOi8vd3d3LnczLm9yZy8xOTk5LzAyLzIyLXJkZi1zeW50YXgtbnMjIj4KICAgICAgPHJkZjpEZXNjcmlwdGlvbiByZGY6YWJvdXQ9IiIKICAgICAgICAgICAgeG1sbnM6dGlmZj0iaHR0cDovL25zLmFkb2JlLmNvbS90aWZmLzEuMC8iCiAgICAgICAgICAgIHhtbG5zOmV4aWY9Imh0dHA6Ly9ucy5hZG9iZS5jb20vZXhpZi8xLjAvIgogICAgICAgICAgICB4bWxuczpkYz0iaHR0cDovL3B1cmwub3JnL2RjL2VsZW1lbnRzLzEuMS8iCiAgICAgICAgICAgIHhtbG5zOnhtcD0iaHR0cDovL25zLmFkb2JlLmNvbS94YXAvMS4wLyI+CiAgICAgICAgIDx0aWZmOlJlc29sdXRpb25Vbml0PjI8L3RpZmY6UmVzb2x1dGlvblVuaXQ+CiAgICAgICAgIDx0aWZmOkNvbXByZXNzaW9uPjU8L3RpZmY6Q29tcHJlc3Npb24+CiAgICAgICAgIDx0aWZmOlhSZXNvbHV0aW9uPjcyPC90aWZmOlhSZXNvbHV0aW9uPgogICAgICAgICA8dGlmZjpPcmllbnRhdGlvbj4xPC90aWZmOk9yaWVudGF0aW9uPgogICAgICAgICA8dGlmZjpZUmVzb2x1dGlvbj43MjwvdGlmZjpZUmVzb2x1dGlvbj4KICAgICAgICAgPGV4aWY6UGl4ZWxYRGltZW5zaW9uPjY0MDwvZXhpZjpQaXhlbFhEaW1lbnNpb24+CiAgICAgICAgIDxleGlmOkNvbG9yU3BhY2U+MTwvZXhpZjpDb2xvclNwYWNlPgogICAgICAgICA8ZXhpZjpQaXhlbFlEaW1lbnNpb24+MjU2PC9leGlmOlBpeGVsWURpbWVuc2lvbj4KICAg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O4qxDy/KPWcv/tsh82bPxyKRSyH+woXBUiwwNcNIYdO5ZbPVtXWLq6DFPsSQ0C4xgDOZkI2p+CNzskdImGjb+rXXHXbQwhkSfwm9LGpMBERABEQgiwloBNDDxT1706bpDUsfuqmkuuZELKTI52igaX5hBiRmyJgyhI7hatVkFT+PAHLBTP+eZju0C7OxmBQKP476Ydp3tGf7ticC9TNOfeCcc3aZ1NU+IiACIiACIiACYwQkABNwJ5z56BNvbHnhuduRGu4wt2nluFKY/oFccWs6kuimy34UgBTJXJlMP78ogjqblpfStzU2Nlgjo5/611cv/JdpXe0nAiIgAiIgAiLwMgEJwJdZeP7rA7++6cyR0ZFfIK1cNVcLm45q8cBMJxeCf2CgEvEDE1j8JgCHuhnPD35+SONmWjhaynA6SN820N/U/G1M9f7MtK72EwEREAEREAEReDUBCcBXM/H0ypLVq0t3PPHUdwtD5V+CaCliOBPTaWHG3iupqbFCM+utwtJST/1wKvtFAEbh59fX3AQR1zFp3EGnvxO3HBFl+BwwjPVs33r74R/8wJIbjjhiYOI++lsEREAEREAERMA9AQlA98yManzquedmN69cdUtJVfW74B+YZwcxNgwbwxGvshl1ViniB/JvLyXdApCjoAOI59ffssd8RJRhXTDiB0E82rNr5wtFleWnPHjeeZu8cFBdERABERABERCBlwlIAL7MIil/nXrfA+/o2bHt94GqmgMYO9BVWjmscrXDxmBU0Mna4baT6RKAzC7C0T6GdWFWFNNip2/DIo/+5qYWjPwtWfaNr/7dtK72EwEREAEREAERMCMgAWjGyeteee+78befQyM/Ki4LVYxEhoyzW/DA9AukfyD9BN2WdAhA+vfRz4/+fqaFWVPykXYu3N0VHtjT/OMV//vty1B31LS+9hMBERABERABETAnIAFozsrznues2FC++/nlPw1UVZ2dl5dfGIMQNPYPhD9cKVYKlyJsDPPcmpZUCsBoOIzpXoR1wQpfN+fFfMOjsehI17Zt98487G2fuuPU47tNz0/7iYAIiIAIiIAIuCcgAeiemeca57z44gEND/7rDyW1046KDUfy7NXChv6ByEds5xYuhY+gSVq5VAhAO30bfPyYuzeG2H5GBX5+9upeTPf27NqxIThr5qn3nXnmGqO62kkEREAEREAERMATAQlAT/i8Vf74HXe/v7+n8zfFobL62BDDxhiKJxy2CKuEQ/WzrJLqagZF3mdHhvv6rPYN6yddeev4FdJfb+/C92oOO9wqDoX2fuvlf9PPr7MT072NrjKb2OnbAsXWYGdnV7Sj+0v/uuQrt7zcqP4SAREQAREQARFINoF9K4dkH1nt2wTOWraspHVHw/9AcH2zIFAc5DSq6fQphR9WGVuhWbNsQTgZ0qGuLqtz86ZJBeBk+7/0GgXgQQdbmK5+6aWJfzB9W19joxXu6oSn3qsF5MR9nb/t9G2Yvh4eGBzGaOGvFh51xNdvXrTIPBK005C2IiACIiACIiACnghIAHrCl7jKTCvX+PC/rg5UVJ6CIb18ho0xFYKcSg3W1iKjSL0dPoW9Yl2Kvz4kzRgeHIyro0XBIMTlbFsEOllK2C+s0LUG29uNw7rY8fwQ1mUUSrFnx/ZltW9+05l/ed/7muLqlCqJgAiIgAiIgAh4JiAB6BlhYhs4+5lnXtOw6qlbg9Nq34hp4Tw3YWMYNLkMsQMLse1vacEq3MSspQhUViIu4QykbRsa8/PD1rTYYV2K6ee3a1tJZfnp93/mM6tM62o/ERABERABERCB5BCQAEwOV8+tnvzHP38k0tt3XXFl5YwY8uW6SStH/73J/Pq8dMptm/YCD+Q5Dre19mCa+Kv//ubFN3g5vuqKgAiIgAiIgAgkjoAEYOJYJrylU1auDA5u3PQdzOtemF9UGKAQNJ0WTnhnDBscS99WYmGqODrQ1PD7acce88U73v72+OagDY+p3URABERABERABNwRkAB0xyste5+1du3MxkdX/iZYUfG+kZHRfISOMV54kbIOY9SxoAjp2/KRvm33rifLF8w79Z5TT92ZsuPrQCIgAiIgAiIgAsYEJACNUaV/x9MfffSt7Rs23hqsrD6U/nhu/AOT2Xv6+dHvsHdPU0N+nvXfD37xiw8n83hqWwREQAREQAREwBsBCUBv/FJfe3Q076Q/3blkNBy+vCAYrIohbMxILJb6fuCITN9WwLAuvb0DA91dP1x+0Zd/iNA0ZjFh0tJjHVQEREAEREAERIAEJAAz9D44Y9Wqis71G3+EtHBL8kbzCqMu0sp5PWU7nh/Tt43GRnoaG/4y+53HnHvrUUf1eG1X9UVABERABERABFJDQAIwNZyTdpSznl13cPMTj/0uUF19FKaE8+xUbIaBmV13yvbzK7JTuPU17F5fVj/3k3ef/vEXXLejCiIgAiIgAiIgAmklIAGYVvyJO/ip997/3t6mhhuLK6vnxJLgH2jH84Of32DLno6RyPD5D110wW2J671aEgEREAEREAERSCUBCcBU0k7ysZasXl3U+J8NF46OjnynMFhaFg0Peg4bY0/3lgSt4b7eyEBb2y8OOW7RJTcccYR50uIkn7OaFwEREAEREAERcE9AAtA9M9/XOHft2prGx578ZXFF+SmjsVhBjP6BLqeFGfi5AH5+Vn7+aO+uXQ/P/H9vPu2Pixa1+f7k1UEREAEREAEREIEpCUgATokoc3dY/Pzzr2t54qlbSiqr30QRaBo2Zix9W8Dqa2rcWjyt+oz7zzxT6dsy9zZQz0VABERABETgVQQkAF+FJPte+Ohdfzt9qLf3F4XBYK3tHxiNTnqSY+nbAtZQT09ftK/3kocuvODqSXfUiyIgAiIgAiIgAhlNQAIwoy+feedPWbY2FN75zLes/KIv5xcWBKIT0srZfn7I24sVxNHBlqbf17z1fRfcsei1feata08REAEREAEREIFMIiABmElXKwF9XbJuXf3Oxx6/KVBeeQJEYD6bLAiUjPY17n6y9uADT73jpJOUvi0BnNWECIiACIiACPiZgASgn69OEvt2+qOPHzfQ3Hg3FokUxqKxT9x75ml/TeLh1LQIiIAIiIAIiICPCPx/9LZZ0UZyLiQAAAAASUVORK5CYII=');
184 - background-repeat: no-repeat;
185 - background-size: contain;
186 -}
187 -
188 -.ipfs-mid {
189 - background-image: url('data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAAnhJREFUeNpsU01PE1EUPdOZKWUotKUKFLEWkQ1EASGGxGBi4sIVrt27IixN/Cn+CxfVnQsXJiz8IAoqRBGEaMUUWzofnXkz781436QDkjKTyXuZe96595x3rxJFEeTzaKW6dmdpfIoxjuRRFECGn7/4Utvarj/syWgflU5s891qvGoJePJasfBgeSpnW+yEIJVS4DEBx3FzGT2qfvh0tJxOE4mCU0yy8X3BLdODRQTJZ5oMzYaD0UuDePzkbnnx1mjV9/lMp+izBKEIwQMOzvnJGoYhhBDgFKtMjmBl9XZ54WapSjLnknMnEkQYgflCVhKXLt+/dRMy2d5OHdVnPoxeHUtLV8u2w5/S78UzBJwLMC8gAsosIqy9/ga37WNmvgKVKmEkb7JSwI3pIdRq1kBXBZJAUKkb6wd49fIzbJthdn6cIhE0XUWbyP4cmshmdZAE0eUBD6gCN0DtZwM7Xw+RUlVEJCui7CmyPaS94zC06ZMedREERNA6djBWHsS9+9fRS3p9AraOXbhELMlUQju2G2O7JAQENk0XhpHG3MIVlEZzaDbdOKO8jWy/TraGsMmL4L8KTgnIfcfy4JBWeQNp0j10MQtB4EJOg6qFMI/bEH3pGNtF4LOAjHMxO1dGvW4jXzDi7Iw60TB0jJRyONhv4MdunbDneMA6BMPDA6iMFzExcQH9AxkUiwby+QzevtnF2OU8lBT1i8fOa2UO1/FwdGTHE2STHM/14+vlPOz0RxibKPfn9AHXZHBzYx866ZdTKkuVndhHuqenS1h/v4ffvxqyvbUuAtPizZ0Dp7X1fTs+FA9cMnWd4ZG90NOjomVFzeTcPwEGACDGeYddZX86AAAAAElFTkSuQmCC');
190 - background-repeat: no-repeat;
191 - background-size: contain;
192 -}
193 -
194 -.ipfs-mp3 {
195 - background-image: url('data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAAnxJREFUeNp0U89PE0EU/ra7XWxpSsFYIbVQf9REFBHkYBRIPJh4wrN3DsZ4MPGP8b/wUCIHEw5EY0w04o9ILcREGmwVgaXbbXdnd2bXNxPahGyczebtzrz3ve99740WRRHkWn5cebu4cH6SMY7e0jRAHr9c3WxsVvcemmbys9yT6+uHJ8oaPefypdPDD5Ymh5w26wMkEho8JtDtuEOZFCrvN/4uJZNGH0T59D58X/C27aFNAL3Xthmsww5GCyN4+uzu+OLtQsUPxPQx6ZMAoQjBAw7O+bEVCMMQgqygs+LFs1h+dGd8bna0QmXO9OL6JYgwAvOFZKKoy3V44CgNfv7Yx8oLH+lUEgvzF8Ydhz+n41snAGRG5gUEwClzhHdvttFxfNyYK0EnJozKK5eGcf1qHo1GOxtjwI+pfvm4g/W1qtJgerYE2SXJSIL9+W0jk0mCShAxDXgQKgbNXxZq35vQKCiKQkSUXdc1+gcch1FHGPmKuIgBCdc66qJQHMG9+1NIpUylxxHtuW6gEiTIu+N4yjdWgty0yTmdNjFzcwKjY0MU7MLt+IjoSad16FoIx3b/A0DZ7FYXnsdpAjUMDOjI5zPgfoBsRodhhGhZHfBBU/nGAGRtxWIOg5lT2NtrI5dL0SB5KJzLodloqXaOEatPGztKq5gG3S5DNjuAK5NjKJfPYKI0okBkSdemCiSgS/rkQNLSePtxBj4LSCwfFtE0krqqX7ZVMnu9XlMXy2l7ME0dzA3iANQyY6vWxC61UY41zTyNcYh6/QCNXQvzi5dR39nHVq1BUyuMGAARsF6tbbe4iKD1r7Om5iFBdmW1SsDflLiuB6sX90+AAQDHAW7dW0YnzgAAAABJRU5ErkJggg==');
196 - background-repeat: no-repeat;
197 - background-size: contain;
198 -}
199 -
200 -.ipfs-mp4 {
201 - background-image: url('data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAAnBJREFUeNpsk99r01AUx79psrTrujVtbceabnZs4DYRHSoMh6Dgq77rn+AfoA/+If4Bok+C0CfxVRDBh+I2NqZzrpS1DVvbtU3SJPcm8SSlsJlecsn9dT73nO85V/B9H0H78OLdt/LDlQ1uMYybIAgI9n99OWxoe83nkiz9hDDae330JvxL48O51Xxm/enNtKPbVwAh0Ec6kYpXat9Pnl2GBC02HrjM5Y7h4P8+7FtIFVJ49OrxUnl7ucIdfhv+BIDv+fBcj7p/tXMPrs2RXVTw4OX2UnFTrXCbbY7tpMsA13FDSDAOQ4gJEGUJLs0PPh9CkESsPrmxxEz2lra3rnpAt3G6adgdQhBpmeLkFodNmsjpOPoXBrQTDcmFFNS7i3MRDzzPCw/vva8ikU+COQxm14BBhvJcHLGpGPTOAJxxeLbrRgAkYujBdH4G5oWJWXUW19YL4XqunAMFhnq1BqWYgaY1MAHASQOiU96zKzkU76mwehaOvx6h9uMv7KFN3RopL4oTAI4HRh4wSl399xla+00YbR3yrIzM9SzSqgJJnoKcklGrH08CcJjnBtLLCsSEGGpSWJvHtDKNoFippsJ0ulIsDDUCCATMlBQkNuahEyiZTcLsmFBKaQxaOk53TlHeKkM70AjAooCghBOk9sKtIvqtPqS4FBaRnJSRX8tj2DOh3lFB5Qw2ZNFK5LRo6w4sKt2ggAzywidAMN/9uIPSZglBLDO5FF3mRD3wHE9qVRvoHrUpfn+UEQK0/7ShtwboHJ6jdH8RZxSC57hSVETb7e5/2u0FxqPHJow+8iZ4lYY2QGu3idhIxO7Y7p8AAwALCGZKEPBGCgAAAABJRU5ErkJggg==');
202 - background-repeat: no-repeat;
203 - background-size: contain;
204 -}
205 -
206 -.ipfs-mpg {
207 - background-image: url('data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAAnxJREFUeNpsU0tPE1EU/ubRdlqmnUBboa0UeUQDiUGCC1+JmrhxoXt/gBvXJi74If4AV0Y3sNKF0YUaICqoIfjgVShEiGF4tDOdO/fOeOaSKtie5GZu7pzz3e/c7ztKGIaI4vn9p+/P3h4e4a6Pv6EoQBDiy7P5rc1P1Xt6XP8M5ejXo6UJ+dWbuemeTGdpvNdiNe9YvQLe4Bi4PmTpRmyq8m71rp74BxKF2twIHvAo+f/l1T2Yp0zceHizfOZa/xRnfBRhG4CQqAYioBWeXDyA8Di6ei1ceXC1XBwrTXHPH2vW6ccBBBMI6BsSUEQzakGL6xB0tvjyBxRNxdCtc2Xf8R9TyaWTDOg2TjfVdw6hqIoE9B2GxkEDWlLH7s4ette2kSp0oDRezrQwCIIA3oGHr0/mKMmE53qo23W4+w5S+Q5ohob9X3tgHgO8ULQACC7gMx9mKQP30EW6mEHpYi8xcJEdzMucjfkKcrTfmqmiFYBxCF/Id+gayKJwoQjHdrA5v4HK7Cq44KjZNWpagaqp7QACks0H9znW365ia24DzoEDozOJbH8eVtGShXHTwNracnsG7q6LzsEuaAlNPm9h7DSSVjLyCMkppDI+GS2StQWA1RlKo0X56n2X+6QHkmkDakxF9WMVqWyK+s/BrthYfvWz1Ug+zUDcjMPMm0h3pxEjFma3CbIuCud7oMc0LL1ZgmElpGJtW3B+15HIGNITrMYIlOH7i0U41NrInREylYbu4R5qQbQBaAh95fVKZCnpQCnb9DrWZyrRERS6NDeUw+yHaXh7rt4C4B8y+9vkwn7kwKNRpDoa9aiFKBYnF+RcREqQ2e1m3R8BBgAy9kz9ysCE6QAAAABJRU5ErkJggg==');
208 - background-repeat: no-repeat;
209 - background-size: contain;
210 -}
211 -
212 -.ipfs-odf {
213 - background-image: url('data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAAi5JREFUeNp0UktrU0EU/mbu3FfE1KRRUpWYheALNBURUVy7cy9UkO6KW/+Lbt0IPsFui4gLBbUqFaUuXETUKCYa0jS5yZ2ZO557b5MmTXpgmDPnfOc7jznMGINYPi0de5UvmpORxpjE/kbNqW005DVu8TWw1H758ZfkFgNgJmtyxSPRjJIj0QTW/RDiYGXGb7Dl32/eXrVsd0gSCx9miqC0ooCdp69g5Q/h6OLN0ty5ynIkwzMwUwh2FwMdcbDiCZQXlkqFCpEoPT/wih1YjLInANcD+/Ua9bu3wJlGvrBZCmet2+S6ME5g4oGlZ9A/I70XCDhhDexPNTFmswJBwcnuXkF86VSNZxVu0ukLSGnBcqlnN4HoCQIaIuIv7LUooMOgQ7q75LAAb59B9gCBHSKgqemRr94mMKmD24CfM8nb7THYGQNLpAkUkcb66JyGBFFEWRVL57gFEH5qj8Lxwca2qS3EZaugmzAw24dR/XQgwtsCSBjPIdWbUoE2UJLBnV8Ac/ciWHsK9/glWLnD6K2vgPszsOdOQdfeQ1c/ThKoTgDn9A3KUED/52d45xchZsvorD6Bf/Z60riV3Q9Z/0bbGU1uopYGkfERSQ3VbsMwl0qlqoIARmSoPYXWy0dor79LfBMEEd8jGs/uQ3Yl7PJFNFbuEXiV2riCf88fovXhBbo/vqP3t02/ZYmJFqTkzY160Go9uEMbFK8hR/NrdXtFuUVmnmySVGgO4v4LMAAjRgmO+SJJiQAAAABJRU5ErkJggg==');
214 - background-repeat: no-repeat;
215 - background-size: contain;
216 -}
217 -
218 -.ipfs-ods {
219 - background-image: url('data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAAetJREFUeNqMUj1IHEEU/i7u7Z23e8tGgneGQPw3hZDkkhQiSuwMQREba4uUgpVlCrvEQhurkCoWqcQQ0oTAaYKNqJygGEwgHCSB6Knn7eXcdX/GmdHVPWYFP3gw78173/vmvYkQQsAwNvckq96UnyIEh7/d4t7uUd/8y+85P+bXSX4grkhI6nJYPW7LrXpBK2YxiSoShhu4Buq1NPofDeqdrZ3Z4cl7D4J3UtA5VyVAlmJoru9Af2ZAp1lcCQ3nqgiuKmbY3l/BH+MnHM9GVLP0Ww3KNA33CQoQQnL834Fj74PUGkANEIkCSSsa8gQqgYTIcB0PVsXB318GInRiCVWCkpRFAs+j5gKlA4t29Ggh4d0t04FKt9PQqF4UFgumSEA8ApeaElilWbYRVy/lsns/N1QBkxtENF4jxPxcgcB1CZVOrvMteK5IQDtJJIGh++PcX9iYwWjXK37+vP0WdYk0Ht99jtX8JywWFkQChw4tc+cZcvlF7rMze+ubbxN40fMalRMDP/6twaiUeK7wlZ0TD0a5hLTWxo2d45KKprqHKJslTsy209s2wnMFBTYNZjc/oLt9gPvLOx+hxVJIKS2YW5pCbSyJTGMK775O8VyBwDJd2LTDl/X5i8v3S7NVw9vJb51tITDEUwEGANCx2/rXEEFFAAAAAElFTkSuQmCC');
220 - background-repeat: no-repeat;
221 - background-size: contain;
222 -}
223 -
224 -.ipfs-odt {
225 - background-image: url('data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAAepJREFUeNqMkz1II1EQx/+7Ca6JkqyYiJ8cKEpAQbBQFDm0sVOsFBS9wt5KOTgEG5twxVlZ+XEnKNiIghYKxx5nwEpIIXaiSAgKGmMi0d23u8+3T7OaZJEMLG9mmPnN/w1vBUopLPNNhRWXHOyDg0nx82TiJtZPlPVoNpftc2cTotcHtxx06kdXpSQ/BvzKESZzIDmAz6y+NojOjpDMZiqRPIgNoFyWM8DrKUV7axO+gcp4g7AzmquAdVNqOgL2z2I4id1B0wgeygOyt/rLL5buLwAIDgA9dY+L+DkuDQOCrkMgBsRglcMOqAGwIstMg8AkGsuZMNUMRMkLqE+QGloglvlA7uIOAKvZajR0qJkUj/XHe0BTIclVKKlrfKsj9qA8gA6wqSJzPaXlr7ky//tdLEUfawsBjExUFGVWbT7AxSa42H2LMfODmvd3wKb7RAMLYwM8nts8xJ/pEe7/3PmP2eGv3D+9usb35W0bINoA7RmjXSHsH0f5Z/mUSZ0Ir2JmsBtD80s8/rGyzWsLFTD5yUQCbfUBHl9d38LvkdDTXIuHVBo0k+bbt06qO+yAPGXwe/cA4wO9PN44jKDG70GougIzi2tQ00ms7/3lpwnBBgjZ37Kkd1Shht5XzBIFl/ufFtniT/lFgAEAU//g6kvdGBMAAAAASUVORK5CYII=');
226 - background-repeat: no-repeat;
227 - background-size: contain;
228 -}
229 -
230 -.ipfs-otp {
231 - background-image: url('data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAAcJJREFUeNqMkssvA1EUxr+ZjkdbrfFKVD12ErYSRELY2fkH+BMsLcQaSwsrSzZi47EjJEQkEhYkFlhYSVtFpdqOqpk717l3jKZmiC+5mZlzv/s795wzCuccQncz3YeRBj4KHz0/RrOZe2NsZPP20o255zQ3EAxzEAC+6uzTw13G4TFQAakA/CWtIYbY0KBOrx7IvwDQqlHV1o3YxKTOvyAUvfQCfqmA3e4ikyS/zRAKvOot7eoSHEgZIHrCfQAfBqBaKQQDKScQAExd8emBANg+2U2CvNMkkgSqBmrCxFB8mujeoJBWwEqARcssKTAJEGrmaGrjqK1zvNknH4BtyxKl2VUpRxmj5W+x73q9AEaZrR/ND1EJluIpS3i9JQiA+a+hSq8HwJjTsLrRaWitPTCOlhEZn5N75sM1qigmlN+dB3u++Qao5W4TtbEXXIsiszGL4PA00itTsu6XnQWo0TjMTAJqfMDx/ryBJcaVzSNSH4fW0Q+rkIf5rsjRiid7yyN7uoXS3Zn0egE0NiORAN9bQ017D1Lri7CLlP2EDr3Rf7C/itzV2bfXA/igLDaRixfngFhSCooH2xVPCWBlwKcAAwBX1suA6te+hAAAAABJRU5ErkJggg==');
232 - background-repeat: no-repeat;
233 - background-size: contain;
234 -}
235 -
236 -.ipfs-ots {
237 - background-image: url('data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAAfZJREFUeNqMUk1rE1EUPS8zmabJdDKB2glEwY9ExJYiBUEQpV25qgtBXfgbpEtXuujKf+AfEKRddOdOGHClbYVCvyKWaijT2mhjphk7Sd7Me76ZONp0EsiBYWbOvfe88+69hHOOAE9f3zTVnDKNHvhlsfqPw/rM0ovyWsRFdXJEpDIyRnSlVz0KSkmvabaJeXSJBEhgAJzTDNybmtUnS5Pmg/lrN07H5NM/f13FoMgpXDSuhiIiK3Qi6LUugX7FAbaPPsJqfIHHKCStqRsXVFPQuZgD9BBxjikSiRq41AAkgCQBzVf0+BWEBX7GBm0xgHHUqk1UbBuEcIydzyCZlOI9YEGuDxwduCCitS3Xh3viCZ4jrcq4PJ6DLHd67tjtuAAXib54dCPVEfQ5XIcik/0/2iDeOYz3ceCxrisMi904y0XiMQFfkB7lg6xFHwFxEqUMV0anUNBLWKm8xd3i4zBWOzmASx0UsiW831mA59Xjm+h7HCOygduXHqJatzA7Poey9QnXjTuoVD/j/sRcmDOWLgqnLC5A2wwST+Pn8T629lahSCo291bwu9XA7vcy3m2+gTaUR14thrk9BXasbdiOjSe3nmPpwys0xSi/HpbDd3bIQC6dx/q3ZbRb/j8BEi3Po5cTJpHI9CBNDEa++GyDBN9/BBgAwfDlCVUQaNAAAAAASUVORK5CYII=');
238 - background-repeat: no-repeat;
239 - background-size: contain;
240 -}
241 -
242 -.ipfs-ott {
243 - background-image: url('data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAAdFJREFUeNqMU89r02AYfpJ0iVm7EqhVOxw7dDBEdpiCE1RoEZRddvUgbIex/Rs7eehppyF4LOzQu4MxwYp0HgShIuwwUVSCVtl0s13afl+SzzcpyZYmyF74eN583/s+PO+PSEIIeJZdrtQVI19Cgmk/Ph39bpllXq82g7sgLxVcyKNZpIx8Uj5u5zSjc9Gov8ZihCRC8D+7On4JczevGeTGSEIC4ctKJtB1DTPXi1iCCEkIm1EFlC2Em0iwtWfinXkIzjiO0jljtDC5TtflGIGUQMB+mfja/oPv2Rx9MMjpMdJxOXyXTwkcwIkewfqQ1QtQNB385zcI14FrtQexsSb6SRysZ4Fbf+F6eHwATc9gJGNAm5iCTL5n/LCVRGADNoeaGoHqyaXj5gqQlTODovcwNk5Aj6wXqV8eCo7EDhMonEHpW+dZC7gUG98D3geo7vkb01h9cAvPdt76OGy1xntUd3bjUxAk3+l2sHJ/FgtrT0MUJNfDSm0bjQ/72Hzxxo+NK+h3B7XRNO4UrwymQtMIkdTBU0m+sBOayLsn8Ka78mQDjx/e87HXPkb1+UsfP37+AmZ1fP/suknBb6nefVQXjl06TxMlJfWKNWr+Kv8TYAAkUueexJF47QAAAABJRU5ErkJggg==');
244 - background-repeat: no-repeat;
245 - background-size: contain;
246 -}
247 -
248 -.ipfs-pdf {
249 - background-image: url('data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAAmhJREFUeNp0U0trU0EYPTP35qYxaW6TlDapNKWGbgo2FkF8rARB6rboXusf0F/hyq2U4krFqugqSBeuAyL4SERBstHa0iR9JKZJ7mvu+M0tqZGkH3x8987jzDnnm2FSSqh4ns0VU1ybFzj674Wa3uWiWbfsFQb+jrGj8Xvbm0HlvYVRxhJprpmTlGmum+OMm5uNPZNbtjk3l82ey8++8oW4Jv/H/wdA456g2kvH99FyHNiuAz2dwflbN8YW8zMK5Go/CMfQkAhpGsyQgRCtlpE4jIULyC9fHzu7MPPEl/5ib6WOE0JJNRiHHg6j86mMjw/2gG4bkbY4PW4Yj2j64skA5FTHdaEMPiAJszt1sK0d4suJmY4k0+IDDGRfqmh0u5gejQc+fG8eYCIahRQCEfgQnIuhEkgtONE+dGxYxEDj1DhiEycZ+1YXdUpHCqTMJIYyEES5aXXQsi2kYlGEia5GtHVKn+amPBeCutPgfLALPuVu+xDVPw2EQyFEjHDghbpYNm1yKVVnYjTOerepn4E6XQmLGSPkPkOXWATMSDcjQEkAaqOu6+i/rccALtFL53LI3r0Nq1ZD4/MXZJaWYFer+PXiJc6s3IEgY3+uPYZHTAcAHM+DTE8gnM1CSyaCulv+GrRy8uYyElcu4XfhLVpkpNtn/DGA5Uu0abFH36WnzzCayWAkmYJvWeCkfb9SwY+NDbSoOx4bYqJF8rZqVRRXV/HhzWtUSmWwmWl0RmN4v76OUqGASrmMOkntSHF8MOs954dT08W248wzYsJDOujRBAaqqikTpRo/qqd0/dv97c3Lat9fAQYA4z8bX9nTsb8AAAAASUVORK5CYII=');
250 - background-repeat: no-repeat;
251 - background-size: contain;
252 -}
253 -
254 -.ipfs-php {
255 - background-image: url('data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAAhNJREFUeNqMkltrE0EUx//ZbDaXNrvZzdIkbYOXGgxYQlCK2IIY6EufxGdB8Av44AdR8AP44JOPBR+Ego0PClUKTTXQSmkTYtOkmubSJrQ1e3H2yJSEJNIDs3PmP+f89pyZcdm2DcdWvn7LzkxFHmCIra7nm9ulg8yLZ09yXON55Dgjt1PM2iPs0+aW/frdh8bzV2/SvQBnCLiEqcFxLKSSodlrU9leiGPihWePBkgeEZO6ShC2dCAZNuf6ADb+ldQ5PUPx4BCFcgXfdwq4Ph1Dtd5CZi4Nw7SQiMdCXkl6yVIy/QBWgcU+yx/XsLK2cdHndqlK/lZxH/OpJO7fnsWY3z/YAq+g0TmHpoUH2vB5PXi8RD9Fo10aAmDJTgWyIuOupmK38rsPcOvqJO33XWEvwLJsmKxHRVEwf/MKWl/yUMf8mIloWN8rw+sP0D6PHQmYuzGNgCRiMZVA17IQV4OIaTI8buH/AJMFd02Tkp05PO4jnWvc57EDAINt7u1X8Pb9KgI+Lxbv3cFR8xjx6AQ+b+Txs/qL9KePlih2CMBCq92hg2qzt1AoV7H5YxdhdqhHzRbgcpFeqdUplpvQW4FhmAixZ/sws4BoWCM/qmsE5XqE3dDQCrqGAYWdejqZgK6GUD8+IV9VghBFN1RZJv3sT5diBwC15gncggCPJKF0WCPN8dun55jQdVpz3Ynl9leAAQAJhiGatD9AOgAAAABJRU5ErkJggg==');
256 - background-repeat: no-repeat;
257 - background-size: contain;
258 -}
259 -
260 -.ipfs-png {
261 - background-image: url('data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAAmtJREFUeNpsU9tOE1EUXXPp0CAUWmJbC04xBANNTF+kKhG8fID6aqL/gPEj9E0lIf6Dj30HL03wxQtVIC0QKrWxNG1Dk9Z2Oj1zxn1m0oIZTnIyZ8/ee+211z5Hsm0bYg29fLGpxWIJWBYGS5IA8ncKhT9Wvf4Yqprtu+w3q85X7f9QxseD/pmZMZsxN9fnc5JNw0ACGGv6tPSvyvEDKEoWZ5Y8OHHObKpucw4B0t3agnl4CJPs2YkQVu4s61ORaBqMJc8CDBiIRhhVM9bXYdVqYAcH8M3NgS0tQQsFcfdKHEbvlr6WyaR/V6uPKPy7B4DT7lUq4MUipMlJ2MPDUKtVfKZ2nn/5BoNbkONxXeb8LYXe/A9AJLNWCxgdhZJagDI9DZg9qIkEytRSkdqTSFQtGILSbgc8LViM+tc0yPfukzIyOJ359k9YR0eQdB2KmBbpwXoM3Dod1SkD+scpEapCI5DdpsJhIJcjajQZagcjI+5oLe4VkeQnyiZgdIH2X6BJ7dSqQLfrggjw0AQwP+/GegCIHppNoFAgEMO1RZKo7BQgRi3yN05cnwdA0BQMAgF3C6pnbuNg92M9AFT1diSCh6kb+FGvo2MxnBB9ocZxp4Mns1cde213B81e7xwAcl4jkaa0IUSjUdLJwkL0Ej6VSvArCt7l81iku6GrKnYEU89VJlSJRmR0Dax+fI9suYxSo4HlWIw6M3FBlnD9YhiXabyOsOeIqG7TzDeIYo6EDGp+ZPb2kKKqH8h+mkxiI5/D1/19J3bwYPvPWXq2skkiJVxesqt0XzghpKM8nRVV2Lv2q9eLIvSfAAMAaacnllcFBmYAAAAASUVORK5CYII=');
262 - background-repeat: no-repeat;
263 - background-size: contain;
264 -}
265 -
266 -.ipfs-ppt {
267 - background-image: url('data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAAkhJREFUeNpsU11rE0EUPTM7ySZpmzT9DNamWAtFfSiCigr+AxF9zKtv/hvf/Aki+FEi6ov4ItWHPGiwiBUKoUqqTUJImmR3M7Mz3t0kNe1m4LIwc+65595zlxljEJzdR5uf5nLmsvZx6gSvtd9W9bjhF7jg5dH9nRc/wq8YXaTSJptb0xklx7IZoKUEz1zJ2DUU69/37vFYrDxegJ9U0lC+AoIIVGg9CL+vIObP48KDQn7x0sWiVnJrnEDg7KGk+i/Ac4iUM/R7BsmrSSxtXMfa3X7el8+Kjf3KfUJ+iRJQw4w0Tc8BRyWGRAZY3rBR/VlC+XED2ayDhZyXl03+hNA3TxNQshlGLAnE44zCIL1goXZwiMNvB1i6zbC0KuAsxNITWwgNMYPeLVJiFEO9ArjHAivrAjNzBr4f4vwIgdGD4YUACsZCE8AtYGWT5jCsGQw5wEYJzP/pj5RwYTA1b07eQmfZ8P0sgdaM2FlYwWkMgMpl6NQAO33GKM0wsQWflkh1uqGVmVWblsiDkQyqxwfag35SqcktaEWTUTHYNx4iGU/C29+BvX4Lpu/C7zYgFjegSY63WySsHyXwpYHU00ieu0bAOuJbBTArBkiXKiaAmTzcvRJUV9E8rOgqBwqlY8ASs/AadbRLb8CzeTjVClqft6FdB17tL7yeCbFRBYoLr6vR/PiSEl5BZJaBD0/R2nkOZqfQ2fsKt+0SEQ+GLSIEUvJm+6jbah2+pS2aon+4g/afd4SYJVuA7vvXdC/IHQtSoTnK+yfAAIEaId1m+vudAAAAAElFTkSuQmCC');
268 - background-repeat: no-repeat;
269 - background-size: contain;
270 -}
271 -
272 -.ipfs-psd {
273 - background-image: url('data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAAqxJREFUeNpsU01ME0EYfbtdKKWGtoItRWgJHApCBE2I0YuoiSaaeDJeOJh41YN3TfTixcRwMfEk8eDJGA+Eg0YTTRRMg02KKFooCBbTlkJLS7f7P+u3K9Xo8iWT3Zn55s173/uGM00TVlwZfzJztD92iKO5ouvQGQPHcQDN380vlDPr65fdLj4Oa41i9sFt+ytgN7o7woGOrqgvvpLBaF8vWj1NUAwGTVNRM3mf5vU/zaU+XySQuTqIFXz9hxmGLkoS7r+YxvVnrzGzlgXPDOzUZPT4m3Dt/KlIuH9oUjXYEHZZ/wOgGQZi4TZcGI5hLb+FO++TSOSKcLtcMA0dI0EPrp4+HtnfG5skiUecDGwQE2MjAwiGWlFVNDz+tIyCokJhPKYSX7Gdz2I01hOJdnY9rJ/7UwPGTEiqjtbmJtw4MYx78S/4Wa3h5UoOYwPdIOp2Xi/t18rlFgcDw6o+ydiWVRwOBnCpL0oOAMmNEhLZIgSeoxwGSWcERon/M9DoBknTIdNQNAMnO4PIVGpIFXcwndlA2OtGc4MAxml27p4AIulWSIa9QVadiYSoJxhqBJivKgh5ad3k9gaw6JdlDaqq7q5wINY4F22HaLHSDZQkBW72O9cBYFEviBIURQH7a7MN0uDisUW12ZZcaGlmdq4DwCqeTo1zNtZuW7hUqGIw7MNqSUS2ImNsKEpSdEwt5lGhfQdAkQBEoub3NNrDJfAIeBuRrcrY5xGQ2RFJAjl00I8PCckJUCB9q1URBnk38XEJEuk41tmGwZAf66s1VOh2keqwoUnYpFxHH4iKIixkN3HzVQKP3iQR/5GDKMuYmE3h+fx3MHqh1sMafztHLuiCg0FAk0uFdLqcpGY5QEXbTC/j7mIaVjc18DxufUtBJ/vcggs+3ijVz/0SYABsJHPUtu/OYwAAAABJRU5ErkJggg==');
274 - background-repeat: no-repeat;
275 - background-size: contain;
276 -}
277 -
278 -.ipfs-py {
279 - background-image: url('data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAAlVJREFUeNpsUktvEmEUPTPzTUFmgJK2UqXQFG3pA6OBLrQxamJcaYwuu3Dp0l9iXLvVtRuDpgt3JIYaTVSaxtRHsJq2xEJBHgXmifebMhECXzKZme+ee+65516h2+2Cn2cb2VwyHl12//vP2/zOQaF4uD7GWN69e/LogfNm7kUsPBFaXYwHMeK0OlpQEJApHJTuykzK98dE98O0bLM/UNgr4v32Dj1fwSQRt9dSsfmZcMa0rIv9ODaqYrPVxuPnL1Cu1aEbJu7fvIZUIo4bqeVYRzcyv/8c3SPYpwECt/dmu4ON3Ed4TymI+hQc1ZqoE+F+uQLDsnHlwkKMscJTgl4eJOi9fxZLePNhGx6ZQRRFqH4VjZaGSv0Y6cQcJLpra0ZguIWegqDiw7lYBBZV6xiGk9DQDLzK5bEyF4Hi9VLMsoYI7J6Es5PjeHjnOl5ubqHaaJGBEkzbxplQAKIgDmBHekDTgI+qKKqKLvNApgmEgyquLs1CoFn2Y4cIeLJpkjoCLkWnUSIF3JxISIUsCjAoxhWNJLBIJs3YeXj/08oYZkOKY65HllE/bkMmY504YUd40HUq2JSSyW6iVPmLiXE/ZMYQCU+hXK3h1toqdNN0sEObyKtqtDQ6kXDwcadDS2TBryp4nX2HxXjsJK6bDnZIAZem6Tp5YMMmicn5OC4lztNWtvB9cg+hQABtWjKL2jH/T3GgBcYDXEE6mcDM6SlaJAGMWkivLBC54ZgniZaDHSI4rNSqn7/t1vgkGJPwZXffSeCjk2iUWz9+nSTQN8e6ef8EGAClUi/qoiOc3wAAAABJRU5ErkJggg==');
280 - background-repeat: no-repeat;
281 - background-size: contain;
282 -}
283 -
284 -.ipfs-qt {
285 - background-image: url('data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAAnVJREFUeNpsU8tu00AUPU5sp41NkzRxpfSZqi0VIIQqEEJUZYXECvbwCWxYsuBD+ABUFrDrCnWBQEJdIWigBSr6pqRJ1ebhxrE9M7aZmSrQ4o505fHMnXPPPWdGiaIIYrx89GKpNDdxmXkU3aEoCsT+z8W1Sm21+jCpJctQTvaerj+TX7WbnJ+0cpfuX8mQtn8GgJ4AZtIFY2Hz3foDVRcgyt+cRHcS0IARh+D/8G0PpmVi7smd0dLs+AIjwTVEiANEYYQwCHlEZyJgIQKfoX84g9uPZ0cHZ4YWmE9nuufU0wABCSSImMsWEgqSuoqA/39/swZFTWLy7vQo7dDnfPvWWQa8GuOV3IYLJXmyzDzG2/ChZ3pwbHdQ267BKJoYuj7SF2MQhiF8LuDK/Gf0DKTBKINz1IbTbEMzU1ANDW7LAfEIQKIgBsBFlAx6LYOz6MAcvoDCtAVGGPKlAiIu/F55F33FDA6W93EOAOMaMOl7biKPwRtD8Foetj5sYPfTDtxjl1f3Ubo5jkQieQ4ACSUD2iE4XDpAdbUiW9D7UsiN9WNkZgxajwbd0LGzt3keAJPUc1N5SVeENT0Ao2BKV6QzwlZeRBSKAYhe3aYHcZWn7l1EfjyPypcK9LQGa8qCvW9j9+MvaasQOHaRhGWdhsNLR8hwodYWf6B4tYjDjSOovRqq32rSYq/lytw4A77o1V2ERiAtzY5kkUrrsH+3QF2KY87ArTtQuQ6nAf4x6FCV1D001+vYersBM2vA4y1Rm2D7/Rac/TZIw4d/6MrcGAPf9htN0miJh7Lyuoyvr8rQeP9iVJcrSKgJ+TrFcyYebXTP/RFgAFQobmIOBxbsAAAAAElFTkSuQmCC');
286 - background-repeat: no-repeat;
287 - background-size: contain;
288 -}
289 -
290 -.ipfs-rar {
291 - background-image: url('data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAAnpJREFUeNpsUktPE1EU/u68OgylZXi0hZACQU1LEKKCMcat7jTRnQsXxsQtv4E/4M74P1iriUaNCw1FgxpjCJQKKAU60+m8mJnrmSll4XCTc8+959zz3e88GOcc8aq9evChOHl/lvMoubvWX/z4+BwTlbvw7bXdg8b7h6LE1gGW+O88CRMt4XTlR6/rYxce5Xv3jlHH19fPkBu+gWy5mlcFb3Wn/umeKOEMJF5C7xCFbtA9dRXjFoYKGiTRAlPGUV1aKU9O3VwNQ74A8DQAIZxqAuAhBPIMFYpQVAVB4CPSZjEzv1weH5tbDQN+JQ2Abu488mnzIbAAA3o/VK2PwDJo7r5Fy7ZRuvi4PFS6+qIXdVYD8Jg6BUcuOD8BozSLlRWyicgVKkTMQWwUlFF0Ooe5FIPk57BD7G0SiywyjD8bCDyHsOkeeeR3SUxEkROmU6BfQYFJMHfhWXV8efkUrb13VPMTsrcTQSzxZ/+n0GVA6EGbSGdgG9vo15fg2nFgbO8k70SRdd+mahDT81vUxTZRlJBRMsjq89C0EXCvSf7TIBZ136YZUJEiE7LgJ2dN01BZuE0dkIhxE7KcQTK1QUj+cwAEyrPZ+IydzRoyah+mLy2isbWBweESJEnB9q+1RM9Ub9GQOWkABg8HjRr2d9Yh0hTlBlRsfn+D4vg0BvUC9rZqECUJuk7Tzr1zahCYlB6HJAREPwfbbMBzLBzsbUKVI0qBgQkc+SxgWUYaIAqOpKwKXJ6bgGlaaDV/YvHaFNrtDsKTfVSrJeqIg/bRNwjclFIALeP3saybhu8SC4VBHwnhBXXIKocYRXD9QzBi4Xgchmkd9+L+CTAAMqwy+ZzluBgAAAAASUVORK5CYII=');
292 - background-repeat: no-repeat;
293 - background-size: contain;
294 -}
295 -
296 -.ipfs-rb {
297 - background-image: url('data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAAixJREFUeNqEUktvElEU/mag5f2yJhXLwxIt0kiqsVEXujP+A925cu1Pce3WtXVtYuJCF7KtTY0NrVQIpRVKeXTkMcO9F8+9ZVooJJ5kcmbmfOe733fO1YbDIWS8+/g1dycVX7W/xyO3vdsuVKqvnE7HZ230783rlyo7bVBicSGyfjsVwozomVbIPe/c+FmsPHfoRKJd1HT7hXHBZjVbA4aA14NnD9bC2VR8gwuxPi5Sx39Cp+M0XUP0ahhP1jLhW7HFD4zze3b93ILtXYyyVKlR8/5hFbnvO9gtlrGSjOF+OpXkYviWyo8mCS4R6bqO4p86vm3v4fC4DrPfw4unj1XN6JvBaQtjChzUXK43sVU4wNFJA43Tv/B73edQwTmfIhAjCVL6UdPAj1IVFSKhCdAcAI9rnjBiAjtBYEu3GEeh1sKJ0YXR68sVIujzIhzwY8DEBHZqiLRKkicQDfvABxaiQTc4Y/C65pCOXwcjcmlvJgHtlwi4epYifiQWgmoLZwPW6HQG07LgcOgKO0UglAKOTt/E+09fwAiUWU7QAE9xUK3jbvomsispZVHMVEDSZdHo9rCZ/4VIMKAu0XGjpU7d2S8hk0pCELHEzrjKnCQOYJoD+Dxu1RyiwUm5LaMDo9NFt2cqDLvY4oQFp/QpfT/MrmI5FkWebt+NpWto0j2QmQkOjZ9hpwhqjXZzM/+7LU+cc7lRrjXh8/lVLRK5ovLWXglOsiOxdt8/AQYAzv8qbmu6vgEAAAAASUVORK5CYII=');
298 - background-repeat: no-repeat;
299 - background-size: contain;
300 -}
301 -
302 -.ipfs-rtf {
303 - background-image: url('data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAAe5JREFUeNqEU01PE0EYfnZmd5FSvgLYFuwWt9EgHyEaox68eDJevHvwJ/hTPHv1N/QgZ2NC4g3kUAQKFKGhjVKqRrvbnRlnht262FHfy+y8877PPM8z71pCCKh4/ebt+rJfXEz26Vjf2mnsN5rPKKWbVpx7+eK5Xu2kyMtNTd5d8MdhiJ9BOO7atFI9ajy1UyAqSPIRMR6ZmoNehNHMMB7fX/UWvEKFMbYKE8DfQnAhwRmmJkbx6M6S5+WmK2Evup2c9yUk2nnKA0XVcSiGXAe1k5beP1i+4RFCXqnPywB/AKVzK34RjHNYlgVKCH50w7EBBogbTa/AVM5SgBdn0gc2AMDjPsbFPz2xye9asweS6n+NTbG8BCCfUtLjff2WoVnVpAH6z6hMUtJE3EykYfpF4vUiL3QNS7FMeSAQRBHW3r1Hq91B+VoBQRji4+ExFsvz6Hz7jm7Yw5OH92AcJKW9G4SoHhzhy/lXbB98Qmm2oCXN5WawsV2TACEoJXqwTKOsb3BtR2ucmZxANpPB8JUhyPnHWDaDpfJ1eZFALzJJ4MKO5MEtv4TSXB7V/br8iQLMz+almRZWbvoo5q9qRlxwewCgeXbe3qrVO5ZkUD/9jJGRLPaOm6COi92TU1DbxYe9umRD0DrrtJO+XwIMABWp9nS+FgaoAAAAAElFTkSuQmCC');
304 - background-repeat: no-repeat;
305 - background-size: contain;
306 -}
307 -
308 -.ipfs-sass {
309 - background-image: url('data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAAyJpVFh0WE1MOmNvbS5hZG9iZS54bXAAAAAAADw/eHBhY2tldCBiZWdpbj0i77u/IiBpZD0iVzVNME1wQ2VoaUh6cmVTek5UY3prYzlkIj8+IDx4OnhtcG1ldGEgeG1sbnM6eD0iYWRvYmU6bnM6bWV0YS8iIHg6eG1wdGs9IkFkb2JlIFhNUCBDb3JlIDUuMy1jMDExIDY2LjE0NTY2MSwgMjAxMi8wMi8wNi0xNDo1NjoyNyAgICAgICAgIj4gPHJkZjpSREYgeG1sbnM6cmRmPSJodHRwOi8vd3d3LnczLm9yZy8xOTk5LzAyLzIyLXJkZi1zeW50YXgtbnMjIj4gPHJkZjpEZXNjcmlwdGlvbiByZGY6YWJvdXQ9IiIgeG1sbnM6eG1wPSJodHRwOi8vbnMuYWRvYmUuY29tL3hhcC8xLjAvIiB4bWxuczp4bXBNTT0iaHR0cDovL25zLmFkb2JlLmNvbS94YXAvMS4wL21tLyIgeG1sbnM6c3RSZWY9Imh0dHA6Ly9ucy5hZG9iZS5jb20veGFwLzEuMC9zVHlwZS9SZXNvdXJjZVJlZiMiIHhtcDpDcmVhdG9yVG9vbD0iQWRvYmUgUGhvdG9zaG9wIENTNiAoV2luZG93cykiIHhtcE1NOkluc3RhbmNlSUQ9InhtcC5paWQ6MDNDMTBBM0JGMTE5MTFFMTg3N0NFOTIyMTQ2QzhBNkQiIHhtcE1NOkRvY3VtZW50SUQ9InhtcC5kaWQ6MDNDMTBBM0NGMTE5MTFFMTg3N0NFOTIyMTQ2QzhBNkQiPiA8eG1wTU06RGVyaXZlZEZyb20gc3RSZWY6aW5zdGFuY2VJRD0ieG1wLmlpZDowM0MxMEEzOUYxMTkxMUUxODc3Q0U5MjIxNDZDOEE2RCIgc3RSZWY6ZG9jdW1lbnRJRD0ieG1wLmRpZDowM0MxMEEzQUYxMTkxMUUxODc3Q0U5MjIxNDZDOEE2RCIvPiA8L3JkZjpEZXNjcmlwdGlvbj4gPC9yZGY6UkRGPiA8L3g6eG1wbWV0YT4gPD94cGFja2V0IGVuZD0iciI/Po72XUcAAAJcSURBVHjahFJdTxNBFD1bykc/ttvdtttWGgI0bYrUgDZoNYqRJ014kMRXHvwB/hQTH/wFhMREJfFBQxBjhMRIFEQSCAlQxKYGggiU3e3HbnfX2bFt1EU9k9m9mblz5p4zlzFNExYmpue/jmTSZw5PZAl1MAwDT0c7O72wvPdudeNakPNtOZ0tsM7cvzdOc5yN5LDAsTFRAJks/kC2PxFRVe39Si6f4byez62EpAEH/gNN18F53Ri/Ocxf7OtdLMpKT42s/ZPg1cISJp/P0tg0TBzLCoK8D7eHh4RkLLJ4cCz12AjMXwgez8yhqtVo3NbqRKlcxcSL16gZwJ2Ry8KVc8kZO0HdTKlURn+8G6PD2SZhLMQj96WAiMAh2RXFYKI78lcJcx9WYBCycICnpNbojUWpD5Y0C4Zh2D0w6hWc70uQZC+IWfQZrXF0IsHvY+meBd08haAhoVMMQFJKWF7PNZM+klhRyogGhbqxOIXAMOtEwGAqDqVcgbVkkE+5UsEAWavf0az2t0ZqvK2qabh6IU3joizDwTgwej1LdVfJXkdbK8mt2QkayO99A0/0trQ46I1lVcX+UREhnsP34yLp1AD1xibBMuntpzU8mJyi3Tc1O4+l9U06n7x8Q/8PHz1DrrALt8tlr0CrkbJMHTop9Sk5sLa1g8L+ARJdnShKClY3tunN69t5iGLYTlCtakjFY7gxNABdN3B37BaqqoYT8pyX0in4ORbRkIA46YlDRbUTbBZ2Jb/Pw4qiKFnapcpPo9pdbrg8DjAOBsFgELJmsGs7eWkkc5bu/xBgAHkWC6UPADTOAAAAAElFTkSuQmCC');
310 - background-repeat: no-repeat;
311 - background-size: contain;
312 -}
313 -
314 -.ipfs-scss {
315 - background-image: url('data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAAyJpVFh0WE1MOmNvbS5hZG9iZS54bXAAAAAAADw/eHBhY2tldCBiZWdpbj0i77u/IiBpZD0iVzVNME1wQ2VoaUh6cmVTek5UY3prYzlkIj8+IDx4OnhtcG1ldGEgeG1sbnM6eD0iYWRvYmU6bnM6bWV0YS8iIHg6eG1wdGs9IkFkb2JlIFhNUCBDb3JlIDUuMy1jMDExIDY2LjE0NTY2MSwgMjAxMi8wMi8wNi0xNDo1NjoyNyAgICAgICAgIj4gPHJkZjpSREYgeG1sbnM6cmRmPSJodHRwOi8vd3d3LnczLm9yZy8xOTk5LzAyLzIyLXJkZi1zeW50YXgtbnMjIj4gPHJkZjpEZXNjcmlwdGlvbiByZGY6YWJvdXQ9IiIgeG1sbnM6eG1wPSJodHRwOi8vbnMuYWRvYmUuY29tL3hhcC8xLjAvIiB4bWxuczp4bXBNTT0iaHR0cDovL25zLmFkb2JlLmNvbS94YXAvMS4wL21tLyIgeG1sbnM6c3RSZWY9Imh0dHA6Ly9ucy5hZG9iZS5jb20veGFwLzEuMC9zVHlwZS9SZXNvdXJjZVJlZiMiIHhtcDpDcmVhdG9yVG9vbD0iQWRvYmUgUGhvdG9zaG9wIENTNiAoV2luZG93cykiIHhtcE1NOkluc3RhbmNlSUQ9InhtcC5paWQ6RkM4QjYyNDVGMTE4MTFFMTlBREZCNDNEM0ExMTk0MUIiIHhtcE1NOkRvY3VtZW50SUQ9InhtcC5kaWQ6RkM4QjYyNDZGMTE4MTFFMTlBREZCNDNEM0ExMTk0MUIiPiA8eG1wTU06RGVyaXZlZEZyb20gc3RSZWY6aW5zdGFuY2VJRD0ieG1wLmlpZDpGQzhCNjI0M0YxMTgxMUUxOUFERkI0M0QzQTExOTQxQiIgc3RSZWY6ZG9jdW1lbnRJRD0ieG1wLmRpZDpGQzhCNjI0NEYxMTgxMUUxOUFERkI0M0QzQTExOTQxQiIvPiA8L3JkZjpEZXNjcmlwdGlvbj4gPC9yZGY6UkRGPiA8L3g6eG1wbWV0YT4gPD94cGFja2V0IGVuZD0iciI/Pkf1yeMAAAJbSURBVHjahFNdTxNBFD0tLULpB91uodVWPmorUIxo0VSiNSExMYYHE33l0Ud/in+C+OSjYgjRGDBRCKJIUkIEWi0WKlja0ul22+5219lJ26gLeiezuXvn7rnnnrlrUFUVms3Mvd2bjIyezRVLBA0zGAzo6jhjm1te+7EU37rFO+w7JlMbtG+ePJ5mOaZmci/nsPl6ONBtw18WDQc9tZq0sp7YjTisXV/NFKRpRvzHpHodDqsF03djzuvDg6vHJWFAprF/Arxe/oins6+YryoqCiUBvNOO+7FrXMjnWc0WyIAOQP0N4Nn8IqqSzPx2swllsYqZl28gK8DDyRvcxKXQvB6gISYpiwgH+jEVi7YAfW4nEqk0PJwDofNejAX7Pae2sPhhHQoF63U5Gai2Bn1epoPWmmaKoug1UBoMrgwHabIVVCx2jdrKFwm67TZ2plldPQGg2cK5HheIUMbaZqKV9In6giDCy3MNYXECgKI2gICxoQAEsQItpNCHWKngMo01arTY/jFIzbutShJuXh1Fm9FImYiM7tTtKOtbO+toN9Nc+fQ5SGUOIVYl7HzPIH2YRZ0y2KZ+sVzBHn2v1mpMGx0DTaR3nzfwfGEJdybGkdo/wEigDyvxLzg4yiESvojZhfd49OAeLJ2degaSLIPOO6vwgiYaaRErTRREEdn8MeJbSVZ5M7nLdNExqFLaQwEfFfACQn1+HBWKSKb3MT4Sgstuh9vVDa+bQ4DORE6o6RlspzMk9TOPfr+fiLJCLFYr3TZSKNcI7+aJwWQmPM+TkqRg49tu65f/JcAAMwMas6WUKd8AAAAASUVORK5CYII=');
316 - background-repeat: no-repeat;
317 - background-size: contain;
318 -}
319 -
320 -.ipfs-sql {
321 - background-image: url('data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAAh5JREFUeNp8kctrE1EUxr+ZyXMkoa1NBROaSkpTBE23PhZ25cql2y5duvAPUdGFS1FxIRRBXZlFQ9GVdDENIhGJxkDsw2mneZnM83ruNZlOmNoDhzlzz3d/9zv3Sowx8Ch/qlYK2XM3cEJsbH0+qjV/rd6/u6aN18b7RMFT+9aosP/Ex+0ae/puw7j36PlKEMAzctKJ3aGFamMHjV0d+wcGitkMrpWWp6hVIciEk2MAOwbUWjosx0UiFoWqJpGMx5DNzODq5aIPoa82AWBg/lyKLMH1PMp/a9XvLXLzG1cuFlBaWpiKxaIPSLY6CaC93ggQjyiQZRkeQSzLRovGaPciWLt5faSWEBoh6KBvOhiaNga0+Y9pwaFxvu7rfp8F5pWDt+qNMp2IijHGwddWCvN+33/CoAOP5nVdT9SdoQ1JkggiQ6Yvr7V60+9z7akA2gfH9cRF8hO5F5Ve4lQAF9uuK+qFsylkzsQxrcaQm04hdWkR83Mzfp9rQ3fAFzu9Ph6+WMfjl6/pGBdb2jbKmx8QlRjWy5vkyhUZBPgOeGNHN9AbDLGUz6He2hVj3Ll9C8/evsdgaMK0HV8bcmDTU0UUBYXcedR+NLGnH0I3jvDk1Rsy46FP4C/1BtrdntCGHNiOAzWZgEKQ5Qt5lIqLojbaXSQTcRy2OwT4SZqk0IYAOgkVWUE+lxX/zb0DpFNpkTzmZmfFtzewhHYcfwUYAMZmVaZQlLFHAAAAAElFTkSuQmCC');
322 - background-repeat: no-repeat;
323 - background-size: contain;
324 -}
325 -
326 -.ipfs-tga {
327 - background-image: url('data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAAnxJREFUeNp0U89PE0EU/ra725K22ILRGipb22pMG6JcSEQTbUIwnozxpBcvepeEP0KPogcT/wlNT17kIKbEmChFUYKGVtL0R2gLtNCl3Z1Z3+zSAlonmezOe/O+973vvZEsy4JYnqdPMu6RkSQYQ29JEkB+PZcrslrtPhQl23VZc8/tr9I1yMHg0EA8HrBM04lVFAhoY38fSSDQVN3pfKV8G7KcxZHl6v1xblqU3eLc3p2VFZjr6+gQgwsnhzGTuq6Nhs6kYZqXjwL0GFhEl3U60OfnwWs1GGtrUKNRsKkpeIIBpKIRtI1J7cX7hXRhc/MOhXw5DkCZGG2zXAajzFIoBMvng1ypIKOqmP30GW3OIEcimovzlxRy5RgAFwDEAIODkCcmIMdiQLsNdWwMZdJlg8pzEUt1aBhKq3XinxKYqF9yQbqRIqsMy+0Gyy47bKgUWXSLtDENE5wdtuqQATm50F1VnPbRGeEw8HXZbiV8fsDvI9ldju9vADAyihLEbrWAZhOoVp3z6iqBUiB1A4nEfwCEsbkL/M4TgE5n5jDx+oTEzp1d8m9tC8H6MaAB0imzx0NU/WKUYE+loEyawDBo2ui6TGfT6ANAxrvx87gYCGCxXEKVJvCWFsG3eh1vN/J4OD6Od4UC8o0G3TX7TGLHwI9iEQmvF9X6Fh7F4/iYy+GcLOMSlfEgGsP0qdNOmX0BiGKpVkV1bw/1nW2b/gCpf1PTcI+Y7eg6ps+G4bG4PR99SjAVo9HE4q+fKNE0vl5awuSohjeijbRefVjAtUgEQRK7Yhi9OKn7nKWZxxlSPWl3QwgnaIrW8QMhD542vUbx/W49m7sq4v4IMABOqi3Ej7bAEAAAAABJRU5ErkJggg==');
328 - background-repeat: no-repeat;
329 - background-size: contain;
330 -}
331 -
332 -.ipfs-tgz {
333 - background-image: url('data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAAnhJREFUeNpsU1trE0EYPbMzSTfdtInFtkkpiaXVWou2FRUEn/so6JugL/oH/Af+B1988if40jcFERQURNBSQdDWlLQN2lsue8neZsZvc7FoOrDszM75znfOmVmmtUYyvry++36yfOeS1qqzDtvH2P76ApPlW3Drb2sHex/uccHWAdbZX30kO2+B3siN3zhTnHuQ66+95i423jzFzOVljBdKOZNHazvVT7e5wF+SZBj9iZJ+3J11mbW2kR8T4LwFli5i4fqTUvnczTUp9RLtDhKgJx0q4dEwWAxrREKICHEsoYYXMXvlcWmquLgmY71yCkG/c0AkARgLMZpnMDMpGNzEYe0dGp6HwvmHpbHC1Wf9MnFCkHQOyYEPzSJwQ2B65Tm5NZG3Fshim6wbMNJn4bpHowMKtIqo2COgR2IcAptwjvcgo6i77igjEmVDqbY8xQJ1VwRULhiBI6+G9Zf3cbTziuzIDkmHSNqECTFgQScEcYuc2NA8TcdYwXD+GkK/TYVN+u72WrIudiAD8o6oAR2RRCmQMjis3CIy1iSpPySCXhFTXeyAgh4BR+JVw8pauLi0Cp4yCX9A90FQhnSBYtnF/k+Q+HYam9itfIZB3QvT8zj8XSW5EhNTs9ivbSLwPUzPLNPJBIMEKnaQYg6aB9+RGR5F5VsNgnNKXMI1NdJGG5WfHzFVLJ7k8c8xUngpVodlDSGbFYj8Y4yMpOG09lHf3yIFPzA3fwHZTAQVtU4JUTeFDrdgDdlI8wAz5Qy2KxswReI7QODZcOr0ZH3q2hIDBI7zq16tuk3FNPxAI4wN+pkoccYoE4YJU5EdUtM4Qst26v26PwIMAKj3P/2YUKgYAAAAAElFTkSuQmCC');
334 - background-repeat: no-repeat;
335 - background-size: contain;
336 -}
337 -
338 -.ipfs-tiff {
339 - background-image: url('data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAAmRJREFUeNp0UktPE1EU/qYzHWstlrYJNcWUElyUJsaNGh9B0g1Lo0v9Ey78EbrVxBhXuHShm25YGBJRQpAYBDEWpaEPEhksdVpbyjzveO4MfZDCTWbauefc736PIziOA77OPH2yJCcSGdg2uksQAKofFou/7VrtASRpvVNynj13f6XOhjg8HAlMTIQdy/LO+v3uYUPTkAHCTb+cK+0pdyGK6+hbvu4/xiyHbncYAwfR19ZgbG/DoO9LsSgeTd9JXoxfyMG2rvQDdBlwIZauQ5ufh12twioU4E+nYU1NIRCNIDs+Bt28mXzx8VNuZ796j9q/DgAwomwqClilAmF0FE4wCInAlkjO4y+r0JgNX2os6XPYS2q/cQyAcQatFjA0BPH6NYipccAwIGUy2CVJFZInkKlyJAqx3T4/IMGmJkeWIWSz5KgI5pdhb3yDXS5DSCYh8rTID8s0wexeVD0GtMd85KkkefFxUfE47M1NokbJkByEQl6tL+ouAI+MUwbFhnYbaJKc/Sqg0x4H4eDRGDA56fUOABA9/GsCpaIHwr8FOhQ823O5RfW66tUGADhNy3RNRDjcN41HLxdQ8J6jYTsOQLfOJBK4f+s2/uoathoNGKT1MtFeVHZxdWTEZfEq/wMKl3rCJOIzTV6ADs2R5ulYDDNkYjp0DhrF+zCVgkw31+v1UxjQZkNV0SADd2o1MIuc9gmY+/kLxb0/UFoHePd9A1qzeUoKpilx9xcLWzgg+u/zeVfuQqkM9bCN1ysrWKXxdtPgvScwUAm58XZ52W16QyPtifRUzi588GbEi1ztHPsvwAC4uC9qhnsZvwAAAABJRU5ErkJggg==');
340 - background-repeat: no-repeat;
341 - background-size: contain;
342 -}
343 -
344 -.ipfs-txt {
345 - background-image: url('data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAAeJJREFUeNp8UrtOG1EQPfsyXiyzBguIJSyChZBBEFCKpKHLo6egpErNn8CHgH8gkZIiTSIXLhJAWCgkoMgRMSiRBSK29z4y9+I1d/HCrFb3MTPnnjkzlpQSynY+fP70fGF2gQuByCz6lfdd9Uurfvrrjes6762eb3tzQ69uFJwPsqOPC+MBEmxxphi4tlU5OGmsOzaBWLc+O9oIIVhScidkyGZ8vH62nHtSKlaI4cse6TjAfSaFBBcco0EWqyvzubmpyQrj/FXk75cQaSEMeMXU8xykPA/Hjd/6/LRcyjEpt2i7HAe4A2TeLZWKUOJaVLxj27j813EHGKCXaAJExu/4BOdiAED08riQD2riOrexyRoYc3CvsAbLGAAjZga7vgZG23WMCdBvoxKJc36TRBlMiaa2JByjNqqD8qkYc1pjDK7abey+/YhrWlfKswhpiCR96aEU9o5+QE3g2ovVWDm2Sc22bBQm8vrVpbkS9r+doPr1EOWZaQ0yFoxg2PcREosEAI4uvZhJpzFMP+cSXRbq+043RManez+tNWKMI6GN0g0Z04HFR+NoNC/0yx717efZOSbzY3AcR4Op2AGA5p/W31r9e0vNgSrh9OwCrpeCkqvZuqTybnpRqx/r2CjvvwADAJC/7lzAzQmwAAAAAElFTkSuQmCC');
346 - background-repeat: no-repeat;
347 - background-size: contain;
348 -}
349 -
350 -.ipfs-wav {
351 - background-image: url('data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAApFJREFUeNpsU1tPE0EYPXtpKbX0wqUQKVQMFdIXQBNCQBs06KP+B8ODGh+Mf4b/4IsGE54kxhcMBrkp7YOQgBRvSKG73fvsrt8Otoask0xmd+b7zpxzvm8E3/cRjPkniyulW0NFy2JoDkEAguOlpXJ9p3L8MBqVl4O9YHxae8pXuRlcGO7KPLhfTDVUqwUgigJMy4Whm6lEXHjxYf3XnByRN0QB/2KaH7btMlUxoRJAcyqKhdOaht7+DJ49n+2cvTnwynXcsb+kLwJ4rgfmMDDGWqvneXCZS9ND7mov5h9ND85M9y86Dpto5rUkuJ4Py3YDJpy6QGJPayqB+Njf+43XL220t0cwOZkfrNXsBUqZugDA6CbLdAiAwaek1ZU9LmP8Rh6S78GsGxjOp9FdzKJaVZIhBgGASzK21w/wbrnCk8euX+EMAjaaZuPHdwUdHVFYluuGPGCORwwYjg5rqOwccRk+3Ux0IEvntmsNG4ZmUayL/wAwKHUNfZfTKN0ZRaw9Cof8qJ/pMAyHy5KkAMTksSEJtnMenM7EMVMawbejMzJRh67bXEYiIXEAVTW50SEAhzqwfqrBcXx4VOhYm4RsNgHbsJFOyZTsQ1MN+hcohoUlkFiMT+TQFpMwXOjGpXgE+XwGk1N5pFJtKNCequgYGupCRBbCDOp0KBJc4VoP3dyBONW8uydBgBHUThqQKCk3mEZ/LoUG+RBioJO7VarAwEAntjYPiUUW9Hh4b2R7k9j98hN37xWx8fGAt3eIAdVMLn+uUv+b2KReSCZjZJiB9bV9jIz2ofr1BKvvd7G9dRC80lae0HzOt+cWVnrSKDrMJykifwNBpCgE/UAllEXufmDu8Zlffvvm8XSQ90eAAQA0pF7c08o4PAAAAABJRU5ErkJggg==');
352 - background-repeat: no-repeat;
353 - background-size: contain;
354 -}
355 -
356 -.ipfs-xls {
357 - background-image: url('data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAAmxJREFUeNpsU0trFEEQ/mamZ3Y2+0zIC2MmITEkUYgERFQErx5E8KTi1b/h79A/4SW3nCNeYggBYZVEMU/y3N3Z7M7OTD/G6lk2ruw20zRdU/XV91VVG0mSQK/3n1a/jky6d6Xs3G8WXS+Pw5N6LXjLLGuna/78oZKerGsYKtrDE16uJGL1L9gEOOcYd2dL1fNwrbL//aXN7J1efPMmkUqEFAk0A0VZNbFEaQCBscIkXj975y3NLq9xye8PBkAniHOFph+j2eC4rsdoB4LsFubGl/Hq8RtvYWpxTQi52o1jvWiGYaRZL0/auDgOkC/Z8BYL2Pqxidp1FZkhoDxpeaXA/Ujuj/4HoOxKKjiOiek7RUShRNQWaNYFQuMafrYCxiw4ozZKfqbYJ0EvRdl1DQyyTs8XCNTA6UELMwvDyLpZWIZNNlNLlQOK2LMJRJ+5AkuZ1S7CFFzJzk56GnUjQWlYkqCoBWFbonEVYcLLA4dNnB624GQsDBWIgfZJEgxkoChzSFWvn4VpQemDm2VwXQsXJwF1h6c+gxlQ5jgSiEUEt0wdIe7tMES+nEG2aCLiJMOIIWIr9e0DEELAMUrwRuchVAyTKimUwO75Jm6VF3Bv7imOaj+xd7UFKVS/BPJF1b/E4tgTrE49J60O5kceoNqowiuuYKa8ghHXA48U9MT2AQgyRvTThE30bQiaSGa4yLMJNFo+Dq/2cHt4CYlwyFf2S6BHwwrMw/avDbR5C1k7h1YQ4KH3Amf+AcZyEbZPv9CItzQD1l9EbtYOjv74v/d3O9RMPTDrsEwGIWN8q2yk7XNYRs9JrRv3V4ABADSGR6eQ0/NQAAAAAElFTkSuQmCC');
358 - background-repeat: no-repeat;
359 - background-size: contain;
360 -}
361 -
362 -.ipfs-xlsx {
363 - background-image: url('data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAAmlJREFUeNpsU8tqFEEUPVXdPY/ueWZIoiYZiSYKYhJc6EbduHOhgijo3t/wH1z6B0JAhOyMILhxo4kJGk1ASTAxwWF0Mpp5dHc9vFUzYwidaoqmq+8959xzbzGtNcx69PTS26ETmQtS9r4Hy/xv7MW7jV+th5yzVcaYPX/++It9u4NAv+CVR6tBUUTqMJsDcRzjZOZM8W9ZLKx+/XDb4e5/kH5In0lpIYWGUaC0YTZnBCAEKoVR3L36oDo7NbsglZwbqD6iQKOXFMcKUVfBkBAoQhlD5xxMDp/HrSv3q1JgYW3z0x0KXzkCYJaRZljru23aHWTzLiamAyytv0O9UYdf5PArqlppBfMUfu4oALErqZBKcUxMFRCHEp0DgW5Lo4N9NIN1dF0XXsVFOUyPJTzo+WBANDidjp8tgHGG3c0DnJ4uIRf4cOCBaW5KjY8xkZL72xpJ9QcFz5bVqHUJGHZL2YtNmKi06YCyiVFb4s/vEKMTAf1p4edOG6mMi1zR6wEpdUwX+vLDtkCzHoK7ptcM6ayLmGajvtex4PliyoIkFRjmUEASelB2rXQRSfjUCT9PlWpmW21iTGzCAyEkUixPRqXhe2V4zKczbdmybgkpJ0cGOuA6Y2MTCsKoi5HsNK7N3MN+uwYaWbxYfoLLkzdxcew6lrYWaZhm8PHHG3zffp1UwJSHz9vvkU8PodbcQYYYS5lxYkxTkGdVDQdV1Js1qPgYD6JIuIE7gsXVefIhIuM05k7dwMbeMmh87a18ufIMaVYyprrJLgje2Nr+1tzYXANnDnr3zRhHj37Vvy2wpXHtNAd5/wQYAD6WMuT2CwoVAAAAAElFTkSuQmCC');
364 - background-repeat: no-repeat;
365 - background-size: contain;
366 -}
367 -
368 -.ipfs-xml {
369 - background-image: url('data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAAilJREFUeNqMks1PE0EYxh+g3W2t1G0sEqyISynUFJsSOShNwCamiYZED3LgIkcuxoN/iCZePZiYGD2aGD+i0F5KMChxlVaakAK2ykcAt+WzdLu7zkxo3WZL4pu8mXfmeeY3885ug67roPFh5nvc62m9hjoR+5LMp7MrkYf370qVtco+VtCUFpbj+jGR+JbWn76OyQ8ePwsZATQb8R/hanZgINgj9IqeuBFCw1Kt9OMBnNWCs24XwkG/QKYUEiGjVAPQof/rq0783pShET3ULQo8xz0iS5FaANmrHQH2DoqY+DSLSz6RzecWlnD9ymU47LYjd4O5BXqDTG4FM3NpTEkpdJ5rw0AowLRMbhUfp58gTOaD/UHmNQPI6YmvKWRX1zESHUJ/oBs2nmPa+Mgw0ZIM3tZyGoJwygzQNB2jNyJIZX7iB0lpPoM70UGmPX8zCU+rG8NDVxHwdiC5mKsPUFUN/gvtLLf39sFzVqaN3YrC6TjBauqhXhNA1TQoqloV7Da+pjZq1FsXUCamF29j6LvYhf3iISamZ3Fv9DZevouhRzzPfOG+3hpA9U9UyioOlTJ7pFeTCQS6RGzIebyf+oz5pSzWtmSW1EO9phvQ00slBRt/8qR3DoWdXbiczUiTzd52D+tdLmyTB14mx1rMAKVcRpEATjrsuElee/HXGmnFRyBOGD30C/nEDjNgs7CDpsYmnHG3YPegBCvHs9oYfm8nG9dJa5X4K8AAQzQX4KSN3wcAAAAASUVORK5CYII=');
370 - background-repeat: no-repeat;
371 - background-size: contain;
372 -}
373 -
374 -.ipfs-yml {
375 - background-image: url('data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAAdxJREFUeNqMUl1rE0EUPbM7m5Y0Zptu21AwWwhYpfSDFh+kvvRd8N0Hf4I/xWdf/Q158F0QoQ+CVsFKaLSQpt/dpmvztTOzzky6cetOpWcZZvbO3MO5514SxzEU3r57/3GpWllM/tP4sL3TarROXuSo/SWJvX71Uu80Cfhlr/T4UdWFAVfdnmsTUtvdP35OUyQKVnJgXDBTcj9icAsTeLax7j/052qM81UjwW1QJXEhMF0qYnN90fdnvdogYmvJPU0/VBApD4hcDrWRcyikfB17srzgW7b9Rh1vEvxDlI4tVytaBSEEtmWh0xsUMwpwnWjqAlcxogiHd1wiQyCu87iI/+sJtf6+NXsgpd7FWCMB50KvkYMGMbLdZgLlfj+K9K4+FnFQ2x7WntIs50AbmiGwLILt+k+EvzvSNIHzdigdJ/AmXQRhiHv5POSwYmG+cqPVo0HqDxj8uTK2vn1Hfa+JmdIkvtZ/4fOPXU3WPDpFeNWVyUKryCiIGMN4zsH98gym3CIcOTwT+XHdXrdQQHAZotE8kBPpSqPNHtBOr48HUmLOcXRJT9dWNMGYJFby91pHOAvaykSaITg+bwefdhrteDRTMSwyrFCgI88E056Hy+4Ah2cXQZL3R4ABALUe7fqXWFN6AAAAAElFTkSuQmCC');
376 - background-repeat: no-repeat;
377 - background-size: contain;
378 -}
379 -
380 -.ipfs-zip {
381 - background-image: url('data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAAm9JREFUeNpsk0tv00AUhc+MY6dOmgeFJg1FoVVpUWlFC0s2IFF1jxBbhKj4BSxYdscPYcEmQmIDq0gsERIViy4TpD7VFzF1Ho5je2a4thOqNhlp5Mz4zudzzp0wpRTC8fPrk0/TC6+fDtYicLH97T1Kc2vQDcs+rH3eUAxVznn0fn1DRM8E+iOdv5ct3XmZG6yVlNj6solUbgVTt0q5FGtX6vXqC6VklTE+KAO/OODHSIQPRQpsXC+kkEz2ELA0ystv84tLzyucsbWByisAGf+QAS2CCDRRLMJMmxC+i8C4jdLCm/zM7OOKFGptcO6/BTpJ0yeQB0Y+mfKQuZZG0jQgeRbW8Xdomobs9LN8scc+UPHNy4Dwq8IljotIIQEm59/RoSyM1CKkXKZNBm7kIVgyM6wgAnSgRK9vqQfHPiMFDHqyFVsLR9Cm0o4YzoAASrSjCelQfRPb1Vc4qn0EY5L2W9GEaBLcxQgFHpGbkMIDJ69e+wjJ8VXqRgKid0r7ftQdxkRs9SqA2kgAm14SSIQh9uhuLGPMnKJs/5KquL1x0N0RCsizigoDaLqBdHoMiyvrlBsHVx1wphD4BCewoqxGKKDwAgtOy8JufYuk+5golGGaGZwc1sIGoDz3AOPZSVLaHgVwydoJDM1H4DbQODughB3YpOD44HfoHgnu4e7So0uAi0stHLJ3Aud8B9bpHu6vPoSu9TtDl6tUuoFiIYOgu0+158MKmOxomtyD3Qi/3MTR7i8K0EDG1GHO5DE3X4DvNahZlJOwEkOATvdPc2//hx3mXJ5lFJaF8K8bStd0YGfnOJbMGex21x6c+yfAAOlIPDJzr7cLAAAAAElFTkSuQmCC');
382 - background-repeat: no-repeat;
383 - background-size: contain;
384 -}
vendor/QmdDfkqDWheE4gsCXNrhixwTwSHnZMPT2cGLcNbiBNcMyU/dir-index-html/knownIcons.txt deleted
-61
@@ -1,61 +0,0 @@
1 -.aac
2 -.aiff
3 -.ai
4 -.avi
5 -.bmp
6 -.c
7 -.cpp
8 -.css
9 -.dat
10 -.dmg
11 -.doc
12 -.dotx
13 -.dwg
14 -.dxf
15 -.eps
16 -.exe
17 -.flv
18 -.gif
19 -.h
20 -.hpp
21 -.html
22 -.ics
23 -.iso
24 -.java
25 -.jpg
26 -.js
27 -.key
28 -.less
29 -.mid
30 -.mp3
31 -.mp4
32 -.mpg
33 -.odf
34 -.ods
35 -.odt
36 -.otp
37 -.ots
38 -.ott
39 -.pdf
40 -.php
41 -.png
42 -.ppt
43 -.psd
44 -.py
45 -.qt
46 -.rar
47 -.rb
48 -.rtf
49 -.sass
50 -.scss
51 -.sql
52 -.tga
53 -.tgz
54 -.tiff
55 -.txt
56 -.wav
57 -.xls
58 -.xlsx
59 -.xml
60 -.yml
61 -.zip
vendor/QmdDfkqDWheE4gsCXNrhixwTwSHnZMPT2cGLcNbiBNcMyU/dir-index-html/package.json deleted
-4
@@ -1,4 +0,0 @@
1 -{
2 - "name": "dir-index-html",
3 - "version": "1.0.0"
4 -}
vendor/dir-index-html-v1.0.0 deleted
-1
@@ -1 +0,0 @@
1 -QmdDfkqDWheE4gsCXNrhixwTwSHnZMPT2cGLcNbiBNcMyU/dir-index-html
\ No newline at end of file