diff --git a/.dockerignore b/.dockerignore index 6b8710a711f..ee0f144b497 100644 --- a/.dockerignore +++ b/.dockerignore @@ -1 +1,6 @@ -.git +.git/ +!.git/HEAD +!.git/refs/ +cmd/ipfs/ipfs +vendor/gx/ +test/ diff --git a/.travis.yml b/.travis.yml index caa7e46dbd7..84e04807ff6 100644 --- a/.travis.yml +++ b/.travis.yml @@ -13,6 +13,8 @@ env: - TEST_NO_FUSE=1 TEST_VERBOSE=1 TEST_SUITE=test_go_expensive - TEST_NO_FUSE=1 TEST_VERBOSE=1 TEST_SUITE=test_sharness_expensive +install: make install + script: - make $TEST_SUITE diff --git a/Dockerfile b/Dockerfile index a4773cd202c..b641c4b463d 100644 --- a/Dockerfile +++ b/Dockerfile @@ -1,34 +1,79 @@ FROM alpine:3.3 -MAINTAINER Brian Tiger Chow +MAINTAINER Lars Gierth + +# There is a copy of this Dockerfile in test/sharness, +# which is optimized for build time, instead of image size. +# +# Please keep these two Dockerfiles in sync. -ENV IPFS_PATH /data/ipfs -ENV GOPATH /go:/go/src/github.com/ipfs/go-ipfs/Godeps/_workspace -EXPOSE 4001 5001 8080 -# 4001 = Swarm, 5001 = API, 8080 = HTTP transport +# Ports for Swarm TCP, Swarm uTP, API, Gateway +EXPOSE 4001 +EXPOSE 4002/udp +EXPOSE 5001 +EXPOSE 8080 -ADD bin/container_daemon /usr/local/bin/start_ipfs -ADD bin/container_shacheck /usr/local/bin/shacheck +# Volume for mounting an IPFS fs-repo +# This is moved to the bottom for technical reasons. +#VOLUME $IPFS_PATH -ADD . /go/src/github.com/ipfs/go-ipfs -WORKDIR /go/src/github.com/ipfs/go-ipfs/cmd/ipfs +# IPFS API to use for fetching gx packages. +# This can be a gateway too, since its read-only API provides all gx needs. +# - e.g. /ip4/172.17.0.1/tcp/8080 if the Docker host +# has the IPFS gateway listening on the bridge interface +# provided by Docker's default networking. +# - if empty, the public gateway at ipfs.io is used. +ENV GX_IPFS "" +# The IPFS fs-repo within the container +ENV IPFS_PATH /data/ipfs +# Golang stuff +ENV GO_VERSION 1.5.3-r0 +ENV GOPATH /go +ENV PATH /go/bin:$PATH +ENV SRC_PATH /go/src/github.com/ipfs/go-ipfs -RUN adduser -D -h /data -u 1000 ipfs \ - && mkdir -p /data/ipfs && chown ipfs:ipfs /data/ipfs \ - && apk add --update bash ca-certificates git go \ - && go install -ldflags "-X github.com/ipfs/go-ipfs/repo/config.CurrentCommit=$(git rev-parse --short HEAD 2> /dev/null || echo unknown)" \ - && mv /go/bin/ipfs /usr/local/bin/ipfs \ - && chmod 755 /usr/local/bin/start_ipfs \ - && apk del --purge go git +# Get the go-ipfs sourcecode +COPY . $SRC_PATH -WORKDIR / -RUN rm -rf /go/src/github.com/ipfs/go-ipfs +RUN apk add --update musl go=$GO_VERSION git bash wget ca-certificates \ + # Setup user and fs-repo directory + && mkdir -p $IPFS_PATH \ + && adduser -D -h $IPFS_PATH -u 1000 ipfs \ + && chown ipfs:ipfs $IPFS_PATH && chmod 755 $IPFS_PATH \ + # Install gx + && go get -u github.com/whyrusleeping/gx \ + && go get -u github.com/whyrusleeping/gx-go \ + # Point gx to a specific IPFS API + && ([ -z "$GX_IPFS" ] || echo $GX_IPFS > $IPFS_PATH/api) \ + # Invoke gx + && cd $SRC_PATH \ + && gx --verbose install --global \ + # We get the current commit using this hack, + # so that we don't have to copy all of .git/ into the build context. + # This saves us quite a bit of image size. + && ref="$(cat .git/HEAD | cut -d' ' -f2)" \ + && commit="$(cat .git/$ref | head -c 7)" \ + && echo "ldflags=-X github.com/ipfs/go-ipfs/repo/config.CurrentCommit=$commit" \ + # Build and install IPFS and entrypoint script + && cd $SRC_PATH/cmd/ipfs \ + && go build -ldflags "-X github.com/ipfs/go-ipfs/repo/config.CurrentCommit=$commit" \ + && cp ipfs /usr/local/bin/ipfs \ + && cp $SRC_PATH/bin/container_daemon /usr/local/bin/start_ipfs \ + && chmod 755 /usr/local/bin/start_ipfs \ + # Remove all build-time dependencies + && apk del --purge musl go git && rm -rf $GOPATH && rm -vf $IPFS_PATH/api +# Call uid 1000 "ipfs" USER ipfs -VOLUME /data/ipfs -ENTRYPOINT ["/usr/local/bin/start_ipfs"] +# Expose the fs-repo as a volume. +# We're doing this down here (and not at the top), +# so that the overlay directory is owned by the ipfs user. +# start_ipfs initializes an ephemeral fs-repo if none is mounted, +# which is why uid=1000 needs write permissions there. +VOLUME $IPFS_PATH -# build: docker build -t go-ipfs . -# run: docker run -p 4001:4001 -p 5001:5001 go-ipfs:latest -# run: docker run -p 8080:8080 -p 4001:4001 -p 5001:5001 go-ipfs:latest +# This just makes sure that: +# 1. There's an fs-repo, and initializes one if there isn't. +# 2. The API and Gateway are accessible from outside the container. +ENTRYPOINT ["/usr/local/bin/start_ipfs"] diff --git a/Godeps/_workspace/src/bazil.org/fuse/fs/bench/bench_test.go b/Godeps/_workspace/src/bazil.org/fuse/fs/bench/bench_test.go index 6cab7dff09f..bf31a516488 100644 --- a/Godeps/_workspace/src/bazil.org/fuse/fs/bench/bench_test.go +++ b/Godeps/_workspace/src/bazil.org/fuse/fs/bench/bench_test.go @@ -10,7 +10,7 @@ import ( "github.com/ipfs/go-ipfs/Godeps/_workspace/src/bazil.org/fuse" "github.com/ipfs/go-ipfs/Godeps/_workspace/src/bazil.org/fuse/fs" "github.com/ipfs/go-ipfs/Godeps/_workspace/src/bazil.org/fuse/fs/fstestutil" - "github.com/ipfs/go-ipfs/Godeps/_workspace/src/golang.org/x/net/context" + "gx/ipfs/QmZy2y8t9zQH2a1b8q2ZSLKp17ATuJoCNxxyMFG5qFExpt/go-net/context" ) type benchConfig struct { diff --git a/Godeps/_workspace/src/bazil.org/fuse/fs/fstestutil/record/record.go b/Godeps/_workspace/src/bazil.org/fuse/fs/fstestutil/record/record.go index 7fbc24b0eb6..de160cd5fc3 100644 --- a/Godeps/_workspace/src/bazil.org/fuse/fs/fstestutil/record/record.go +++ b/Godeps/_workspace/src/bazil.org/fuse/fs/fstestutil/record/record.go @@ -6,7 +6,7 @@ import ( "github.com/ipfs/go-ipfs/Godeps/_workspace/src/bazil.org/fuse" "github.com/ipfs/go-ipfs/Godeps/_workspace/src/bazil.org/fuse/fs" - "github.com/ipfs/go-ipfs/Godeps/_workspace/src/golang.org/x/net/context" + "gx/ipfs/QmZy2y8t9zQH2a1b8q2ZSLKp17ATuJoCNxxyMFG5qFExpt/go-net/context" ) // Writes gathers data from FUSE Write calls. diff --git a/Godeps/_workspace/src/bazil.org/fuse/fs/fstestutil/record/wait.go b/Godeps/_workspace/src/bazil.org/fuse/fs/fstestutil/record/wait.go index e938637072e..b37f38beb7c 100644 --- a/Godeps/_workspace/src/bazil.org/fuse/fs/fstestutil/record/wait.go +++ b/Godeps/_workspace/src/bazil.org/fuse/fs/fstestutil/record/wait.go @@ -6,7 +6,7 @@ import ( "github.com/ipfs/go-ipfs/Godeps/_workspace/src/bazil.org/fuse" "github.com/ipfs/go-ipfs/Godeps/_workspace/src/bazil.org/fuse/fs" - "github.com/ipfs/go-ipfs/Godeps/_workspace/src/golang.org/x/net/context" + "gx/ipfs/QmZy2y8t9zQH2a1b8q2ZSLKp17ATuJoCNxxyMFG5qFExpt/go-net/context" ) type nothing struct{} diff --git a/Godeps/_workspace/src/bazil.org/fuse/fs/fstestutil/testfs.go b/Godeps/_workspace/src/bazil.org/fuse/fs/fstestutil/testfs.go index f86bdbe54fa..f8c9c65623c 100644 --- a/Godeps/_workspace/src/bazil.org/fuse/fs/fstestutil/testfs.go +++ b/Godeps/_workspace/src/bazil.org/fuse/fs/fstestutil/testfs.go @@ -5,7 +5,7 @@ import ( "github.com/ipfs/go-ipfs/Godeps/_workspace/src/bazil.org/fuse" "github.com/ipfs/go-ipfs/Godeps/_workspace/src/bazil.org/fuse/fs" - "github.com/ipfs/go-ipfs/Godeps/_workspace/src/golang.org/x/net/context" + "gx/ipfs/QmZy2y8t9zQH2a1b8q2ZSLKp17ATuJoCNxxyMFG5qFExpt/go-net/context" ) // SimpleFS is a trivial FS that just implements the Root method. diff --git a/Godeps/_workspace/src/bazil.org/fuse/fs/serve.go b/Godeps/_workspace/src/bazil.org/fuse/fs/serve.go index 3eab002ccf8..7987462977a 100644 --- a/Godeps/_workspace/src/bazil.org/fuse/fs/serve.go +++ b/Godeps/_workspace/src/bazil.org/fuse/fs/serve.go @@ -14,7 +14,7 @@ import ( "sync" "time" - "github.com/ipfs/go-ipfs/Godeps/_workspace/src/golang.org/x/net/context" + "gx/ipfs/QmZy2y8t9zQH2a1b8q2ZSLKp17ATuJoCNxxyMFG5qFExpt/go-net/context" ) import ( diff --git a/Godeps/_workspace/src/bazil.org/fuse/fs/serve_test.go b/Godeps/_workspace/src/bazil.org/fuse/fs/serve_test.go index b15f9069875..8d7ab69779b 100644 --- a/Godeps/_workspace/src/bazil.org/fuse/fs/serve_test.go +++ b/Godeps/_workspace/src/bazil.org/fuse/fs/serve_test.go @@ -21,7 +21,7 @@ import ( "github.com/ipfs/go-ipfs/Godeps/_workspace/src/bazil.org/fuse/fs/fstestutil/record" "github.com/ipfs/go-ipfs/Godeps/_workspace/src/bazil.org/fuse/fuseutil" "github.com/ipfs/go-ipfs/Godeps/_workspace/src/bazil.org/fuse/syscallx" - "github.com/ipfs/go-ipfs/Godeps/_workspace/src/golang.org/x/net/context" + "gx/ipfs/QmZy2y8t9zQH2a1b8q2ZSLKp17ATuJoCNxxyMFG5qFExpt/go-net/context" ) // TO TEST: diff --git a/Godeps/_workspace/src/bazil.org/fuse/fs/tree.go b/Godeps/_workspace/src/bazil.org/fuse/fs/tree.go index fc47ee321fc..b07c0c36a80 100644 --- a/Godeps/_workspace/src/bazil.org/fuse/fs/tree.go +++ b/Godeps/_workspace/src/bazil.org/fuse/fs/tree.go @@ -7,7 +7,7 @@ import ( pathpkg "path" "strings" - "github.com/ipfs/go-ipfs/Godeps/_workspace/src/golang.org/x/net/context" + "gx/ipfs/QmZy2y8t9zQH2a1b8q2ZSLKp17ATuJoCNxxyMFG5qFExpt/go-net/context" ) import ( diff --git a/Godeps/_workspace/src/bazil.org/fuse/hellofs/hello.go b/Godeps/_workspace/src/bazil.org/fuse/hellofs/hello.go index 45b644e4da7..443fb9e5681 100644 --- a/Godeps/_workspace/src/bazil.org/fuse/hellofs/hello.go +++ b/Godeps/_workspace/src/bazil.org/fuse/hellofs/hello.go @@ -10,7 +10,7 @@ import ( "github.com/ipfs/go-ipfs/Godeps/_workspace/src/bazil.org/fuse" "github.com/ipfs/go-ipfs/Godeps/_workspace/src/bazil.org/fuse/fs" _ "github.com/ipfs/go-ipfs/Godeps/_workspace/src/bazil.org/fuse/fs/fstestutil" - "github.com/ipfs/go-ipfs/Godeps/_workspace/src/golang.org/x/net/context" + "gx/ipfs/QmZy2y8t9zQH2a1b8q2ZSLKp17ATuJoCNxxyMFG5qFExpt/go-net/context" ) var Usage = func() { diff --git a/Godeps/_workspace/src/bazil.org/fuse/options_test.go b/Godeps/_workspace/src/bazil.org/fuse/options_test.go index a28dfa067e5..1e8a23206aa 100644 --- a/Godeps/_workspace/src/bazil.org/fuse/options_test.go +++ b/Godeps/_workspace/src/bazil.org/fuse/options_test.go @@ -9,7 +9,7 @@ import ( "github.com/ipfs/go-ipfs/Godeps/_workspace/src/bazil.org/fuse" "github.com/ipfs/go-ipfs/Godeps/_workspace/src/bazil.org/fuse/fs" "github.com/ipfs/go-ipfs/Godeps/_workspace/src/bazil.org/fuse/fs/fstestutil" - "github.com/ipfs/go-ipfs/Godeps/_workspace/src/golang.org/x/net/context" + "gx/ipfs/QmZy2y8t9zQH2a1b8q2ZSLKp17ATuJoCNxxyMFG5qFExpt/go-net/context" ) func init() { diff --git a/Godeps/_workspace/src/github.com/alecthomas/kingpin/app_test.go b/Godeps/_workspace/src/github.com/alecthomas/kingpin/app_test.go index a18894f8b82..025e4c491dc 100644 --- a/Godeps/_workspace/src/github.com/alecthomas/kingpin/app_test.go +++ b/Godeps/_workspace/src/github.com/alecthomas/kingpin/app_test.go @@ -3,7 +3,7 @@ package kingpin import ( "io/ioutil" - "github.com/stretchr/testify/assert" + "gx/ipfs/QmZwjfAKWe7vWZ8f48u7AGA1xYfzR1iCD9A2XSCYFRBWot/testify/assert" "testing" "time" diff --git a/Godeps/_workspace/src/github.com/alecthomas/kingpin/args_test.go b/Godeps/_workspace/src/github.com/alecthomas/kingpin/args_test.go index 01e2eb794d0..f3a3bf33d90 100644 --- a/Godeps/_workspace/src/github.com/alecthomas/kingpin/args_test.go +++ b/Godeps/_workspace/src/github.com/alecthomas/kingpin/args_test.go @@ -4,7 +4,7 @@ import ( "io/ioutil" "testing" - "github.com/stretchr/testify/assert" + "gx/ipfs/QmZwjfAKWe7vWZ8f48u7AGA1xYfzR1iCD9A2XSCYFRBWot/testify/assert" ) func TestArgRemainder(t *testing.T) { diff --git a/Godeps/_workspace/src/github.com/alecthomas/kingpin/cmd_test.go b/Godeps/_workspace/src/github.com/alecthomas/kingpin/cmd_test.go index 39215777689..5c2006441ed 100644 --- a/Godeps/_workspace/src/github.com/alecthomas/kingpin/cmd_test.go +++ b/Godeps/_workspace/src/github.com/alecthomas/kingpin/cmd_test.go @@ -3,7 +3,7 @@ package kingpin import ( "strings" - "github.com/stretchr/testify/assert" + "gx/ipfs/QmZwjfAKWe7vWZ8f48u7AGA1xYfzR1iCD9A2XSCYFRBWot/testify/assert" "testing" ) diff --git a/Godeps/_workspace/src/github.com/alecthomas/kingpin/flags_test.go b/Godeps/_workspace/src/github.com/alecthomas/kingpin/flags_test.go index 0316f75cb55..2c4b46babbc 100644 --- a/Godeps/_workspace/src/github.com/alecthomas/kingpin/flags_test.go +++ b/Godeps/_workspace/src/github.com/alecthomas/kingpin/flags_test.go @@ -4,7 +4,7 @@ import ( "io/ioutil" "os" - "github.com/stretchr/testify/assert" + "gx/ipfs/QmZwjfAKWe7vWZ8f48u7AGA1xYfzR1iCD9A2XSCYFRBWot/testify/assert" "testing" ) diff --git a/Godeps/_workspace/src/github.com/alecthomas/kingpin/parser_test.go b/Godeps/_workspace/src/github.com/alecthomas/kingpin/parser_test.go index f439e97ddaf..1e108d26a8f 100644 --- a/Godeps/_workspace/src/github.com/alecthomas/kingpin/parser_test.go +++ b/Godeps/_workspace/src/github.com/alecthomas/kingpin/parser_test.go @@ -5,7 +5,7 @@ import ( "os" "testing" - "github.com/stretchr/testify/assert" + "gx/ipfs/QmZwjfAKWe7vWZ8f48u7AGA1xYfzR1iCD9A2XSCYFRBWot/testify/assert" ) func TestParserExpandFromFile(t *testing.T) { diff --git a/Godeps/_workspace/src/github.com/alecthomas/kingpin/parsers_test.go b/Godeps/_workspace/src/github.com/alecthomas/kingpin/parsers_test.go index 81708c7c87c..c53eebaa0fb 100644 --- a/Godeps/_workspace/src/github.com/alecthomas/kingpin/parsers_test.go +++ b/Godeps/_workspace/src/github.com/alecthomas/kingpin/parsers_test.go @@ -6,7 +6,7 @@ import ( "net/url" "os" - "github.com/stretchr/testify/assert" + "gx/ipfs/QmZwjfAKWe7vWZ8f48u7AGA1xYfzR1iCD9A2XSCYFRBWot/testify/assert" "testing" ) diff --git a/Godeps/_workspace/src/github.com/alecthomas/kingpin/usage_test.go b/Godeps/_workspace/src/github.com/alecthomas/kingpin/usage_test.go index 2b818570518..6593924f10c 100644 --- a/Godeps/_workspace/src/github.com/alecthomas/kingpin/usage_test.go +++ b/Godeps/_workspace/src/github.com/alecthomas/kingpin/usage_test.go @@ -5,7 +5,7 @@ import ( "strings" "testing" - "github.com/stretchr/testify/assert" + "gx/ipfs/QmZwjfAKWe7vWZ8f48u7AGA1xYfzR1iCD9A2XSCYFRBWot/testify/assert" ) func TestFormatTwoColumns(t *testing.T) { diff --git a/Godeps/_workspace/src/github.com/alecthomas/kingpin/values_test.go b/Godeps/_workspace/src/github.com/alecthomas/kingpin/values_test.go index 8e32189a6bd..798d0062993 100644 --- a/Godeps/_workspace/src/github.com/alecthomas/kingpin/values_test.go +++ b/Godeps/_workspace/src/github.com/alecthomas/kingpin/values_test.go @@ -1,7 +1,7 @@ package kingpin import ( - "github.com/stretchr/testify/assert" + "gx/ipfs/QmZwjfAKWe7vWZ8f48u7AGA1xYfzR1iCD9A2XSCYFRBWot/testify/assert" "testing" ) diff --git a/Godeps/_workspace/src/github.com/alecthomas/units/bytes_test.go b/Godeps/_workspace/src/github.com/alecthomas/units/bytes_test.go index d4317aa58b2..e0c6374b8e5 100644 --- a/Godeps/_workspace/src/github.com/alecthomas/units/bytes_test.go +++ b/Godeps/_workspace/src/github.com/alecthomas/units/bytes_test.go @@ -3,7 +3,7 @@ package units import ( "testing" - "github.com/stretchr/testify/assert" + "gx/ipfs/QmZwjfAKWe7vWZ8f48u7AGA1xYfzR1iCD9A2XSCYFRBWot/testify/assert" ) func TestBase2BytesString(t *testing.T) { diff --git a/Godeps/_workspace/src/github.com/anacrolix/missinggo/addr_test.go b/Godeps/_workspace/src/github.com/anacrolix/missinggo/addr_test.go index 96ffee0e6db..473d5475e66 100644 --- a/Godeps/_workspace/src/github.com/anacrolix/missinggo/addr_test.go +++ b/Godeps/_workspace/src/github.com/anacrolix/missinggo/addr_test.go @@ -3,7 +3,7 @@ package missinggo import ( "testing" - "github.com/stretchr/testify/assert" + "gx/ipfs/QmZwjfAKWe7vWZ8f48u7AGA1xYfzR1iCD9A2XSCYFRBWot/testify/assert" ) func TestSplitHostPort(t *testing.T) { diff --git a/Godeps/_workspace/src/github.com/anacrolix/missinggo/filecache/cache_test.go b/Godeps/_workspace/src/github.com/anacrolix/missinggo/filecache/cache_test.go index 89ba6e4d503..9587fedfb2e 100644 --- a/Godeps/_workspace/src/github.com/anacrolix/missinggo/filecache/cache_test.go +++ b/Godeps/_workspace/src/github.com/anacrolix/missinggo/filecache/cache_test.go @@ -7,8 +7,8 @@ import ( "path/filepath" "testing" - "github.com/stretchr/testify/assert" - "github.com/stretchr/testify/require" + "gx/ipfs/QmZwjfAKWe7vWZ8f48u7AGA1xYfzR1iCD9A2XSCYFRBWot/testify/assert" + "gx/ipfs/QmZwjfAKWe7vWZ8f48u7AGA1xYfzR1iCD9A2XSCYFRBWot/testify/require" "github.com/ipfs/go-ipfs/Godeps/_workspace/src/github.com/anacrolix/missinggo" ) diff --git a/Godeps/_workspace/src/github.com/anacrolix/missinggo/filecache/lruitems.go b/Godeps/_workspace/src/github.com/anacrolix/missinggo/filecache/lruitems.go index 75f0f7bd4ef..bd4d2bf92ff 100644 --- a/Godeps/_workspace/src/github.com/anacrolix/missinggo/filecache/lruitems.go +++ b/Godeps/_workspace/src/github.com/anacrolix/missinggo/filecache/lruitems.go @@ -4,7 +4,7 @@ import ( "container/list" "io" - "github.com/cznic/b" + "gx/ipfs/QmVgtwPh2NNoZTSyYkr4Y3epaYACBKf26r8hV6EFA7xS6c/b" ) type Iterator interface { diff --git a/Godeps/_workspace/src/github.com/anacrolix/missinggo/httpcontentrange_test.go b/Godeps/_workspace/src/github.com/anacrolix/missinggo/httpcontentrange_test.go index e76ce6018f5..30505f1a7f5 100644 --- a/Godeps/_workspace/src/github.com/anacrolix/missinggo/httpcontentrange_test.go +++ b/Godeps/_workspace/src/github.com/anacrolix/missinggo/httpcontentrange_test.go @@ -3,7 +3,7 @@ package missinggo import ( "testing" - "github.com/stretchr/testify/assert" + "gx/ipfs/QmZwjfAKWe7vWZ8f48u7AGA1xYfzR1iCD9A2XSCYFRBWot/testify/assert" ) func TestParseHTTPContentRange(t *testing.T) { diff --git a/Godeps/_workspace/src/github.com/anacrolix/missinggo/itertools/groupby_test.go b/Godeps/_workspace/src/github.com/anacrolix/missinggo/itertools/groupby_test.go index c194e73029d..26143e14b32 100644 --- a/Godeps/_workspace/src/github.com/anacrolix/missinggo/itertools/groupby_test.go +++ b/Godeps/_workspace/src/github.com/anacrolix/missinggo/itertools/groupby_test.go @@ -3,7 +3,7 @@ package itertools import ( "testing" - "github.com/stretchr/testify/require" + "gx/ipfs/QmZwjfAKWe7vWZ8f48u7AGA1xYfzR1iCD9A2XSCYFRBWot/testify/require" ) func TestGroupByKey(t *testing.T) { diff --git a/Godeps/_workspace/src/github.com/anacrolix/missinggo/itertools/iterator_test.go b/Godeps/_workspace/src/github.com/anacrolix/missinggo/itertools/iterator_test.go index 61f0be8c6b6..8a1bc102dd8 100644 --- a/Godeps/_workspace/src/github.com/anacrolix/missinggo/itertools/iterator_test.go +++ b/Godeps/_workspace/src/github.com/anacrolix/missinggo/itertools/iterator_test.go @@ -3,7 +3,7 @@ package itertools import ( "testing" - "github.com/stretchr/testify/require" + "gx/ipfs/QmZwjfAKWe7vWZ8f48u7AGA1xYfzR1iCD9A2XSCYFRBWot/testify/require" ) func TestIterator(t *testing.T) { diff --git a/Godeps/_workspace/src/github.com/anacrolix/missinggo/perf/perf_test.go b/Godeps/_workspace/src/github.com/anacrolix/missinggo/perf/perf_test.go index aaa7f922adc..0258028ea3d 100644 --- a/Godeps/_workspace/src/github.com/anacrolix/missinggo/perf/perf_test.go +++ b/Godeps/_workspace/src/github.com/anacrolix/missinggo/perf/perf_test.go @@ -7,7 +7,7 @@ import ( "time" "github.com/ipfs/go-ipfs/Godeps/_workspace/src/github.com/bradfitz/iter" - "github.com/stretchr/testify/assert" + "gx/ipfs/QmZwjfAKWe7vWZ8f48u7AGA1xYfzR1iCD9A2XSCYFRBWot/testify/assert" ) func TestTimer(t *testing.T) { diff --git a/Godeps/_workspace/src/github.com/anacrolix/missinggo/pubsub/pubsub_test.go b/Godeps/_workspace/src/github.com/anacrolix/missinggo/pubsub/pubsub_test.go index 56c871ba2f7..87c99861760 100644 --- a/Godeps/_workspace/src/github.com/anacrolix/missinggo/pubsub/pubsub_test.go +++ b/Godeps/_workspace/src/github.com/anacrolix/missinggo/pubsub/pubsub_test.go @@ -5,8 +5,8 @@ import ( "testing" "github.com/ipfs/go-ipfs/Godeps/_workspace/src/github.com/bradfitz/iter" - "github.com/stretchr/testify/assert" - "github.com/stretchr/testify/require" + "gx/ipfs/QmZwjfAKWe7vWZ8f48u7AGA1xYfzR1iCD9A2XSCYFRBWot/testify/assert" + "gx/ipfs/QmZwjfAKWe7vWZ8f48u7AGA1xYfzR1iCD9A2XSCYFRBWot/testify/require" ) func TestDoubleClose(t *testing.T) { diff --git a/Godeps/_workspace/src/github.com/anacrolix/missinggo/wolf_test.go b/Godeps/_workspace/src/github.com/anacrolix/missinggo/wolf_test.go index 3ee59ca7903..f920c237fca 100644 --- a/Godeps/_workspace/src/github.com/anacrolix/missinggo/wolf_test.go +++ b/Godeps/_workspace/src/github.com/anacrolix/missinggo/wolf_test.go @@ -3,7 +3,7 @@ package missinggo import ( "testing" - "github.com/stretchr/testify/require" + "gx/ipfs/QmZwjfAKWe7vWZ8f48u7AGA1xYfzR1iCD9A2XSCYFRBWot/testify/require" ) func cryHeard() bool { diff --git a/Godeps/_workspace/src/github.com/anacrolix/utp/cmd/ucat/ucat.go b/Godeps/_workspace/src/github.com/anacrolix/utp/cmd/ucat/ucat.go index fc2e827c8f4..f5937e12f47 100644 --- a/Godeps/_workspace/src/github.com/anacrolix/utp/cmd/ucat/ucat.go +++ b/Godeps/_workspace/src/github.com/anacrolix/utp/cmd/ucat/ucat.go @@ -9,7 +9,7 @@ import ( "os" "os/signal" - "github.com/anacrolix/envpprof" + "gx/ipfs/QmazECKVXFsA3J6cHAqf8HeTDUB8zARjfo75nxE6o63AAp/envpprof" "github.com/ipfs/go-ipfs/Godeps/_workspace/src/github.com/anacrolix/utp" ) diff --git a/Godeps/_workspace/src/github.com/anacrolix/utp/utp_test.go b/Godeps/_workspace/src/github.com/anacrolix/utp/utp_test.go index a604f257c35..622457758a9 100644 --- a/Godeps/_workspace/src/github.com/anacrolix/utp/utp_test.go +++ b/Godeps/_workspace/src/github.com/anacrolix/utp/utp_test.go @@ -11,10 +11,10 @@ import ( "testing" "time" - _ "github.com/anacrolix/envpprof" "github.com/ipfs/go-ipfs/Godeps/_workspace/src/github.com/anacrolix/missinggo" "github.com/ipfs/go-ipfs/Godeps/_workspace/src/github.com/bradfitz/iter" - "github.com/stretchr/testify/require" + "gx/ipfs/QmZwjfAKWe7vWZ8f48u7AGA1xYfzR1iCD9A2XSCYFRBWot/testify/require" + _ "gx/ipfs/QmazECKVXFsA3J6cHAqf8HeTDUB8zARjfo75nxE6o63AAp/envpprof" ) func init() { diff --git a/Godeps/_workspace/src/github.com/docker/spdystream/ws/connection.go b/Godeps/_workspace/src/github.com/docker/spdystream/ws/connection.go index d0ea001b454..51a3e182b23 100644 --- a/Godeps/_workspace/src/github.com/docker/spdystream/ws/connection.go +++ b/Godeps/_workspace/src/github.com/docker/spdystream/ws/connection.go @@ -1,7 +1,7 @@ package ws import ( - "github.com/gorilla/websocket" + "gx/ipfs/QmUe1Ljrtwz5NSKqJRw5mgjthSSfW7g94hkGRqiQs5aJna/websocket" "io" "log" "time" diff --git a/Godeps/_workspace/src/github.com/docker/spdystream/ws/ws_test.go b/Godeps/_workspace/src/github.com/docker/spdystream/ws/ws_test.go index 58d2b991263..4c2425a234e 100644 --- a/Godeps/_workspace/src/github.com/docker/spdystream/ws/ws_test.go +++ b/Godeps/_workspace/src/github.com/docker/spdystream/ws/ws_test.go @@ -2,8 +2,8 @@ package ws import ( "bytes" - "github.com/gorilla/websocket" "github.com/ipfs/go-ipfs/Godeps/_workspace/src/github.com/docker/spdystream" + "gx/ipfs/QmUe1Ljrtwz5NSKqJRw5mgjthSSfW7g94hkGRqiQs5aJna/websocket" "io" "log" "net/http" diff --git a/Godeps/_workspace/src/github.com/gogo/protobuf/io/io_test.go b/Godeps/_workspace/src/github.com/gogo/protobuf/io/io_test.go index eabaa948989..08ed47c11f1 100644 --- a/Godeps/_workspace/src/github.com/gogo/protobuf/io/io_test.go +++ b/Godeps/_workspace/src/github.com/gogo/protobuf/io/io_test.go @@ -31,8 +31,8 @@ package io_test import ( "bytes" "encoding/binary" - "github.com/gogo/protobuf/test" "github.com/ipfs/go-ipfs/Godeps/_workspace/src/github.com/gogo/protobuf/io" + "gx/ipfs/QmZ4Qi3GaRbjcx28Sme5eMH7RQjGkt8wHxt2a65oLaeFEV/gogo-protobuf/test" goio "io" "math/rand" "testing" diff --git a/Godeps/_workspace/src/github.com/ipfs/go-datastore/flatfs/flatfs.go b/Godeps/_workspace/src/github.com/ipfs/go-datastore/flatfs/flatfs.go index f2fdf49bdd4..9eafb88cef2 100644 --- a/Godeps/_workspace/src/github.com/ipfs/go-datastore/flatfs/flatfs.go +++ b/Godeps/_workspace/src/github.com/ipfs/go-datastore/flatfs/flatfs.go @@ -17,7 +17,7 @@ import ( "github.com/ipfs/go-ipfs/Godeps/_workspace/src/github.com/ipfs/go-datastore/query" "github.com/ipfs/go-ipfs/Godeps/_workspace/src/github.com/jbenet/go-os-rename" - logging "github.com/ipfs/go-ipfs/vendor/QmQg1J6vikuXF9oDvm4wpdeAUvvkVEKW1EYDw9HhTMnP2b/go-log" + logging "gx/ipfs/Qmazh5oNUVsDZTs2g59rq8aYQqwpss8tcUWQzor5sCCEuH/go-log" ) var log = logging.Logger("flatfs") diff --git a/Godeps/_workspace/src/github.com/jbenet/go-context/frac/fracctx.go b/Godeps/_workspace/src/github.com/jbenet/go-context/frac/fracctx.go index 73e0f7730db..c92daa9c9c8 100644 --- a/Godeps/_workspace/src/github.com/jbenet/go-context/frac/fracctx.go +++ b/Godeps/_workspace/src/github.com/jbenet/go-context/frac/fracctx.go @@ -4,7 +4,7 @@ package ctxext import ( "time" - context "github.com/ipfs/go-ipfs/Godeps/_workspace/src/golang.org/x/net/context" + context "gx/ipfs/QmZy2y8t9zQH2a1b8q2ZSLKp17ATuJoCNxxyMFG5qFExpt/go-net/context" ) // WithDeadlineFraction returns a Context with a fraction of the diff --git a/Godeps/_workspace/src/github.com/jbenet/go-context/frac/fracctx_test.go b/Godeps/_workspace/src/github.com/jbenet/go-context/frac/fracctx_test.go index 0b5541a1525..975b7696d66 100644 --- a/Godeps/_workspace/src/github.com/jbenet/go-context/frac/fracctx_test.go +++ b/Godeps/_workspace/src/github.com/jbenet/go-context/frac/fracctx_test.go @@ -5,7 +5,7 @@ import ( "testing" "time" - context "github.com/ipfs/go-ipfs/Godeps/_workspace/src/golang.org/x/net/context" + context "gx/ipfs/QmZy2y8t9zQH2a1b8q2ZSLKp17ATuJoCNxxyMFG5qFExpt/go-net/context" ) // this test is on the context tool itself, not our stuff. it's for sanity on ours. diff --git a/Godeps/_workspace/src/github.com/jbenet/go-context/io/ctxio.go b/Godeps/_workspace/src/github.com/jbenet/go-context/io/ctxio.go index 86eae64db71..411eea892b7 100644 --- a/Godeps/_workspace/src/github.com/jbenet/go-context/io/ctxio.go +++ b/Godeps/_workspace/src/github.com/jbenet/go-context/io/ctxio.go @@ -13,7 +13,7 @@ package ctxio import ( "io" - context "github.com/ipfs/go-ipfs/Godeps/_workspace/src/golang.org/x/net/context" + context "gx/ipfs/QmZy2y8t9zQH2a1b8q2ZSLKp17ATuJoCNxxyMFG5qFExpt/go-net/context" ) type ioret struct { diff --git a/Godeps/_workspace/src/github.com/jbenet/go-context/io/ctxio_test.go b/Godeps/_workspace/src/github.com/jbenet/go-context/io/ctxio_test.go index 1c4acff3ffb..a9de8694c43 100644 --- a/Godeps/_workspace/src/github.com/jbenet/go-context/io/ctxio_test.go +++ b/Godeps/_workspace/src/github.com/jbenet/go-context/io/ctxio_test.go @@ -6,7 +6,7 @@ import ( "testing" "time" - context "github.com/ipfs/go-ipfs/Godeps/_workspace/src/golang.org/x/net/context" + context "gx/ipfs/QmZy2y8t9zQH2a1b8q2ZSLKp17ATuJoCNxxyMFG5qFExpt/go-net/context" ) func TestReader(t *testing.T) { diff --git a/Godeps/_workspace/src/github.com/jbenet/go-msgio/chan_test.go b/Godeps/_workspace/src/github.com/jbenet/go-msgio/chan_test.go index d2f2cb2f6d8..c54112eac0d 100644 --- a/Godeps/_workspace/src/github.com/jbenet/go-msgio/chan_test.go +++ b/Godeps/_workspace/src/github.com/jbenet/go-msgio/chan_test.go @@ -2,7 +2,7 @@ package msgio import ( "bytes" - randbuf "github.com/jbenet/go-randbuf" + randbuf "gx/ipfs/QmYNGtJHgaGZkpzq8yG6Wxqm6EQTKqgpBfnyyGBKbZeDUi/go-randbuf" "io" "math/rand" "testing" diff --git a/Godeps/_workspace/src/github.com/jbenet/go-msgio/msgio_test.go b/Godeps/_workspace/src/github.com/jbenet/go-msgio/msgio_test.go index da1590d6eea..51bbf10c04c 100644 --- a/Godeps/_workspace/src/github.com/jbenet/go-msgio/msgio_test.go +++ b/Godeps/_workspace/src/github.com/jbenet/go-msgio/msgio_test.go @@ -3,7 +3,7 @@ package msgio import ( "bytes" "fmt" - randbuf "github.com/jbenet/go-randbuf" + randbuf "gx/ipfs/QmYNGtJHgaGZkpzq8yG6Wxqm6EQTKqgpBfnyyGBKbZeDUi/go-randbuf" "io" "math/rand" "sync" diff --git a/Godeps/_workspace/src/github.com/jbenet/go-multiaddr-net/convert.go b/Godeps/_workspace/src/github.com/jbenet/go-multiaddr-net/convert.go index d129bd4afe6..13b9fed4feb 100644 --- a/Godeps/_workspace/src/github.com/jbenet/go-multiaddr-net/convert.go +++ b/Godeps/_workspace/src/github.com/jbenet/go-multiaddr-net/convert.go @@ -5,8 +5,8 @@ import ( "net" "strings" - ma "github.com/ipfs/go-ipfs/Godeps/_workspace/src/github.com/jbenet/go-multiaddr" - utp "github.com/ipfs/go-ipfs/Godeps/_workspace/src/github.com/jbenet/go-multiaddr-net/utp" + ma "gx/ipfs/QmR3JkmZBKYXgNMNsNZawm914455Qof3PEopwuVSeXG7aV/go-multiaddr" + utp "gx/ipfs/QmYtzQmUwPFGxjCXctJ8e6GXS8sYfoXy2pdeMbS5SFWqRi/go-multiaddr-net/utp" ) var errIncorrectNetAddr = fmt.Errorf("incorrect network addr conversion") diff --git a/Godeps/_workspace/src/github.com/jbenet/go-multiaddr-net/convert_test.go b/Godeps/_workspace/src/github.com/jbenet/go-multiaddr-net/convert_test.go index 3a4c171a67b..e80a0ac1182 100644 --- a/Godeps/_workspace/src/github.com/jbenet/go-multiaddr-net/convert_test.go +++ b/Godeps/_workspace/src/github.com/jbenet/go-multiaddr-net/convert_test.go @@ -4,8 +4,8 @@ import ( "net" "testing" - ma "github.com/ipfs/go-ipfs/Godeps/_workspace/src/github.com/jbenet/go-multiaddr" - mautp "github.com/ipfs/go-ipfs/Godeps/_workspace/src/github.com/jbenet/go-multiaddr-net/utp" + ma "gx/ipfs/QmR3JkmZBKYXgNMNsNZawm914455Qof3PEopwuVSeXG7aV/go-multiaddr" + mautp "gx/ipfs/QmYtzQmUwPFGxjCXctJ8e6GXS8sYfoXy2pdeMbS5SFWqRi/go-multiaddr-net/utp" ) type GenFunc func() (ma.Multiaddr, error) diff --git a/Godeps/_workspace/src/github.com/jbenet/go-multiaddr-net/ip.go b/Godeps/_workspace/src/github.com/jbenet/go-multiaddr-net/ip.go index 297c6954221..d535a8a2f96 100644 --- a/Godeps/_workspace/src/github.com/jbenet/go-multiaddr-net/ip.go +++ b/Godeps/_workspace/src/github.com/jbenet/go-multiaddr-net/ip.go @@ -3,7 +3,7 @@ package manet import ( "bytes" - ma "github.com/ipfs/go-ipfs/Godeps/_workspace/src/github.com/jbenet/go-multiaddr" + ma "gx/ipfs/QmR3JkmZBKYXgNMNsNZawm914455Qof3PEopwuVSeXG7aV/go-multiaddr" ) // Loopback Addresses diff --git a/Godeps/_workspace/src/github.com/jbenet/go-multiaddr-net/multiaddr/multiaddr.go b/Godeps/_workspace/src/github.com/jbenet/go-multiaddr-net/multiaddr/multiaddr.go index 5c010ff613a..5a430e4ad00 100644 --- a/Godeps/_workspace/src/github.com/jbenet/go-multiaddr-net/multiaddr/multiaddr.go +++ b/Godeps/_workspace/src/github.com/jbenet/go-multiaddr-net/multiaddr/multiaddr.go @@ -6,8 +6,8 @@ import ( "fmt" "os" - ma "github.com/ipfs/go-ipfs/Godeps/_workspace/src/github.com/jbenet/go-multiaddr" - manet "github.com/ipfs/go-ipfs/Godeps/_workspace/src/github.com/jbenet/go-multiaddr-net" + ma "gx/ipfs/QmR3JkmZBKYXgNMNsNZawm914455Qof3PEopwuVSeXG7aV/go-multiaddr" + manet "gx/ipfs/QmYtzQmUwPFGxjCXctJ8e6GXS8sYfoXy2pdeMbS5SFWqRi/go-multiaddr-net" ) // flags diff --git a/Godeps/_workspace/src/github.com/jbenet/go-multiaddr-net/net.go b/Godeps/_workspace/src/github.com/jbenet/go-multiaddr-net/net.go index bc007a1492e..d31662ab4d9 100644 --- a/Godeps/_workspace/src/github.com/jbenet/go-multiaddr-net/net.go +++ b/Godeps/_workspace/src/github.com/jbenet/go-multiaddr-net/net.go @@ -4,8 +4,8 @@ import ( "fmt" "net" - ma "github.com/ipfs/go-ipfs/Godeps/_workspace/src/github.com/jbenet/go-multiaddr" - mautp "github.com/ipfs/go-ipfs/Godeps/_workspace/src/github.com/jbenet/go-multiaddr-net/utp" + ma "gx/ipfs/QmR3JkmZBKYXgNMNsNZawm914455Qof3PEopwuVSeXG7aV/go-multiaddr" + mautp "gx/ipfs/QmYtzQmUwPFGxjCXctJ8e6GXS8sYfoXy2pdeMbS5SFWqRi/go-multiaddr-net/utp" ) // Conn is the equivalent of a net.Conn object. It is the diff --git a/Godeps/_workspace/src/github.com/jbenet/go-multiaddr-net/net_test.go b/Godeps/_workspace/src/github.com/jbenet/go-multiaddr-net/net_test.go index 08498c269e2..c29bbc72c1a 100644 --- a/Godeps/_workspace/src/github.com/jbenet/go-multiaddr-net/net_test.go +++ b/Godeps/_workspace/src/github.com/jbenet/go-multiaddr-net/net_test.go @@ -7,7 +7,7 @@ import ( "sync" "testing" - ma "github.com/ipfs/go-ipfs/Godeps/_workspace/src/github.com/jbenet/go-multiaddr" + ma "gx/ipfs/QmR3JkmZBKYXgNMNsNZawm914455Qof3PEopwuVSeXG7aV/go-multiaddr" ) func newMultiaddr(t *testing.T, m string) ma.Multiaddr { diff --git a/Godeps/_workspace/src/github.com/jbenet/go-reuseport/test/main.go b/Godeps/_workspace/src/github.com/jbenet/go-reuseport/test/main.go index 40beead3abf..d5ec137260b 100644 --- a/Godeps/_workspace/src/github.com/jbenet/go-reuseport/test/main.go +++ b/Godeps/_workspace/src/github.com/jbenet/go-reuseport/test/main.go @@ -7,7 +7,7 @@ import ( "os" reuse "github.com/ipfs/go-ipfs/Godeps/_workspace/src/github.com/jbenet/go-reuseport" - resolve "github.com/jbenet/go-net-resolve-addr" + resolve "gx/ipfs/Qma73Sqt13DzHzveZ667BBfraM7MuMrPepUXjmv812JhRS/go-net-resolve-addr" ) func main() { diff --git a/Godeps/_workspace/src/github.com/jbenet/go-stream-muxer/muxado/muxado.go b/Godeps/_workspace/src/github.com/jbenet/go-stream-muxer/muxado/muxado.go index 74edbf48cc5..e1b6a3313c1 100644 --- a/Godeps/_workspace/src/github.com/jbenet/go-stream-muxer/muxado/muxado.go +++ b/Godeps/_workspace/src/github.com/jbenet/go-stream-muxer/muxado/muxado.go @@ -3,8 +3,8 @@ package peerstream_muxado import ( "net" - muxado "github.com/inconshreveable/muxado" smux "github.com/ipfs/go-ipfs/Godeps/_workspace/src/github.com/jbenet/go-stream-muxer" + muxado "gx/ipfs/QmaZ9WavcC9EKocNHof8onR8JHci2Qt8AuybkFaxJdr51Q/muxado" ) // stream implements smux.Stream using a ss.Stream diff --git a/Godeps/_workspace/src/github.com/jbenet/goprocess/context/context.go b/Godeps/_workspace/src/github.com/jbenet/goprocess/context/context.go index 2ac8535a4bd..55f1be8ef06 100644 --- a/Godeps/_workspace/src/github.com/jbenet/goprocess/context/context.go +++ b/Godeps/_workspace/src/github.com/jbenet/goprocess/context/context.go @@ -2,7 +2,7 @@ package goprocessctx import ( goprocess "github.com/ipfs/go-ipfs/Godeps/_workspace/src/github.com/jbenet/goprocess" - context "github.com/ipfs/go-ipfs/Godeps/_workspace/src/golang.org/x/net/context" + context "gx/ipfs/QmZy2y8t9zQH2a1b8q2ZSLKp17ATuJoCNxxyMFG5qFExpt/go-net/context" ) // WithContext constructs and returns a Process that respects diff --git a/Godeps/_workspace/src/github.com/jbenet/goprocess/context/derive.go b/Godeps/_workspace/src/github.com/jbenet/goprocess/context/derive.go index b0aecee528a..cdd31da2b54 100644 --- a/Godeps/_workspace/src/github.com/jbenet/goprocess/context/derive.go +++ b/Godeps/_workspace/src/github.com/jbenet/goprocess/context/derive.go @@ -5,7 +5,7 @@ import ( "time" goprocess "github.com/ipfs/go-ipfs/Godeps/_workspace/src/github.com/jbenet/goprocess" - "github.com/ipfs/go-ipfs/Godeps/_workspace/src/golang.org/x/net/context" + "gx/ipfs/QmZy2y8t9zQH2a1b8q2ZSLKp17ATuJoCNxxyMFG5qFExpt/go-net/context" ) const ( diff --git a/Godeps/_workspace/src/github.com/jbenet/goprocess/periodic/periodic_test.go b/Godeps/_workspace/src/github.com/jbenet/goprocess/periodic/periodic_test.go index 088d31fe8fa..a008fffa5a4 100644 --- a/Godeps/_workspace/src/github.com/jbenet/goprocess/periodic/periodic_test.go +++ b/Godeps/_workspace/src/github.com/jbenet/goprocess/periodic/periodic_test.go @@ -5,7 +5,7 @@ import ( "time" gp "github.com/ipfs/go-ipfs/Godeps/_workspace/src/github.com/jbenet/goprocess" - ci "github.com/jbenet/go-cienv" + ci "gx/ipfs/QmZcUXuzsUSvxNj9pmU112V8L5kGUFMTYCdFcAbQ3Zj5cp/go-cienv" ) var ( diff --git a/Godeps/_workspace/src/github.com/whyrusleeping/multiaddr-filter/mask.go b/Godeps/_workspace/src/github.com/whyrusleeping/multiaddr-filter/mask.go index dec913d76a6..739e4ed5561 100644 --- a/Godeps/_workspace/src/github.com/whyrusleeping/multiaddr-filter/mask.go +++ b/Godeps/_workspace/src/github.com/whyrusleeping/multiaddr-filter/mask.go @@ -6,7 +6,7 @@ import ( "net" "strings" - manet "github.com/ipfs/go-ipfs/Godeps/_workspace/src/github.com/jbenet/go-multiaddr-net" + manet "gx/ipfs/QmYtzQmUwPFGxjCXctJ8e6GXS8sYfoXy2pdeMbS5SFWqRi/go-multiaddr-net" ) var ErrInvalidFormat = errors.New("invalid multiaddr-filter format") diff --git a/Godeps/_workspace/src/golang.org/x/net/context/withtimeout_test.go b/Godeps/_workspace/src/golang.org/x/net/context/withtimeout_test.go index 4e7d48203e8..5ed70717375 100644 --- a/Godeps/_workspace/src/golang.org/x/net/context/withtimeout_test.go +++ b/Godeps/_workspace/src/golang.org/x/net/context/withtimeout_test.go @@ -8,7 +8,7 @@ import ( "fmt" "time" - "github.com/ipfs/go-ipfs/Godeps/_workspace/src/golang.org/x/net/context" + "gx/ipfs/QmZy2y8t9zQH2a1b8q2ZSLKp17ATuJoCNxxyMFG5qFExpt/go-net/context" ) func ExampleWithTimeout() { diff --git a/Godeps/_workspace/src/golang.org/x/net/ipv4/example_test.go b/Godeps/_workspace/src/golang.org/x/net/ipv4/example_test.go index 2239cd3cb63..4f6c7510fa7 100644 --- a/Godeps/_workspace/src/golang.org/x/net/ipv4/example_test.go +++ b/Godeps/_workspace/src/golang.org/x/net/ipv4/example_test.go @@ -14,7 +14,7 @@ import ( "github.com/ipfs/go-ipfs/Godeps/_workspace/src/golang.org/x/net/internal/iana" "github.com/ipfs/go-ipfs/Godeps/_workspace/src/golang.org/x/net/ipv4" - "golang.org/x/net/icmp" + "gx/ipfs/QmZy2y8t9zQH2a1b8q2ZSLKp17ATuJoCNxxyMFG5qFExpt/go-net/icmp" ) func ExampleConn_markingTCP() { diff --git a/Godeps/_workspace/src/golang.org/x/net/ipv4/icmp_test.go b/Godeps/_workspace/src/golang.org/x/net/ipv4/icmp_test.go index 808dc42f60b..19fd91f5405 100644 --- a/Godeps/_workspace/src/golang.org/x/net/ipv4/icmp_test.go +++ b/Godeps/_workspace/src/golang.org/x/net/ipv4/icmp_test.go @@ -11,7 +11,7 @@ import ( "testing" "github.com/ipfs/go-ipfs/Godeps/_workspace/src/golang.org/x/net/ipv4" - "golang.org/x/net/internal/nettest" + "gx/ipfs/QmZy2y8t9zQH2a1b8q2ZSLKp17ATuJoCNxxyMFG5qFExpt/go-net/internal/nettest" ) var icmpStringTests = []struct { diff --git a/Godeps/_workspace/src/golang.org/x/net/ipv4/multicast_test.go b/Godeps/_workspace/src/golang.org/x/net/ipv4/multicast_test.go index d640be358ac..4289abbc197 100644 --- a/Godeps/_workspace/src/golang.org/x/net/ipv4/multicast_test.go +++ b/Godeps/_workspace/src/golang.org/x/net/ipv4/multicast_test.go @@ -14,8 +14,8 @@ import ( "github.com/ipfs/go-ipfs/Godeps/_workspace/src/golang.org/x/net/internal/iana" "github.com/ipfs/go-ipfs/Godeps/_workspace/src/golang.org/x/net/ipv4" - "golang.org/x/net/icmp" - "golang.org/x/net/internal/nettest" + "gx/ipfs/QmZy2y8t9zQH2a1b8q2ZSLKp17ATuJoCNxxyMFG5qFExpt/go-net/icmp" + "gx/ipfs/QmZy2y8t9zQH2a1b8q2ZSLKp17ATuJoCNxxyMFG5qFExpt/go-net/internal/nettest" ) var packetConnReadWriteMulticastUDPTests = []struct { diff --git a/Godeps/_workspace/src/golang.org/x/net/ipv4/multicastlistener_test.go b/Godeps/_workspace/src/golang.org/x/net/ipv4/multicastlistener_test.go index e4ad5ec67a2..376f3457b76 100644 --- a/Godeps/_workspace/src/golang.org/x/net/ipv4/multicastlistener_test.go +++ b/Godeps/_workspace/src/golang.org/x/net/ipv4/multicastlistener_test.go @@ -10,7 +10,7 @@ import ( "testing" "github.com/ipfs/go-ipfs/Godeps/_workspace/src/golang.org/x/net/ipv4" - "golang.org/x/net/internal/nettest" + "gx/ipfs/QmZy2y8t9zQH2a1b8q2ZSLKp17ATuJoCNxxyMFG5qFExpt/go-net/internal/nettest" ) var udpMultipleGroupListenerTests = []net.Addr{ diff --git a/Godeps/_workspace/src/golang.org/x/net/ipv4/multicastsockopt_test.go b/Godeps/_workspace/src/golang.org/x/net/ipv4/multicastsockopt_test.go index 3de9edd662b..afcc251ef65 100644 --- a/Godeps/_workspace/src/golang.org/x/net/ipv4/multicastsockopt_test.go +++ b/Godeps/_workspace/src/golang.org/x/net/ipv4/multicastsockopt_test.go @@ -10,7 +10,7 @@ import ( "testing" "github.com/ipfs/go-ipfs/Godeps/_workspace/src/golang.org/x/net/ipv4" - "golang.org/x/net/internal/nettest" + "gx/ipfs/QmZy2y8t9zQH2a1b8q2ZSLKp17ATuJoCNxxyMFG5qFExpt/go-net/internal/nettest" ) var packetConnMulticastSocketOptionTests = []struct { diff --git a/Godeps/_workspace/src/golang.org/x/net/ipv4/readwrite_test.go b/Godeps/_workspace/src/golang.org/x/net/ipv4/readwrite_test.go index dcc38fab895..4c934cfbeb6 100644 --- a/Godeps/_workspace/src/golang.org/x/net/ipv4/readwrite_test.go +++ b/Godeps/_workspace/src/golang.org/x/net/ipv4/readwrite_test.go @@ -12,7 +12,7 @@ import ( "testing" "github.com/ipfs/go-ipfs/Godeps/_workspace/src/golang.org/x/net/ipv4" - "golang.org/x/net/internal/nettest" + "gx/ipfs/QmZy2y8t9zQH2a1b8q2ZSLKp17ATuJoCNxxyMFG5qFExpt/go-net/internal/nettest" ) func benchmarkUDPListener() (net.PacketConn, net.Addr, error) { diff --git a/Godeps/_workspace/src/golang.org/x/net/ipv4/unicast_test.go b/Godeps/_workspace/src/golang.org/x/net/ipv4/unicast_test.go index 22176f9ef70..c920f2f623f 100644 --- a/Godeps/_workspace/src/golang.org/x/net/ipv4/unicast_test.go +++ b/Godeps/_workspace/src/golang.org/x/net/ipv4/unicast_test.go @@ -14,8 +14,8 @@ import ( "github.com/ipfs/go-ipfs/Godeps/_workspace/src/golang.org/x/net/internal/iana" "github.com/ipfs/go-ipfs/Godeps/_workspace/src/golang.org/x/net/ipv4" - "golang.org/x/net/icmp" - "golang.org/x/net/internal/nettest" + "gx/ipfs/QmZy2y8t9zQH2a1b8q2ZSLKp17ATuJoCNxxyMFG5qFExpt/go-net/icmp" + "gx/ipfs/QmZy2y8t9zQH2a1b8q2ZSLKp17ATuJoCNxxyMFG5qFExpt/go-net/internal/nettest" ) func TestPacketConnReadWriteUnicastUDP(t *testing.T) { diff --git a/Godeps/_workspace/src/golang.org/x/net/ipv4/unicastsockopt_test.go b/Godeps/_workspace/src/golang.org/x/net/ipv4/unicastsockopt_test.go index 186de4623ce..e60e8adb5c3 100644 --- a/Godeps/_workspace/src/golang.org/x/net/ipv4/unicastsockopt_test.go +++ b/Godeps/_workspace/src/golang.org/x/net/ipv4/unicastsockopt_test.go @@ -11,7 +11,7 @@ import ( "github.com/ipfs/go-ipfs/Godeps/_workspace/src/golang.org/x/net/internal/iana" "github.com/ipfs/go-ipfs/Godeps/_workspace/src/golang.org/x/net/ipv4" - "golang.org/x/net/internal/nettest" + "gx/ipfs/QmZy2y8t9zQH2a1b8q2ZSLKp17ATuJoCNxxyMFG5qFExpt/go-net/internal/nettest" ) func TestConnUnicastSocketOptions(t *testing.T) { diff --git a/Godeps/_workspace/src/golang.org/x/net/ipv6/example_test.go b/Godeps/_workspace/src/golang.org/x/net/ipv6/example_test.go index f697393c956..e47766dc751 100644 --- a/Godeps/_workspace/src/golang.org/x/net/ipv6/example_test.go +++ b/Godeps/_workspace/src/golang.org/x/net/ipv6/example_test.go @@ -13,7 +13,7 @@ import ( "github.com/ipfs/go-ipfs/Godeps/_workspace/src/golang.org/x/net/internal/iana" "github.com/ipfs/go-ipfs/Godeps/_workspace/src/golang.org/x/net/ipv6" - "golang.org/x/net/icmp" + "gx/ipfs/QmZy2y8t9zQH2a1b8q2ZSLKp17ATuJoCNxxyMFG5qFExpt/go-net/icmp" ) func ExampleConn_markingTCP() { diff --git a/Godeps/_workspace/src/golang.org/x/net/ipv6/icmp_test.go b/Godeps/_workspace/src/golang.org/x/net/ipv6/icmp_test.go index 17e05ea127b..ab4b5aedbb0 100644 --- a/Godeps/_workspace/src/golang.org/x/net/ipv6/icmp_test.go +++ b/Godeps/_workspace/src/golang.org/x/net/ipv6/icmp_test.go @@ -11,7 +11,7 @@ import ( "testing" "github.com/ipfs/go-ipfs/Godeps/_workspace/src/golang.org/x/net/ipv6" - "golang.org/x/net/internal/nettest" + "gx/ipfs/QmZy2y8t9zQH2a1b8q2ZSLKp17ATuJoCNxxyMFG5qFExpt/go-net/internal/nettest" ) var icmpStringTests = []struct { diff --git a/Godeps/_workspace/src/golang.org/x/net/ipv6/multicast_test.go b/Godeps/_workspace/src/golang.org/x/net/ipv6/multicast_test.go index 7d64f0fc7b1..7e7e1454e05 100644 --- a/Godeps/_workspace/src/golang.org/x/net/ipv6/multicast_test.go +++ b/Godeps/_workspace/src/golang.org/x/net/ipv6/multicast_test.go @@ -14,8 +14,8 @@ import ( "github.com/ipfs/go-ipfs/Godeps/_workspace/src/golang.org/x/net/internal/iana" "github.com/ipfs/go-ipfs/Godeps/_workspace/src/golang.org/x/net/ipv6" - "golang.org/x/net/icmp" - "golang.org/x/net/internal/nettest" + "gx/ipfs/QmZy2y8t9zQH2a1b8q2ZSLKp17ATuJoCNxxyMFG5qFExpt/go-net/icmp" + "gx/ipfs/QmZy2y8t9zQH2a1b8q2ZSLKp17ATuJoCNxxyMFG5qFExpt/go-net/internal/nettest" ) var packetConnReadWriteMulticastUDPTests = []struct { diff --git a/Godeps/_workspace/src/golang.org/x/net/ipv6/multicastlistener_test.go b/Godeps/_workspace/src/golang.org/x/net/ipv6/multicastlistener_test.go index 1ce9b99fb7c..5c884cf7656 100644 --- a/Godeps/_workspace/src/golang.org/x/net/ipv6/multicastlistener_test.go +++ b/Godeps/_workspace/src/golang.org/x/net/ipv6/multicastlistener_test.go @@ -11,7 +11,7 @@ import ( "testing" "github.com/ipfs/go-ipfs/Godeps/_workspace/src/golang.org/x/net/ipv6" - "golang.org/x/net/internal/nettest" + "gx/ipfs/QmZy2y8t9zQH2a1b8q2ZSLKp17ATuJoCNxxyMFG5qFExpt/go-net/internal/nettest" ) var udpMultipleGroupListenerTests = []net.Addr{ diff --git a/Godeps/_workspace/src/golang.org/x/net/ipv6/multicastsockopt_test.go b/Godeps/_workspace/src/golang.org/x/net/ipv6/multicastsockopt_test.go index 65b547c0244..7bdfba4b504 100644 --- a/Godeps/_workspace/src/golang.org/x/net/ipv6/multicastsockopt_test.go +++ b/Godeps/_workspace/src/golang.org/x/net/ipv6/multicastsockopt_test.go @@ -10,7 +10,7 @@ import ( "testing" "github.com/ipfs/go-ipfs/Godeps/_workspace/src/golang.org/x/net/ipv6" - "golang.org/x/net/internal/nettest" + "gx/ipfs/QmZy2y8t9zQH2a1b8q2ZSLKp17ATuJoCNxxyMFG5qFExpt/go-net/internal/nettest" ) var packetConnMulticastSocketOptionTests = []struct { diff --git a/Godeps/_workspace/src/golang.org/x/net/ipv6/readwrite_test.go b/Godeps/_workspace/src/golang.org/x/net/ipv6/readwrite_test.go index 82786bd783d..c5d1494eb84 100644 --- a/Godeps/_workspace/src/golang.org/x/net/ipv6/readwrite_test.go +++ b/Godeps/_workspace/src/golang.org/x/net/ipv6/readwrite_test.go @@ -13,7 +13,7 @@ import ( "github.com/ipfs/go-ipfs/Godeps/_workspace/src/golang.org/x/net/internal/iana" "github.com/ipfs/go-ipfs/Godeps/_workspace/src/golang.org/x/net/ipv6" - "golang.org/x/net/internal/nettest" + "gx/ipfs/QmZy2y8t9zQH2a1b8q2ZSLKp17ATuJoCNxxyMFG5qFExpt/go-net/internal/nettest" ) func benchmarkUDPListener() (net.PacketConn, net.Addr, error) { diff --git a/Godeps/_workspace/src/golang.org/x/net/ipv6/sockopt_test.go b/Godeps/_workspace/src/golang.org/x/net/ipv6/sockopt_test.go index c9bf073bd6a..f33e512c0be 100644 --- a/Godeps/_workspace/src/golang.org/x/net/ipv6/sockopt_test.go +++ b/Godeps/_workspace/src/golang.org/x/net/ipv6/sockopt_test.go @@ -12,7 +12,7 @@ import ( "github.com/ipfs/go-ipfs/Godeps/_workspace/src/golang.org/x/net/internal/iana" "github.com/ipfs/go-ipfs/Godeps/_workspace/src/golang.org/x/net/ipv6" - "golang.org/x/net/internal/nettest" + "gx/ipfs/QmZy2y8t9zQH2a1b8q2ZSLKp17ATuJoCNxxyMFG5qFExpt/go-net/internal/nettest" ) var supportsIPv6 bool = nettest.SupportsIPv6() diff --git a/Godeps/_workspace/src/golang.org/x/net/ipv6/unicast_test.go b/Godeps/_workspace/src/golang.org/x/net/ipv6/unicast_test.go index 2a7aa524174..9f741af656b 100644 --- a/Godeps/_workspace/src/golang.org/x/net/ipv6/unicast_test.go +++ b/Godeps/_workspace/src/golang.org/x/net/ipv6/unicast_test.go @@ -14,8 +14,8 @@ import ( "github.com/ipfs/go-ipfs/Godeps/_workspace/src/golang.org/x/net/internal/iana" "github.com/ipfs/go-ipfs/Godeps/_workspace/src/golang.org/x/net/ipv6" - "golang.org/x/net/icmp" - "golang.org/x/net/internal/nettest" + "gx/ipfs/QmZy2y8t9zQH2a1b8q2ZSLKp17ATuJoCNxxyMFG5qFExpt/go-net/icmp" + "gx/ipfs/QmZy2y8t9zQH2a1b8q2ZSLKp17ATuJoCNxxyMFG5qFExpt/go-net/internal/nettest" ) func TestPacketConnReadWriteUnicastUDP(t *testing.T) { diff --git a/Godeps/_workspace/src/golang.org/x/net/ipv6/unicastsockopt_test.go b/Godeps/_workspace/src/golang.org/x/net/ipv6/unicastsockopt_test.go index a3a87e55304..fd915e41fe3 100644 --- a/Godeps/_workspace/src/golang.org/x/net/ipv6/unicastsockopt_test.go +++ b/Godeps/_workspace/src/golang.org/x/net/ipv6/unicastsockopt_test.go @@ -11,7 +11,7 @@ import ( "github.com/ipfs/go-ipfs/Godeps/_workspace/src/golang.org/x/net/internal/iana" "github.com/ipfs/go-ipfs/Godeps/_workspace/src/golang.org/x/net/ipv6" - "golang.org/x/net/internal/nettest" + "gx/ipfs/QmZy2y8t9zQH2a1b8q2ZSLKp17ATuJoCNxxyMFG5qFExpt/go-net/internal/nettest" ) func TestConnUnicastSocketOptions(t *testing.T) { diff --git a/Makefile b/Makefile index 656dc0f9ea4..228051a3f1f 100644 --- a/Makefile +++ b/Makefile @@ -14,19 +14,26 @@ all: help godep: go get github.com/tools/godep +gx: + go get -u github.com/whyrusleeping/gx + go get -u github.com/whyrusleeping/gx-go + +deps: gx + gx --verbose install --global + # saves/vendors third-party dependencies to Godeps/_workspace # -r flag rewrites import paths to use the vendored path # ./... performs operation on all packages in tree vendor: godep godep save -r ./... -install: +install: build cd cmd/ipfs && go install -ldflags=$(ldflags) -build: +build: deps cd cmd/ipfs && go build -i -ldflags=$(ldflags) -nofuse: +nofuse: deps cd cmd/ipfs && go install -tags nofuse -ldflags=$(ldflags) clean: diff --git a/README.md b/README.md index 86bc587246b..6dc56281cbe 100644 --- a/README.md +++ b/README.md @@ -1,16 +1,36 @@ -# ipfs implementation in go. +# IPFS implementation in Go [![GoDoc](https://godoc.org/github.com/ipfs/go-ipfs?status.svg)](https://godoc.org/github.com/ipfs/go-ipfs) [![Build Status](https://travis-ci.org/ipfs/go-ipfs.svg?branch=master)](https://travis-ci.org/ipfs/go-ipfs) -Ipfs is a global, versioned, peer-to-peer filesystem. It combines good ideas from +IPFS is a global, versioned, peer-to-peer filesystem. It combines good ideas from Git, BitTorrent, Kademlia, SFS, and the Web. It is like a single bittorrent swarm, exchanging git objects. IPFS provides an interface as simple as the HTTP web, but with permanence built in. You can also mount the world at /ipfs. -For more info see: https://github.com/ipfs/ipfs +For more info see: https://github.com/ipfs/ipfs. Please put all issues regarding IPFS _design_ in the [ipfs repo issues](https://github.com/ipfs/ipfs/issues). -Please put all issues regarding go IPFS _implementation_ in [this repo](https://github.com/ipfs/go-ipfs/issues). +Please put all issues regarding Go IPFS _implementation_ in [this repo](https://github.com/ipfs/go-ipfs/issues). + +## Table of Contents + +- [Security Issues](#security-issues) +- [Install](#install) + - [Install prebuilt packages](#install-prebuilt-packages) + - [Build from Source](#build-from-source) + - [Prerequisite: Install Go](#prerequisite-install-go) + - [Download + Compile IPFS](#download--compile-ipfs) + - [Development Dependencies](#development-dependencies) +- [Updating](#updating) +- [Usage](#usage) +- [Getting Started](#getting-started) + - [Some things to try](#some-things-to-try) + - [Docker usage](#docker-usage) + - [Docker usage with VirtualBox/boot2docker (OSX and Windows)](#docker-usage-with-virtualboxboot2docker-osx-and-windows) +- [Troubleshooting](#troubleshooting) +- [Contributing](#contributing) +- [Todo](#todo) +- [License](#license) ## Security Issues @@ -22,9 +42,9 @@ If the issue is a protocol weakness that cannot be immediately exploited or some ## Install -The canonical download instructions for IPFS are over at: http://ipfs.io/docs/install/ +The canonical download instructions for IPFS are over at: http://ipfs.io/docs/install/. It is **highly suggested** you follow those instructions if you are not interested in working on IPFS development. -## Install prebuilt packages +### Install prebuilt packages We use [gobuilder.me](https://gobuilder.me), a great service that automatically builds a release on every commit. @@ -34,31 +54,33 @@ You can see the latest builds for your platform at these links: - [`master` - development, stable](https://gobuilder.me/github.com/ipfs/go-ipfs/cmd/ipfs?branch=master) From there: -- click "Download" on the build for your platform -- open/extract the archive -- move `ipfs` to your path (`install.sh` can do it for you) +- Click "Download" on the build for your platform. +- Open/extract the archive. +- Move `ipfs` to your path (`install.sh` can do it for you), +### Build from Source -## Build from Source +#### Prerequisite: Install Go -### Prerequisite: Install Go - -First, you'll need go. If you don't have it: [Download Go 1.5.2+](https://golang.org/dl/). +First, you'll need Go. If you don't have it: [Download Go 1.5.2+](https://golang.org/dl/). You'll need to add Go's bin directories to your `$PATH` environment variable e.g., by adding these lines to your `/etc/profile` (for a system-wide installation) or `$HOME/.profile`: + ``` export PATH=$PATH:/usr/local/go/bin export PATH=$PATH:$GOPATH/bin ``` -(If you run into trouble, see the [Go install instructions](https://golang.org/doc/install)) +(If you run into trouble, see the [Go install instructions](https://golang.org/doc/install)). -### Download + Compile IPFS +#### Download + Compile IPFS -Then simply: +Then: ``` -go get -u github.com/ipfs/go-ipfs/cmd/ipfs +$ go get -d github.com/ipfs/go-ipfs +$ cd $GOPATH/src/github.com/ipfs/go-ipfs +$ make install ``` NOTES: @@ -69,17 +91,21 @@ all dependencies. Compilation from source is recommended. * If you are interested in development, please install the development dependencies as well. -* *WARNING: older versions of OSX FUSE (for Mac OS X) can cause kernel panics when mounting!* +* *WARNING: Older versions of OSX FUSE (for Mac OS X) can cause kernel panics when mounting!* We strongly recommend you use the [latest version of OSX FUSE](http://osxfuse.github.io/). (See https://github.com/ipfs/go-ipfs/issues/177) -* For more details on setting up FUSE (so that you can mount the filesystem), see the docs folder +* For more details on setting up FUSE (so that you can mount the filesystem), see the docs folder. * Shell command completion is available in `misc/completion/ipfs-completion.bash`. Read [docs/command-completion.md](docs/command-completion.md) to learn how to install it. * See the [init examples](https://github.com/ipfs/examples/tree/master/examples/init) for how to connect IPFS to systemd or whatever init system your distro uses. -### Updating -ipfs has an updating tool that can be accessed through `ipfs update`. The tool is -not installed alongside ipfs in order to keep that logic independent of the main -codebase. To install ipfs update, either [download it here](https://gobuilder.me/github.com/ipfs/ipfs-update) +### Development Dependencies + +If you make changes to the protocol buffers, you will need to install the [protoc compiler](https://github.com/google/protobuf). + +## Updating +IPFS has an updating tool that can be accessed through `ipfs update`. The tool is +not installed alongside IPFS in order to keep that logic independent of the main +codebase. To install `ipfs update`, either [download it here](https://gobuilder.me/github.com/ipfs/ipfs-update) or install it from source with `go get -u github.com/ipfs/ipfs-update`. ## Usage @@ -94,7 +120,7 @@ USAGE: BASIC COMMANDS init Initialize ipfs local configuration - add Add a file to ipfs + add Add an object to ipfs cat Show ipfs object data get Download ipfs objects ls List links from an object @@ -141,7 +167,7 @@ USAGE: See also: http://ipfs.io/docs/getting-started/ -To start using ipfs, you must first initialize ipfs's config files on your +To start using IPFS, you must first initialize IPFS's config files on your system, this is done with `ipfs init`. See `ipfs init --help` for information on the optional arguments it takes. After initialization is complete, you can use `ipfs mount`, `ipfs add` and any of the other commands to explore! @@ -159,15 +185,15 @@ Basic proof of 'ipfs working' locally: ### Docker usage -An ipfs docker image is hosted at [hub.docker.com/r/jbenet/go-ipfs](https://hub.docker.com/r/jbenet/go-ipfs/). +An IPFS docker image is hosted at [hub.docker.com/r/jbenet/go-ipfs](https://hub.docker.com/r/jbenet/go-ipfs/). To make files visible inside the container you need to mount a host directory with the `-v` option to docker. Choose a directory that you want to use to -import/export files from ipfs. You should also choose a directory to store -ipfs files that will persist when you restart the container. +import/export files from IPFS. You should also choose a directory to store +IPFS files that will persist when you restart the container. export ipfs_staging= export ipfs_data= - + Make sure docker can access these folders: sudo chmod -R 777 /absolute/path/to/somewhere/ @@ -186,7 +212,7 @@ Wait for ipfs to start. ipfs is running when you see: Gateway (readonly) server listening on /ip4/0.0.0.0/tcp/8080 -(you can now stop watching the log) +You can now stop watching the log. Run ipfs commands: @@ -196,7 +222,6 @@ For example: connect to peers docker exec ipfs_host ipfs swarm peers - Add files: cp -r $ipfs_staging @@ -209,16 +234,15 @@ Stop the running container: #### Docker usage with VirtualBox/boot2docker (OSX and Windows) Since docker is running in the boot2docker VM, you need to forward -relevant ports from the VM to your host for ipfs act normally. This is +relevant ports from the VM to your host for IPFS to act normally. This is accomplished with the following command: boot2docker ssh -L 5001:localhost:5001 -L 4001:localhost:4001 -L 8080:localhost:8080 -fN - ### Troubleshooting -If you have previously installed ipfs before and you are running into +If you have previously installed IPFS before and you are running into problems getting a newer version to work, try deleting (or backing up somewhere -else) your ipfs config directory (~/.ipfs by default) and rerunning `ipfs init`. +else) your IPFS config directory (~/.ipfs by default) and rerunning `ipfs init`. This will reinitialize the config file to its defaults and clear out the local datastore of any bad entries. @@ -226,18 +250,13 @@ For any other problems, check the [issues list](https://github.com/ipfs/go-ipfs/ and if you dont see your problem there, either come talk to us on irc (freenode #ipfs) or file an issue of your own! - ## Contributing Please see [Contribute.md](contribute.md)! ## Todo -An IPFS alpha version has been released in February 2015. Things left to be done are all marked as [Issues](https://github.com/ipfs/go-ipfs/issues) - -## Development Dependencies - -If you make changes to the protocol buffers, you will need to install the [protoc compiler](https://github.com/google/protobuf). +An IPFS alpha version has been released in February 2015. Things left to be done are all marked as [issues](https://github.com/ipfs/go-ipfs/issues). ## License diff --git a/assets/assets_test.go b/assets/assets_test.go index cb67ccc27a9..18d69f362cb 100644 --- a/assets/assets_test.go +++ b/assets/assets_test.go @@ -13,6 +13,10 @@ func TestEmbeddedDocs(t *testing.T) { } func TestDirIndex(t *testing.T) { + t.Skip("skipping for now, code being tested is currently unused") + // TODO: import assets during init. + // this will require figuring out how to set the right paths up for + // referencing the code from its gx path testNFiles(initDirIndex, 2, t, "assets") } diff --git a/bin/container_daemon b/bin/container_daemon index 4b85fc9ec11..82fa2640029 100644 --- a/bin/container_daemon +++ b/bin/container_daemon @@ -1,17 +1,18 @@ -#!/bin/bash +#!/bin/sh + +user=$(whoami) +repo="$IPFS_PATH" # Test whether the mounted directory is writable for us -if ( touch /data/ipfs/write_test 2>/dev/null ); then - rm /data/ipfs/write_test -else - echo "ERR: /data/ipfs is not writable for user 'ipfs' (UID 1000)" +if [ ! -w "$repo" 2>/dev/null ]; then + echo "error: $repo is not writable for user $user (uid=$(id -u $user))" exit 1 fi -echo "Running $(ipfs version)..." +ipfs version -if [ -e /data/ipfs/config ]; then - echo "Found ipfs repository. Not initializing." +if [ -e "$repo/config" ]; then + echo "Found IPFS fs-repo at $repo" else ipfs init ipfs config Addresses.API /ip4/0.0.0.0/tcp/5001 diff --git a/bin/container_shacheck b/bin/container_shacheck deleted file mode 100644 index fc53ec6d13f..00000000000 --- a/bin/container_shacheck +++ /dev/null @@ -1,10 +0,0 @@ -#!/bin/bash -xe - -VERSION=$1 -FILENAME=$2 - -ONLINE_SHA=$( curl "https://gobuilder.me/api/v1/github.com/ipfs/go-ipfs/cmd/ipfs/signed-hashes/${VERSION}" 2>/dev/null | grep -A 4 ${FILENAME} | grep sha1 | awk '{ print $3 }' ) - -echo "Checking SHA1: ${ONLINE_SHA} == $(sha1sum ${FILENAME} | awk '{print $1}')" - -echo "${ONLINE_SHA} ${FILENAME}" | sha1sum -cw diff --git a/blocks/blockstore/blockstore.go b/blocks/blockstore/blockstore.go index 342bbc72db9..8221ec4a5de 100644 --- a/blocks/blockstore/blockstore.go +++ b/blocks/blockstore/blockstore.go @@ -11,10 +11,10 @@ import ( dsns "github.com/ipfs/go-ipfs/Godeps/_workspace/src/github.com/ipfs/go-datastore/namespace" dsq "github.com/ipfs/go-ipfs/Godeps/_workspace/src/github.com/ipfs/go-datastore/query" mh "github.com/ipfs/go-ipfs/Godeps/_workspace/src/github.com/jbenet/go-multihash" - context "github.com/ipfs/go-ipfs/Godeps/_workspace/src/golang.org/x/net/context" blocks "github.com/ipfs/go-ipfs/blocks" key "github.com/ipfs/go-ipfs/blocks/key" - logging "github.com/ipfs/go-ipfs/vendor/QmQg1J6vikuXF9oDvm4wpdeAUvvkVEKW1EYDw9HhTMnP2b/go-log" + context "gx/ipfs/QmZy2y8t9zQH2a1b8q2ZSLKp17ATuJoCNxxyMFG5qFExpt/go-net/context" + logging "gx/ipfs/Qmazh5oNUVsDZTs2g59rq8aYQqwpss8tcUWQzor5sCCEuH/go-log" ) var log = logging.Logger("blockstore") diff --git a/blocks/blockstore/blockstore_test.go b/blocks/blockstore/blockstore_test.go index 9c535b9d8eb..685745f0080 100644 --- a/blocks/blockstore/blockstore_test.go +++ b/blocks/blockstore/blockstore_test.go @@ -8,7 +8,7 @@ import ( ds "github.com/ipfs/go-ipfs/Godeps/_workspace/src/github.com/ipfs/go-datastore" dsq "github.com/ipfs/go-ipfs/Godeps/_workspace/src/github.com/ipfs/go-datastore/query" ds_sync "github.com/ipfs/go-ipfs/Godeps/_workspace/src/github.com/ipfs/go-datastore/sync" - context "github.com/ipfs/go-ipfs/Godeps/_workspace/src/golang.org/x/net/context" + context "gx/ipfs/QmZy2y8t9zQH2a1b8q2ZSLKp17ATuJoCNxxyMFG5qFExpt/go-net/context" blocks "github.com/ipfs/go-ipfs/blocks" key "github.com/ipfs/go-ipfs/blocks/key" diff --git a/blocks/blockstore/write_cache.go b/blocks/blockstore/write_cache.go index 73a7813f5ae..90109e8a2bd 100644 --- a/blocks/blockstore/write_cache.go +++ b/blocks/blockstore/write_cache.go @@ -2,9 +2,9 @@ package blockstore import ( "github.com/ipfs/go-ipfs/Godeps/_workspace/src/github.com/hashicorp/golang-lru" - context "github.com/ipfs/go-ipfs/Godeps/_workspace/src/golang.org/x/net/context" "github.com/ipfs/go-ipfs/blocks" key "github.com/ipfs/go-ipfs/blocks/key" + context "gx/ipfs/QmZy2y8t9zQH2a1b8q2ZSLKp17ATuJoCNxxyMFG5qFExpt/go-net/context" ) // WriteCached returns a blockstore that caches up to |size| unique writes (bs.Put). diff --git a/blocks/set/set.go b/blocks/set/set.go index 16d3772c79b..ccecff83bf8 100644 --- a/blocks/set/set.go +++ b/blocks/set/set.go @@ -4,7 +4,7 @@ package set import ( "github.com/ipfs/go-ipfs/blocks/bloom" key "github.com/ipfs/go-ipfs/blocks/key" - logging "github.com/ipfs/go-ipfs/vendor/QmQg1J6vikuXF9oDvm4wpdeAUvvkVEKW1EYDw9HhTMnP2b/go-log" + logging "gx/ipfs/Qmazh5oNUVsDZTs2g59rq8aYQqwpss8tcUWQzor5sCCEuH/go-log" ) var log = logging.Logger("blockset") diff --git a/blockservice/blockservice.go b/blockservice/blockservice.go index 9c5cc00e52a..21af30dfbe3 100644 --- a/blockservice/blockservice.go +++ b/blockservice/blockservice.go @@ -6,12 +6,12 @@ package blockservice import ( "errors" - context "github.com/ipfs/go-ipfs/Godeps/_workspace/src/golang.org/x/net/context" blocks "github.com/ipfs/go-ipfs/blocks" "github.com/ipfs/go-ipfs/blocks/blockstore" key "github.com/ipfs/go-ipfs/blocks/key" exchange "github.com/ipfs/go-ipfs/exchange" - logging "github.com/ipfs/go-ipfs/vendor/QmQg1J6vikuXF9oDvm4wpdeAUvvkVEKW1EYDw9HhTMnP2b/go-log" + context "gx/ipfs/QmZy2y8t9zQH2a1b8q2ZSLKp17ATuJoCNxxyMFG5qFExpt/go-net/context" + logging "gx/ipfs/Qmazh5oNUVsDZTs2g59rq8aYQqwpss8tcUWQzor5sCCEuH/go-log" ) var log = logging.Logger("blockservice") diff --git a/blockservice/test/blocks_test.go b/blockservice/test/blocks_test.go index 8b56753ad50..8cd5e6dfb95 100644 --- a/blockservice/test/blocks_test.go +++ b/blockservice/test/blocks_test.go @@ -7,7 +7,6 @@ import ( ds "github.com/ipfs/go-ipfs/Godeps/_workspace/src/github.com/ipfs/go-datastore" dssync "github.com/ipfs/go-ipfs/Godeps/_workspace/src/github.com/ipfs/go-datastore/sync" - "github.com/ipfs/go-ipfs/Godeps/_workspace/src/golang.org/x/net/context" blocks "github.com/ipfs/go-ipfs/blocks" blockstore "github.com/ipfs/go-ipfs/blocks/blockstore" blocksutil "github.com/ipfs/go-ipfs/blocks/blocksutil" @@ -15,6 +14,7 @@ import ( . "github.com/ipfs/go-ipfs/blockservice" offline "github.com/ipfs/go-ipfs/exchange/offline" u "github.com/ipfs/go-ipfs/util" + "gx/ipfs/QmZy2y8t9zQH2a1b8q2ZSLKp17ATuJoCNxxyMFG5qFExpt/go-net/context" ) func TestBlocks(t *testing.T) { diff --git a/circle.yml b/circle.yml index 13f2ad543c6..b0474d57368 100644 --- a/circle.yml +++ b/circle.yml @@ -2,12 +2,17 @@ machine: environment: TEST_NO_FUSE: 1 TEST_VERBOSE: 1 + TEST_NO_DOCKER: 1 TRAVIS: 1 CIRCLE: 1 + IMPORT_PATH: "github.com/ipfs/go-ipfs" + GOPATH: "$HOME/.go_workspace" + post: - sudo rm -rf /usr/local/go - - if [ ! -e go1.5.linux-amd64.tar.gz ]; then curl -o go1.5.linux-amd64.tar.gz https://storage.googleapis.com/golang/go1.5.linux-amd64.tar.gz; fi - - sudo tar -C /usr/local -xzf go1.5.linux-amd64.tar.gz + - if [ ! -e go1.5.2.linux-amd64.tar.gz ]; then curl -o go1.5.2.linux-amd64.tar.gz https://storage.googleapis.com/golang/go1.5.2.linux-amd64.tar.gz; fi + - sudo tar -C /usr/local -xzf go1.5.2.linux-amd64.tar.gz + services: - docker @@ -15,10 +20,21 @@ dependencies: pre: # setup ipv6 - sudo sysctl -w net.ipv6.conf.lo.disable_ipv6=0 net.ipv6.conf.default.disable_ipv6=0 net.ipv6.conf.all.disable_ipv6=0 + - go get -u github.com/whyrusleeping/gx + - go get -u github.com/whyrusleeping/gx-go + + override: + - mkdir -p "$HOME/.go_workspace/src/$IMPORT_PATH" + - cp -a ./* "$HOME/.go_workspace/src/$IMPORT_PATH" + - gx --verbose install --global + cache_directories: - - ~/go1.5.linux-amd64.tar.gz + - ~/go1.5.2.linux-amd64.tar.gz + - "$HOME/.go_workspace/src/gx/ipfs" test: override: - - make test_go_expensive - - make test_sharness_expensive + - make test_go_expensive: + pwd: "../.go_workspace/src/$IMPORT_PATH" + - make test_sharness_expensive: + pwd: "../.go_workspace/src/$IMPORT_PATH" diff --git a/cmd/ipfs/Makefile b/cmd/ipfs/Makefile index d2b7d813201..e0ce5f4d2ae 100644 --- a/cmd/ipfs/Makefile +++ b/cmd/ipfs/Makefile @@ -1,9 +1,7 @@ all: install -commit = $(shell git rev-parse --short HEAD 2> /dev/null || echo unknown) -ldflags = "-X "github.com/ipfs/go-ipfs/repo/config".CurrentCommit=$(commit)" build: - go build -ldflags=$(ldflags) + cd ../../ && make build -install: build - go install +install: + cd ../../ && make install diff --git a/cmd/ipfs/daemon.go b/cmd/ipfs/daemon.go index a2cbb6ccd44..3906bec8664 100644 --- a/cmd/ipfs/daemon.go +++ b/cmd/ipfs/daemon.go @@ -12,8 +12,8 @@ import ( "sync" _ "github.com/ipfs/go-ipfs/Godeps/_workspace/src/github.com/codahale/metrics/runtime" - ma "github.com/ipfs/go-ipfs/Godeps/_workspace/src/github.com/jbenet/go-multiaddr" - "github.com/ipfs/go-ipfs/Godeps/_workspace/src/github.com/jbenet/go-multiaddr-net" + ma "gx/ipfs/QmR3JkmZBKYXgNMNsNZawm914455Qof3PEopwuVSeXG7aV/go-multiaddr" + "gx/ipfs/QmYtzQmUwPFGxjCXctJ8e6GXS8sYfoXy2pdeMbS5SFWqRi/go-multiaddr-net" cmds "github.com/ipfs/go-ipfs/commands" "github.com/ipfs/go-ipfs/core" @@ -21,10 +21,10 @@ import ( corehttp "github.com/ipfs/go-ipfs/core/corehttp" corerepo "github.com/ipfs/go-ipfs/core/corerepo" "github.com/ipfs/go-ipfs/core/corerouting" - conn "github.com/ipfs/go-ipfs/p2p/net/conn" - peer "github.com/ipfs/go-ipfs/p2p/peer" fsrepo "github.com/ipfs/go-ipfs/repo/fsrepo" util "github.com/ipfs/go-ipfs/util" + conn "gx/ipfs/QmUBogf4nUefBjmYjn6jfsfPJRkmDGSeMhNj4usRKq69f4/go-libp2p/p2p/net/conn" + peer "gx/ipfs/QmUBogf4nUefBjmYjn6jfsfPJRkmDGSeMhNj4usRKq69f4/go-libp2p/p2p/peer" ) const ( diff --git a/cmd/ipfs/init.go b/cmd/ipfs/init.go index d9981304cba..2861901fb97 100644 --- a/cmd/ipfs/init.go +++ b/cmd/ipfs/init.go @@ -7,13 +7,13 @@ import ( "os" "path" - context "github.com/ipfs/go-ipfs/Godeps/_workspace/src/golang.org/x/net/context" assets "github.com/ipfs/go-ipfs/assets" cmds "github.com/ipfs/go-ipfs/commands" core "github.com/ipfs/go-ipfs/core" namesys "github.com/ipfs/go-ipfs/namesys" config "github.com/ipfs/go-ipfs/repo/config" fsrepo "github.com/ipfs/go-ipfs/repo/fsrepo" + context "gx/ipfs/QmZy2y8t9zQH2a1b8q2ZSLKp17ATuJoCNxxyMFG5qFExpt/go-net/context" ) const nBitsForKeypairDefault = 2048 diff --git a/cmd/ipfs/main.go b/cmd/ipfs/main.go index 955198d669b..5fe667c3bc4 100644 --- a/cmd/ipfs/main.go +++ b/cmd/ipfs/main.go @@ -17,10 +17,9 @@ import ( "syscall" "time" - ma "github.com/ipfs/go-ipfs/Godeps/_workspace/src/github.com/jbenet/go-multiaddr" - manet "github.com/ipfs/go-ipfs/Godeps/_workspace/src/github.com/jbenet/go-multiaddr-net" + ma "gx/ipfs/QmR3JkmZBKYXgNMNsNZawm914455Qof3PEopwuVSeXG7aV/go-multiaddr" + manet "gx/ipfs/QmYtzQmUwPFGxjCXctJ8e6GXS8sYfoXy2pdeMbS5SFWqRi/go-multiaddr-net" - context "github.com/ipfs/go-ipfs/Godeps/_workspace/src/golang.org/x/net/context" cmds "github.com/ipfs/go-ipfs/commands" cmdsCli "github.com/ipfs/go-ipfs/commands/cli" cmdsHttp "github.com/ipfs/go-ipfs/commands/http" @@ -30,7 +29,8 @@ import ( config "github.com/ipfs/go-ipfs/repo/config" fsrepo "github.com/ipfs/go-ipfs/repo/fsrepo" u "github.com/ipfs/go-ipfs/util" - logging "github.com/ipfs/go-ipfs/vendor/QmQg1J6vikuXF9oDvm4wpdeAUvvkVEKW1EYDw9HhTMnP2b/go-log" + context "gx/ipfs/QmZy2y8t9zQH2a1b8q2ZSLKp17ATuJoCNxxyMFG5qFExpt/go-net/context" + logging "gx/ipfs/Qmazh5oNUVsDZTs2g59rq8aYQqwpss8tcUWQzor5sCCEuH/go-log" ) // log is the command logger diff --git a/cmd/ipfswatch/main.go b/cmd/ipfswatch/main.go index ec98f2bffca..3c03c6b0fad 100644 --- a/cmd/ipfswatch/main.go +++ b/cmd/ipfswatch/main.go @@ -9,7 +9,6 @@ import ( process "github.com/ipfs/go-ipfs/Godeps/_workspace/src/github.com/jbenet/goprocess" homedir "github.com/ipfs/go-ipfs/Godeps/_workspace/src/github.com/mitchellh/go-homedir" - context "github.com/ipfs/go-ipfs/Godeps/_workspace/src/golang.org/x/net/context" fsnotify "github.com/ipfs/go-ipfs/Godeps/_workspace/src/gopkg.in/fsnotify.v1" commands "github.com/ipfs/go-ipfs/commands" core "github.com/ipfs/go-ipfs/core" @@ -17,6 +16,7 @@ import ( coreunix "github.com/ipfs/go-ipfs/core/coreunix" config "github.com/ipfs/go-ipfs/repo/config" fsrepo "github.com/ipfs/go-ipfs/repo/fsrepo" + context "gx/ipfs/QmZy2y8t9zQH2a1b8q2ZSLKp17ATuJoCNxxyMFG5qFExpt/go-net/context" ) var http = flag.Bool("http", false, "expose IPFS HTTP API") diff --git a/cmd/seccat/seccat.go b/cmd/seccat/seccat.go index ac1829ae9b4..e883d0e06d6 100644 --- a/cmd/seccat/seccat.go +++ b/cmd/seccat/seccat.go @@ -18,11 +18,11 @@ import ( "os/signal" "syscall" - context "github.com/ipfs/go-ipfs/Godeps/_workspace/src/golang.org/x/net/context" - ci "github.com/ipfs/go-ipfs/p2p/crypto" - secio "github.com/ipfs/go-ipfs/p2p/crypto/secio" - peer "github.com/ipfs/go-ipfs/p2p/peer" - logging "github.com/ipfs/go-ipfs/vendor/QmQg1J6vikuXF9oDvm4wpdeAUvvkVEKW1EYDw9HhTMnP2b/go-log" + ci "gx/ipfs/QmUBogf4nUefBjmYjn6jfsfPJRkmDGSeMhNj4usRKq69f4/go-libp2p/p2p/crypto" + secio "gx/ipfs/QmUBogf4nUefBjmYjn6jfsfPJRkmDGSeMhNj4usRKq69f4/go-libp2p/p2p/crypto/secio" + peer "gx/ipfs/QmUBogf4nUefBjmYjn6jfsfPJRkmDGSeMhNj4usRKq69f4/go-libp2p/p2p/peer" + context "gx/ipfs/QmZy2y8t9zQH2a1b8q2ZSLKp17ATuJoCNxxyMFG5qFExpt/go-net/context" + logging "gx/ipfs/Qmazh5oNUVsDZTs2g59rq8aYQqwpss8tcUWQzor5sCCEuH/go-log" ) var verbose = false diff --git a/cmd/seccat/util.go b/cmd/seccat/util.go index 6f09574efa3..433e8b51508 100644 --- a/cmd/seccat/util.go +++ b/cmd/seccat/util.go @@ -5,7 +5,7 @@ import ( "io" "os" - logging "github.com/ipfs/go-ipfs/vendor/QmQg1J6vikuXF9oDvm4wpdeAUvvkVEKW1EYDw9HhTMnP2b/go-log" + logging "gx/ipfs/Qmazh5oNUVsDZTs2g59rq8aYQqwpss8tcUWQzor5sCCEuH/go-log" ) var log = logging.Logger("seccat") diff --git a/commands/command.go b/commands/command.go index 3a6ba681ada..d572daa0317 100644 --- a/commands/command.go +++ b/commands/command.go @@ -15,7 +15,7 @@ import ( "reflect" "github.com/ipfs/go-ipfs/path" - logging "github.com/ipfs/go-ipfs/vendor/QmQg1J6vikuXF9oDvm4wpdeAUvvkVEKW1EYDw9HhTMnP2b/go-log" + logging "gx/ipfs/Qmazh5oNUVsDZTs2g59rq8aYQqwpss8tcUWQzor5sCCEuH/go-log" ) var log = logging.Logger("command") diff --git a/commands/http/client.go b/commands/http/client.go index 8489bf9b62e..eec01a26826 100644 --- a/commands/http/client.go +++ b/commands/http/client.go @@ -15,7 +15,7 @@ import ( cmds "github.com/ipfs/go-ipfs/commands" config "github.com/ipfs/go-ipfs/repo/config" - context "github.com/ipfs/go-ipfs/Godeps/_workspace/src/golang.org/x/net/context" + context "gx/ipfs/QmZy2y8t9zQH2a1b8q2ZSLKp17ATuJoCNxxyMFG5qFExpt/go-net/context" ) const ( diff --git a/commands/http/handler.go b/commands/http/handler.go index 3188c8bb573..2aa89a9ef8f 100644 --- a/commands/http/handler.go +++ b/commands/http/handler.go @@ -12,11 +12,11 @@ import ( "sync" cors "github.com/ipfs/go-ipfs/Godeps/_workspace/src/github.com/rs/cors" - context "github.com/ipfs/go-ipfs/Godeps/_workspace/src/golang.org/x/net/context" "github.com/ipfs/go-ipfs/repo/config" + context "gx/ipfs/QmZy2y8t9zQH2a1b8q2ZSLKp17ATuJoCNxxyMFG5qFExpt/go-net/context" cmds "github.com/ipfs/go-ipfs/commands" - logging "github.com/ipfs/go-ipfs/vendor/QmQg1J6vikuXF9oDvm4wpdeAUvvkVEKW1EYDw9HhTMnP2b/go-log" + logging "gx/ipfs/Qmazh5oNUVsDZTs2g59rq8aYQqwpss8tcUWQzor5sCCEuH/go-log" ) var log = logging.Logger("commands/http") diff --git a/commands/request.go b/commands/request.go index b31e7417ebc..ccc7c0f8967 100644 --- a/commands/request.go +++ b/commands/request.go @@ -9,11 +9,11 @@ import ( "strconv" "time" - context "github.com/ipfs/go-ipfs/Godeps/_workspace/src/golang.org/x/net/context" "github.com/ipfs/go-ipfs/commands/files" "github.com/ipfs/go-ipfs/core" "github.com/ipfs/go-ipfs/repo/config" u "github.com/ipfs/go-ipfs/util" + context "gx/ipfs/QmZy2y8t9zQH2a1b8q2ZSLKp17ATuJoCNxxyMFG5qFExpt/go-net/context" ) type OptMap map[string]interface{} diff --git a/core/bootstrap.go b/core/bootstrap.go index 6b969c96dcb..ff757730021 100644 --- a/core/bootstrap.go +++ b/core/bootstrap.go @@ -8,17 +8,17 @@ import ( "sync" "time" - host "github.com/ipfs/go-ipfs/p2p/host" - inet "github.com/ipfs/go-ipfs/p2p/net" - peer "github.com/ipfs/go-ipfs/p2p/peer" config "github.com/ipfs/go-ipfs/repo/config" math2 "github.com/ipfs/go-ipfs/thirdparty/math2" lgbl "github.com/ipfs/go-ipfs/util/eventlog/loggables" + host "gx/ipfs/QmUBogf4nUefBjmYjn6jfsfPJRkmDGSeMhNj4usRKq69f4/go-libp2p/p2p/host" + inet "gx/ipfs/QmUBogf4nUefBjmYjn6jfsfPJRkmDGSeMhNj4usRKq69f4/go-libp2p/p2p/net" + peer "gx/ipfs/QmUBogf4nUefBjmYjn6jfsfPJRkmDGSeMhNj4usRKq69f4/go-libp2p/p2p/peer" goprocess "github.com/ipfs/go-ipfs/Godeps/_workspace/src/github.com/jbenet/goprocess" procctx "github.com/ipfs/go-ipfs/Godeps/_workspace/src/github.com/jbenet/goprocess/context" periodicproc "github.com/ipfs/go-ipfs/Godeps/_workspace/src/github.com/jbenet/goprocess/periodic" - context "github.com/ipfs/go-ipfs/Godeps/_workspace/src/golang.org/x/net/context" + context "gx/ipfs/QmZy2y8t9zQH2a1b8q2ZSLKp17ATuJoCNxxyMFG5qFExpt/go-net/context" ) // ErrNotEnoughBootstrapPeers signals that we do not have enough bootstrap diff --git a/core/bootstrap_test.go b/core/bootstrap_test.go index 9e4b2d14a52..0a2fb8b8239 100644 --- a/core/bootstrap_test.go +++ b/core/bootstrap_test.go @@ -4,9 +4,9 @@ import ( "fmt" "testing" - peer "github.com/ipfs/go-ipfs/p2p/peer" config "github.com/ipfs/go-ipfs/repo/config" testutil "github.com/ipfs/go-ipfs/util/testutil" + peer "gx/ipfs/QmUBogf4nUefBjmYjn6jfsfPJRkmDGSeMhNj4usRKq69f4/go-libp2p/p2p/peer" ) func TestSubsetWhenMaxIsGreaterThanLengthOfSlice(t *testing.T) { diff --git a/core/builder.go b/core/builder.go index e5fbb4f0126..cd1c0f77c42 100644 --- a/core/builder.go +++ b/core/builder.go @@ -8,18 +8,18 @@ import ( ds "github.com/ipfs/go-ipfs/Godeps/_workspace/src/github.com/ipfs/go-datastore" dsync "github.com/ipfs/go-ipfs/Godeps/_workspace/src/github.com/ipfs/go-datastore/sync" goprocessctx "github.com/ipfs/go-ipfs/Godeps/_workspace/src/github.com/jbenet/goprocess/context" - context "github.com/ipfs/go-ipfs/Godeps/_workspace/src/golang.org/x/net/context" bstore "github.com/ipfs/go-ipfs/blocks/blockstore" key "github.com/ipfs/go-ipfs/blocks/key" bserv "github.com/ipfs/go-ipfs/blockservice" offline "github.com/ipfs/go-ipfs/exchange/offline" dag "github.com/ipfs/go-ipfs/merkledag" - ci "github.com/ipfs/go-ipfs/p2p/crypto" - peer "github.com/ipfs/go-ipfs/p2p/peer" path "github.com/ipfs/go-ipfs/path" pin "github.com/ipfs/go-ipfs/pin" repo "github.com/ipfs/go-ipfs/repo" cfg "github.com/ipfs/go-ipfs/repo/config" + ci "gx/ipfs/QmUBogf4nUefBjmYjn6jfsfPJRkmDGSeMhNj4usRKq69f4/go-libp2p/p2p/crypto" + peer "gx/ipfs/QmUBogf4nUefBjmYjn6jfsfPJRkmDGSeMhNj4usRKq69f4/go-libp2p/p2p/peer" + context "gx/ipfs/QmZy2y8t9zQH2a1b8q2ZSLKp17ATuJoCNxxyMFG5qFExpt/go-net/context" ) type BuildCfg struct { diff --git a/core/commands/bitswap.go b/core/commands/bitswap.go index 05af5703674..ece9a3f5278 100644 --- a/core/commands/bitswap.go +++ b/core/commands/bitswap.go @@ -10,8 +10,8 @@ import ( key "github.com/ipfs/go-ipfs/blocks/key" cmds "github.com/ipfs/go-ipfs/commands" bitswap "github.com/ipfs/go-ipfs/exchange/bitswap" - peer "github.com/ipfs/go-ipfs/p2p/peer" u "github.com/ipfs/go-ipfs/util" + peer "gx/ipfs/QmUBogf4nUefBjmYjn6jfsfPJRkmDGSeMhNj4usRKq69f4/go-libp2p/p2p/peer" ) var BitswapCmd = &cmds.Command{ diff --git a/core/commands/cat.go b/core/commands/cat.go index e00cccd79d1..09d28bcbce5 100644 --- a/core/commands/cat.go +++ b/core/commands/cat.go @@ -8,7 +8,7 @@ import ( "github.com/ipfs/go-ipfs/core/corerepo" coreunix "github.com/ipfs/go-ipfs/core/coreunix" - context "github.com/ipfs/go-ipfs/Godeps/_workspace/src/golang.org/x/net/context" + context "gx/ipfs/QmZy2y8t9zQH2a1b8q2ZSLKp17ATuJoCNxxyMFG5qFExpt/go-net/context" ) const progressBarMinSize = 1024 * 1024 * 8 // show progress bar for outputs > 8MiB diff --git a/core/commands/dht.go b/core/commands/dht.go index 016ec054a71..782d599a8e5 100644 --- a/core/commands/dht.go +++ b/core/commands/dht.go @@ -10,10 +10,10 @@ import ( key "github.com/ipfs/go-ipfs/blocks/key" cmds "github.com/ipfs/go-ipfs/commands" notif "github.com/ipfs/go-ipfs/notifications" - peer "github.com/ipfs/go-ipfs/p2p/peer" path "github.com/ipfs/go-ipfs/path" ipdht "github.com/ipfs/go-ipfs/routing/dht" u "github.com/ipfs/go-ipfs/util" + peer "gx/ipfs/QmUBogf4nUefBjmYjn6jfsfPJRkmDGSeMhNj4usRKq69f4/go-libp2p/p2p/peer" ) var ErrNotDHT = errors.New("routing service is not a DHT") diff --git a/core/commands/files/files.go b/core/commands/files/files.go index d03d5e36fe8..eb17c674eba 100644 --- a/core/commands/files/files.go +++ b/core/commands/files/files.go @@ -16,8 +16,8 @@ import ( path "github.com/ipfs/go-ipfs/path" ft "github.com/ipfs/go-ipfs/unixfs" - context "github.com/ipfs/go-ipfs/Godeps/_workspace/src/golang.org/x/net/context" - logging "github.com/ipfs/go-ipfs/vendor/QmQg1J6vikuXF9oDvm4wpdeAUvvkVEKW1EYDw9HhTMnP2b/go-log" + context "gx/ipfs/QmZy2y8t9zQH2a1b8q2ZSLKp17ATuJoCNxxyMFG5qFExpt/go-net/context" + logging "gx/ipfs/Qmazh5oNUVsDZTs2g59rq8aYQqwpss8tcUWQzor5sCCEuH/go-log" ) var log = logging.Logger("cmds/files") diff --git a/core/commands/id.go b/core/commands/id.go index d6d70c98126..ad0895b34fa 100644 --- a/core/commands/id.go +++ b/core/commands/id.go @@ -12,11 +12,11 @@ import ( cmds "github.com/ipfs/go-ipfs/commands" core "github.com/ipfs/go-ipfs/core" - ic "github.com/ipfs/go-ipfs/p2p/crypto" - "github.com/ipfs/go-ipfs/p2p/peer" - identify "github.com/ipfs/go-ipfs/p2p/protocol/identify" kb "github.com/ipfs/go-ipfs/routing/kbucket" u "github.com/ipfs/go-ipfs/util" + ic "gx/ipfs/QmUBogf4nUefBjmYjn6jfsfPJRkmDGSeMhNj4usRKq69f4/go-libp2p/p2p/crypto" + "gx/ipfs/QmUBogf4nUefBjmYjn6jfsfPJRkmDGSeMhNj4usRKq69f4/go-libp2p/p2p/peer" + identify "gx/ipfs/QmUBogf4nUefBjmYjn6jfsfPJRkmDGSeMhNj4usRKq69f4/go-libp2p/p2p/protocol/identify" ) const offlineIdErrorMessage = `'ipfs id' currently cannot query information on remote @@ -205,7 +205,7 @@ func printSelf(node *core.IpfsNode) (interface{}, error) { info.Addresses = append(info.Addresses, s) } } - info.ProtocolVersion = identify.IpfsVersion + info.ProtocolVersion = identify.LibP2PVersion info.AgentVersion = identify.ClientVersion return info, nil } diff --git a/core/commands/log.go b/core/commands/log.go index ead2d38f51c..ec53c853b21 100644 --- a/core/commands/log.go +++ b/core/commands/log.go @@ -5,7 +5,7 @@ import ( "io" cmds "github.com/ipfs/go-ipfs/commands" - logging "github.com/ipfs/go-ipfs/vendor/QmQg1J6vikuXF9oDvm4wpdeAUvvkVEKW1EYDw9HhTMnP2b/go-log" + logging "gx/ipfs/Qmazh5oNUVsDZTs2g59rq8aYQqwpss8tcUWQzor5sCCEuH/go-log" ) // Golang os.Args overrides * and replaces the character argument with diff --git a/core/commands/pin.go b/core/commands/pin.go index e175f1e030b..55262e3715d 100644 --- a/core/commands/pin.go +++ b/core/commands/pin.go @@ -7,12 +7,12 @@ import ( key "github.com/ipfs/go-ipfs/blocks/key" cmds "github.com/ipfs/go-ipfs/commands" - context "github.com/ipfs/go-ipfs/Godeps/_workspace/src/golang.org/x/net/context" core "github.com/ipfs/go-ipfs/core" corerepo "github.com/ipfs/go-ipfs/core/corerepo" dag "github.com/ipfs/go-ipfs/merkledag" path "github.com/ipfs/go-ipfs/path" u "github.com/ipfs/go-ipfs/util" + context "gx/ipfs/QmZy2y8t9zQH2a1b8q2ZSLKp17ATuJoCNxxyMFG5qFExpt/go-net/context" ) var PinCmd = &cmds.Command{ diff --git a/core/commands/ping.go b/core/commands/ping.go index 62568c18413..430252a659d 100644 --- a/core/commands/ping.go +++ b/core/commands/ping.go @@ -10,11 +10,11 @@ import ( cmds "github.com/ipfs/go-ipfs/commands" core "github.com/ipfs/go-ipfs/core" - peer "github.com/ipfs/go-ipfs/p2p/peer" u "github.com/ipfs/go-ipfs/util" + peer "gx/ipfs/QmUBogf4nUefBjmYjn6jfsfPJRkmDGSeMhNj4usRKq69f4/go-libp2p/p2p/peer" - ma "github.com/ipfs/go-ipfs/Godeps/_workspace/src/github.com/jbenet/go-multiaddr" - context "github.com/ipfs/go-ipfs/Godeps/_workspace/src/golang.org/x/net/context" + ma "gx/ipfs/QmR3JkmZBKYXgNMNsNZawm914455Qof3PEopwuVSeXG7aV/go-multiaddr" + context "gx/ipfs/QmZy2y8t9zQH2a1b8q2ZSLKp17ATuJoCNxxyMFG5qFExpt/go-net/context" ) const kPingTimeout = 10 * time.Second diff --git a/core/commands/publish.go b/core/commands/publish.go index 85037dc9bd2..904cfb7c3f8 100644 --- a/core/commands/publish.go +++ b/core/commands/publish.go @@ -7,13 +7,13 @@ import ( "strings" "time" - context "github.com/ipfs/go-ipfs/Godeps/_workspace/src/golang.org/x/net/context" + context "gx/ipfs/QmZy2y8t9zQH2a1b8q2ZSLKp17ATuJoCNxxyMFG5qFExpt/go-net/context" key "github.com/ipfs/go-ipfs/blocks/key" cmds "github.com/ipfs/go-ipfs/commands" core "github.com/ipfs/go-ipfs/core" - crypto "github.com/ipfs/go-ipfs/p2p/crypto" path "github.com/ipfs/go-ipfs/path" + crypto "gx/ipfs/QmUBogf4nUefBjmYjn6jfsfPJRkmDGSeMhNj4usRKq69f4/go-libp2p/p2p/crypto" ) var errNotOnline = errors.New("This command must be run in online mode. Try running 'ipfs daemon' first.") diff --git a/core/commands/refs.go b/core/commands/refs.go index 384c2870695..02d53e4f5a8 100644 --- a/core/commands/refs.go +++ b/core/commands/refs.go @@ -7,13 +7,13 @@ import ( "io" "strings" - context "github.com/ipfs/go-ipfs/Godeps/_workspace/src/golang.org/x/net/context" key "github.com/ipfs/go-ipfs/blocks/key" cmds "github.com/ipfs/go-ipfs/commands" "github.com/ipfs/go-ipfs/core" dag "github.com/ipfs/go-ipfs/merkledag" path "github.com/ipfs/go-ipfs/path" u "github.com/ipfs/go-ipfs/util" + context "gx/ipfs/QmZy2y8t9zQH2a1b8q2ZSLKp17ATuJoCNxxyMFG5qFExpt/go-net/context" ) // KeyList is a general type for outputting lists of keys diff --git a/core/commands/root.go b/core/commands/root.go index 32b9c88925c..91e007b3795 100644 --- a/core/commands/root.go +++ b/core/commands/root.go @@ -8,7 +8,7 @@ import ( files "github.com/ipfs/go-ipfs/core/commands/files" ocmd "github.com/ipfs/go-ipfs/core/commands/object" unixfs "github.com/ipfs/go-ipfs/core/commands/unixfs" - logging "github.com/ipfs/go-ipfs/vendor/QmQg1J6vikuXF9oDvm4wpdeAUvvkVEKW1EYDw9HhTMnP2b/go-log" + logging "gx/ipfs/Qmazh5oNUVsDZTs2g59rq8aYQqwpss8tcUWQzor5sCCEuH/go-log" ) var log = logging.Logger("core/commands") diff --git a/core/commands/stat.go b/core/commands/stat.go index 277e3b88ce8..e9d13f0bb12 100644 --- a/core/commands/stat.go +++ b/core/commands/stat.go @@ -10,10 +10,10 @@ import ( humanize "github.com/ipfs/go-ipfs/Godeps/_workspace/src/github.com/dustin/go-humanize" cmds "github.com/ipfs/go-ipfs/commands" - metrics "github.com/ipfs/go-ipfs/metrics" - peer "github.com/ipfs/go-ipfs/p2p/peer" - protocol "github.com/ipfs/go-ipfs/p2p/protocol" u "github.com/ipfs/go-ipfs/util" + metrics "gx/ipfs/QmUBogf4nUefBjmYjn6jfsfPJRkmDGSeMhNj4usRKq69f4/go-libp2p/p2p/metrics" + peer "gx/ipfs/QmUBogf4nUefBjmYjn6jfsfPJRkmDGSeMhNj4usRKq69f4/go-libp2p/p2p/peer" + protocol "gx/ipfs/QmUBogf4nUefBjmYjn6jfsfPJRkmDGSeMhNj4usRKq69f4/go-libp2p/p2p/protocol" ) var StatsCmd = &cmds.Command{ diff --git a/core/commands/swarm.go b/core/commands/swarm.go index 5a7777e5fda..b99a7edd7b6 100644 --- a/core/commands/swarm.go +++ b/core/commands/swarm.go @@ -9,12 +9,12 @@ import ( "sort" cmds "github.com/ipfs/go-ipfs/commands" - swarm "github.com/ipfs/go-ipfs/p2p/net/swarm" - peer "github.com/ipfs/go-ipfs/p2p/peer" iaddr "github.com/ipfs/go-ipfs/util/ipfsaddr" + swarm "gx/ipfs/QmUBogf4nUefBjmYjn6jfsfPJRkmDGSeMhNj4usRKq69f4/go-libp2p/p2p/net/swarm" + peer "gx/ipfs/QmUBogf4nUefBjmYjn6jfsfPJRkmDGSeMhNj4usRKq69f4/go-libp2p/p2p/peer" - ma "github.com/ipfs/go-ipfs/Godeps/_workspace/src/github.com/jbenet/go-multiaddr" mafilter "github.com/ipfs/go-ipfs/Godeps/_workspace/src/github.com/whyrusleeping/multiaddr-filter" + ma "gx/ipfs/QmR3JkmZBKYXgNMNsNZawm914455Qof3PEopwuVSeXG7aV/go-multiaddr" ) type stringList struct { diff --git a/core/commands/sysdiag.go b/core/commands/sysdiag.go index b4557dd8042..06b1e2a651c 100644 --- a/core/commands/sysdiag.go +++ b/core/commands/sysdiag.go @@ -8,8 +8,8 @@ import ( cmds "github.com/ipfs/go-ipfs/commands" config "github.com/ipfs/go-ipfs/repo/config" - manet "github.com/ipfs/go-ipfs/Godeps/_workspace/src/github.com/jbenet/go-multiaddr-net" sysi "github.com/ipfs/go-ipfs/Godeps/_workspace/src/github.com/whyrusleeping/go-sysinfo" + manet "gx/ipfs/QmYtzQmUwPFGxjCXctJ8e6GXS8sYfoXy2pdeMbS5SFWqRi/go-multiaddr-net" ) var sysDiagCmd = &cmds.Command{ diff --git a/core/core.go b/core/core.go index fa01d4a6901..ccad484cfb4 100644 --- a/core/core.go +++ b/core/core.go @@ -18,22 +18,22 @@ import ( ds "github.com/ipfs/go-ipfs/Godeps/_workspace/src/github.com/ipfs/go-datastore" b58 "github.com/ipfs/go-ipfs/Godeps/_workspace/src/github.com/jbenet/go-base58" - ma "github.com/ipfs/go-ipfs/Godeps/_workspace/src/github.com/jbenet/go-multiaddr" goprocess "github.com/ipfs/go-ipfs/Godeps/_workspace/src/github.com/jbenet/goprocess" mamask "github.com/ipfs/go-ipfs/Godeps/_workspace/src/github.com/whyrusleeping/multiaddr-filter" - context "github.com/ipfs/go-ipfs/Godeps/_workspace/src/golang.org/x/net/context" diag "github.com/ipfs/go-ipfs/diagnostics" - metrics "github.com/ipfs/go-ipfs/metrics" - ic "github.com/ipfs/go-ipfs/p2p/crypto" - discovery "github.com/ipfs/go-ipfs/p2p/discovery" - p2phost "github.com/ipfs/go-ipfs/p2p/host" - p2pbhost "github.com/ipfs/go-ipfs/p2p/host/basic" - rhost "github.com/ipfs/go-ipfs/p2p/host/routed" - swarm "github.com/ipfs/go-ipfs/p2p/net/swarm" - addrutil "github.com/ipfs/go-ipfs/p2p/net/swarm/addr" - peer "github.com/ipfs/go-ipfs/p2p/peer" - ping "github.com/ipfs/go-ipfs/p2p/protocol/ping" - logging "github.com/ipfs/go-ipfs/vendor/QmQg1J6vikuXF9oDvm4wpdeAUvvkVEKW1EYDw9HhTMnP2b/go-log" + ma "gx/ipfs/QmR3JkmZBKYXgNMNsNZawm914455Qof3PEopwuVSeXG7aV/go-multiaddr" + ic "gx/ipfs/QmUBogf4nUefBjmYjn6jfsfPJRkmDGSeMhNj4usRKq69f4/go-libp2p/p2p/crypto" + discovery "gx/ipfs/QmUBogf4nUefBjmYjn6jfsfPJRkmDGSeMhNj4usRKq69f4/go-libp2p/p2p/discovery" + p2phost "gx/ipfs/QmUBogf4nUefBjmYjn6jfsfPJRkmDGSeMhNj4usRKq69f4/go-libp2p/p2p/host" + p2pbhost "gx/ipfs/QmUBogf4nUefBjmYjn6jfsfPJRkmDGSeMhNj4usRKq69f4/go-libp2p/p2p/host/basic" + rhost "gx/ipfs/QmUBogf4nUefBjmYjn6jfsfPJRkmDGSeMhNj4usRKq69f4/go-libp2p/p2p/host/routed" + metrics "gx/ipfs/QmUBogf4nUefBjmYjn6jfsfPJRkmDGSeMhNj4usRKq69f4/go-libp2p/p2p/metrics" + swarm "gx/ipfs/QmUBogf4nUefBjmYjn6jfsfPJRkmDGSeMhNj4usRKq69f4/go-libp2p/p2p/net/swarm" + addrutil "gx/ipfs/QmUBogf4nUefBjmYjn6jfsfPJRkmDGSeMhNj4usRKq69f4/go-libp2p/p2p/net/swarm/addr" + peer "gx/ipfs/QmUBogf4nUefBjmYjn6jfsfPJRkmDGSeMhNj4usRKq69f4/go-libp2p/p2p/peer" + ping "gx/ipfs/QmUBogf4nUefBjmYjn6jfsfPJRkmDGSeMhNj4usRKq69f4/go-libp2p/p2p/protocol/ping" + context "gx/ipfs/QmZy2y8t9zQH2a1b8q2ZSLKp17ATuJoCNxxyMFG5qFExpt/go-net/context" + logging "gx/ipfs/Qmazh5oNUVsDZTs2g59rq8aYQqwpss8tcUWQzor5sCCEuH/go-log" routing "github.com/ipfs/go-ipfs/routing" dht "github.com/ipfs/go-ipfs/routing/dht" diff --git a/core/core_test.go b/core/core_test.go index 42568b4c0f4..027a721d03c 100644 --- a/core/core_test.go +++ b/core/core_test.go @@ -3,10 +3,10 @@ package core import ( "testing" - context "github.com/ipfs/go-ipfs/Godeps/_workspace/src/golang.org/x/net/context" "github.com/ipfs/go-ipfs/repo" config "github.com/ipfs/go-ipfs/repo/config" "github.com/ipfs/go-ipfs/util/testutil" + context "gx/ipfs/QmZy2y8t9zQH2a1b8q2ZSLKp17ATuJoCNxxyMFG5qFExpt/go-net/context" ) func TestInitialization(t *testing.T) { diff --git a/core/corehttp/corehttp.go b/core/corehttp/corehttp.go index 155f532a40f..ed14165ced8 100644 --- a/core/corehttp/corehttp.go +++ b/core/corehttp/corehttp.go @@ -10,11 +10,11 @@ import ( "net/http" "time" - ma "github.com/ipfs/go-ipfs/Godeps/_workspace/src/github.com/jbenet/go-multiaddr" - manet "github.com/ipfs/go-ipfs/Godeps/_workspace/src/github.com/jbenet/go-multiaddr-net" "github.com/ipfs/go-ipfs/Godeps/_workspace/src/github.com/jbenet/goprocess" core "github.com/ipfs/go-ipfs/core" - logging "github.com/ipfs/go-ipfs/vendor/QmQg1J6vikuXF9oDvm4wpdeAUvvkVEKW1EYDw9HhTMnP2b/go-log" + ma "gx/ipfs/QmR3JkmZBKYXgNMNsNZawm914455Qof3PEopwuVSeXG7aV/go-multiaddr" + manet "gx/ipfs/QmYtzQmUwPFGxjCXctJ8e6GXS8sYfoXy2pdeMbS5SFWqRi/go-multiaddr-net" + logging "gx/ipfs/Qmazh5oNUVsDZTs2g59rq8aYQqwpss8tcUWQzor5sCCEuH/go-log" ) var log = logging.Logger("core/server") diff --git a/core/corehttp/gateway.go b/core/corehttp/gateway.go index e5d6569a7a8..a1b66397391 100644 --- a/core/corehttp/gateway.go +++ b/core/corehttp/gateway.go @@ -7,8 +7,8 @@ import ( "sync" core "github.com/ipfs/go-ipfs/core" - id "github.com/ipfs/go-ipfs/p2p/protocol/identify" config "github.com/ipfs/go-ipfs/repo/config" + id "gx/ipfs/QmUBogf4nUefBjmYjn6jfsfPJRkmDGSeMhNj4usRKq69f4/go-libp2p/p2p/protocol/identify" ) // Gateway should be instantiated using NewGateway @@ -61,7 +61,7 @@ func VersionOption() ServeOption { mux.HandleFunc("/version", func(w http.ResponseWriter, r *http.Request) { fmt.Fprintf(w, "Commit: %s\n", config.CurrentCommit) fmt.Fprintf(w, "Client Version: %s\n", id.ClientVersion) - fmt.Fprintf(w, "Protocol Version: %s\n", id.IpfsVersion) + fmt.Fprintf(w, "Protocol Version: %s\n", id.LibP2PVersion) }) return mux, nil } diff --git a/core/corehttp/gateway_handler.go b/core/corehttp/gateway_handler.go index ddabc474d8c..ebf0b3c6ef4 100644 --- a/core/corehttp/gateway_handler.go +++ b/core/corehttp/gateway_handler.go @@ -11,7 +11,7 @@ import ( "time" humanize "github.com/ipfs/go-ipfs/Godeps/_workspace/src/github.com/dustin/go-humanize" - "github.com/ipfs/go-ipfs/Godeps/_workspace/src/golang.org/x/net/context" + "gx/ipfs/QmZy2y8t9zQH2a1b8q2ZSLKp17ATuJoCNxxyMFG5qFExpt/go-net/context" key "github.com/ipfs/go-ipfs/blocks/key" core "github.com/ipfs/go-ipfs/core" diff --git a/core/corehttp/gateway_test.go b/core/corehttp/gateway_test.go index ffc49c604a7..7624714fae1 100644 --- a/core/corehttp/gateway_test.go +++ b/core/corehttp/gateway_test.go @@ -9,16 +9,16 @@ import ( "testing" "time" - context "github.com/ipfs/go-ipfs/Godeps/_workspace/src/golang.org/x/net/context" core "github.com/ipfs/go-ipfs/core" coreunix "github.com/ipfs/go-ipfs/core/coreunix" namesys "github.com/ipfs/go-ipfs/namesys" - ci "github.com/ipfs/go-ipfs/p2p/crypto" - id "github.com/ipfs/go-ipfs/p2p/protocol/identify" path "github.com/ipfs/go-ipfs/path" repo "github.com/ipfs/go-ipfs/repo" config "github.com/ipfs/go-ipfs/repo/config" testutil "github.com/ipfs/go-ipfs/util/testutil" + ci "gx/ipfs/QmUBogf4nUefBjmYjn6jfsfPJRkmDGSeMhNj4usRKq69f4/go-libp2p/p2p/crypto" + id "gx/ipfs/QmUBogf4nUefBjmYjn6jfsfPJRkmDGSeMhNj4usRKq69f4/go-libp2p/p2p/protocol/identify" + context "gx/ipfs/QmZy2y8t9zQH2a1b8q2ZSLKp17ATuJoCNxxyMFG5qFExpt/go-net/context" ) type mockNamesys map[string]path.Path @@ -431,7 +431,7 @@ func TestVersion(t *testing.T) { t.Fatalf("response doesn't contain client version:\n%s", s) } - if !strings.Contains(s, "Protocol Version: "+id.IpfsVersion) { + if !strings.Contains(s, "Protocol Version: "+id.LibP2PVersion) { t.Fatalf("response doesn't contain protocol version:\n%s", s) } } diff --git a/core/corehttp/ipns_hostname.go b/core/corehttp/ipns_hostname.go index dd6a64d5f5a..c6b14404008 100644 --- a/core/corehttp/ipns_hostname.go +++ b/core/corehttp/ipns_hostname.go @@ -6,8 +6,8 @@ import ( "strings" isd "github.com/ipfs/go-ipfs/Godeps/_workspace/src/github.com/jbenet/go-is-domain" - "github.com/ipfs/go-ipfs/Godeps/_workspace/src/golang.org/x/net/context" "github.com/ipfs/go-ipfs/core" + "gx/ipfs/QmZy2y8t9zQH2a1b8q2ZSLKp17ATuJoCNxxyMFG5qFExpt/go-net/context" ) // IPNSHostnameOption rewrites an incoming request if its Host: header contains diff --git a/core/corehttp/logs.go b/core/corehttp/logs.go index 6964a2f79a8..82bd2ab799c 100644 --- a/core/corehttp/logs.go +++ b/core/corehttp/logs.go @@ -6,7 +6,7 @@ import ( "net/http" core "github.com/ipfs/go-ipfs/core" - logging "github.com/ipfs/go-ipfs/vendor/QmQg1J6vikuXF9oDvm4wpdeAUvvkVEKW1EYDw9HhTMnP2b/go-log" + logging "gx/ipfs/Qmazh5oNUVsDZTs2g59rq8aYQqwpss8tcUWQzor5sCCEuH/go-log" ) type writeErrNotifier struct { diff --git a/core/corenet/net.go b/core/corenet/net.go index 8618067e301..bd4365ebda8 100644 --- a/core/corenet/net.go +++ b/core/corenet/net.go @@ -3,11 +3,11 @@ package corenet import ( "time" - context "github.com/ipfs/go-ipfs/Godeps/_workspace/src/golang.org/x/net/context" core "github.com/ipfs/go-ipfs/core" - net "github.com/ipfs/go-ipfs/p2p/net" - peer "github.com/ipfs/go-ipfs/p2p/peer" - pro "github.com/ipfs/go-ipfs/p2p/protocol" + net "gx/ipfs/QmUBogf4nUefBjmYjn6jfsfPJRkmDGSeMhNj4usRKq69f4/go-libp2p/p2p/net" + peer "gx/ipfs/QmUBogf4nUefBjmYjn6jfsfPJRkmDGSeMhNj4usRKq69f4/go-libp2p/p2p/peer" + pro "gx/ipfs/QmUBogf4nUefBjmYjn6jfsfPJRkmDGSeMhNj4usRKq69f4/go-libp2p/p2p/protocol" + context "gx/ipfs/QmZy2y8t9zQH2a1b8q2ZSLKp17ATuJoCNxxyMFG5qFExpt/go-net/context" ) type ipfsListener struct { @@ -60,5 +60,5 @@ func Dial(nd *core.IpfsNode, p peer.ID, protocol string) (net.Stream, error) { if err != nil { return nil, err } - return nd.PeerHost.NewStream(pro.ID(protocol), p) + return nd.PeerHost.NewStream(nd.Context(), pro.ID(protocol), p) } diff --git a/core/corerepo/gc.go b/core/corerepo/gc.go index 75e859edbb4..6210f16e8a7 100644 --- a/core/corerepo/gc.go +++ b/core/corerepo/gc.go @@ -5,12 +5,12 @@ import ( "time" humanize "github.com/ipfs/go-ipfs/Godeps/_workspace/src/github.com/dustin/go-humanize" - context "github.com/ipfs/go-ipfs/Godeps/_workspace/src/golang.org/x/net/context" key "github.com/ipfs/go-ipfs/blocks/key" "github.com/ipfs/go-ipfs/core" gc "github.com/ipfs/go-ipfs/pin/gc" repo "github.com/ipfs/go-ipfs/repo" - logging "github.com/ipfs/go-ipfs/vendor/QmQg1J6vikuXF9oDvm4wpdeAUvvkVEKW1EYDw9HhTMnP2b/go-log" + context "gx/ipfs/QmZy2y8t9zQH2a1b8q2ZSLKp17ATuJoCNxxyMFG5qFExpt/go-net/context" + logging "gx/ipfs/Qmazh5oNUVsDZTs2g59rq8aYQqwpss8tcUWQzor5sCCEuH/go-log" ) var log = logging.Logger("corerepo") diff --git a/core/corerepo/pinning.go b/core/corerepo/pinning.go index 4cb1ec7f270..675ba834945 100644 --- a/core/corerepo/pinning.go +++ b/core/corerepo/pinning.go @@ -16,7 +16,7 @@ package corerepo import ( "fmt" - context "github.com/ipfs/go-ipfs/Godeps/_workspace/src/golang.org/x/net/context" + context "gx/ipfs/QmZy2y8t9zQH2a1b8q2ZSLKp17ATuJoCNxxyMFG5qFExpt/go-net/context" key "github.com/ipfs/go-ipfs/blocks/key" "github.com/ipfs/go-ipfs/core" diff --git a/core/corerouting/core.go b/core/corerouting/core.go index 6a97c0bf799..a26d73031c4 100644 --- a/core/corerouting/core.go +++ b/core/corerouting/core.go @@ -4,14 +4,14 @@ import ( "errors" ds "github.com/ipfs/go-ipfs/Godeps/_workspace/src/github.com/ipfs/go-datastore" - context "github.com/ipfs/go-ipfs/Godeps/_workspace/src/golang.org/x/net/context" core "github.com/ipfs/go-ipfs/core" - "github.com/ipfs/go-ipfs/p2p/host" - "github.com/ipfs/go-ipfs/p2p/peer" repo "github.com/ipfs/go-ipfs/repo" routing "github.com/ipfs/go-ipfs/routing" supernode "github.com/ipfs/go-ipfs/routing/supernode" gcproxy "github.com/ipfs/go-ipfs/routing/supernode/proxy" + "gx/ipfs/QmUBogf4nUefBjmYjn6jfsfPJRkmDGSeMhNj4usRKq69f4/go-libp2p/p2p/host" + "gx/ipfs/QmUBogf4nUefBjmYjn6jfsfPJRkmDGSeMhNj4usRKq69f4/go-libp2p/p2p/peer" + context "gx/ipfs/QmZy2y8t9zQH2a1b8q2ZSLKp17ATuJoCNxxyMFG5qFExpt/go-net/context" ) // NB: DHT option is included in the core to avoid 1) because it's a sane diff --git a/core/coreunix/add.go b/core/coreunix/add.go index d0619b6e680..a7f6951162c 100644 --- a/core/coreunix/add.go +++ b/core/coreunix/add.go @@ -10,7 +10,6 @@ import ( ds "github.com/ipfs/go-ipfs/Godeps/_workspace/src/github.com/ipfs/go-datastore" syncds "github.com/ipfs/go-ipfs/Godeps/_workspace/src/github.com/ipfs/go-datastore/sync" - context "github.com/ipfs/go-ipfs/Godeps/_workspace/src/golang.org/x/net/context" bstore "github.com/ipfs/go-ipfs/blocks/blockstore" key "github.com/ipfs/go-ipfs/blocks/key" bserv "github.com/ipfs/go-ipfs/blockservice" @@ -19,12 +18,13 @@ import ( "github.com/ipfs/go-ipfs/importer/chunk" mfs "github.com/ipfs/go-ipfs/mfs" "github.com/ipfs/go-ipfs/pin" + context "gx/ipfs/QmZy2y8t9zQH2a1b8q2ZSLKp17ATuJoCNxxyMFG5qFExpt/go-net/context" "github.com/ipfs/go-ipfs/commands/files" core "github.com/ipfs/go-ipfs/core" dag "github.com/ipfs/go-ipfs/merkledag" unixfs "github.com/ipfs/go-ipfs/unixfs" - logging "github.com/ipfs/go-ipfs/vendor/QmQg1J6vikuXF9oDvm4wpdeAUvvkVEKW1EYDw9HhTMnP2b/go-log" + logging "gx/ipfs/Qmazh5oNUVsDZTs2g59rq8aYQqwpss8tcUWQzor5sCCEuH/go-log" ) var log = logging.Logger("coreunix") diff --git a/core/coreunix/add_test.go b/core/coreunix/add_test.go index 56c921eebe0..f2b2b212d37 100644 --- a/core/coreunix/add_test.go +++ b/core/coreunix/add_test.go @@ -7,7 +7,6 @@ import ( "testing" "time" - "github.com/ipfs/go-ipfs/Godeps/_workspace/src/golang.org/x/net/context" "github.com/ipfs/go-ipfs/blocks/key" "github.com/ipfs/go-ipfs/commands/files" "github.com/ipfs/go-ipfs/core" @@ -16,6 +15,7 @@ import ( "github.com/ipfs/go-ipfs/repo" "github.com/ipfs/go-ipfs/repo/config" "github.com/ipfs/go-ipfs/util/testutil" + "gx/ipfs/QmZy2y8t9zQH2a1b8q2ZSLKp17ATuJoCNxxyMFG5qFExpt/go-net/context" ) func TestAddRecursive(t *testing.T) { diff --git a/core/coreunix/cat.go b/core/coreunix/cat.go index ca621e0611b..74119b0f4cb 100644 --- a/core/coreunix/cat.go +++ b/core/coreunix/cat.go @@ -1,10 +1,10 @@ package coreunix import ( - context "github.com/ipfs/go-ipfs/Godeps/_workspace/src/golang.org/x/net/context" core "github.com/ipfs/go-ipfs/core" path "github.com/ipfs/go-ipfs/path" uio "github.com/ipfs/go-ipfs/unixfs/io" + context "gx/ipfs/QmZy2y8t9zQH2a1b8q2ZSLKp17ATuJoCNxxyMFG5qFExpt/go-net/context" ) func Cat(ctx context.Context, n *core.IpfsNode, pstr string) (*uio.DagReader, error) { diff --git a/core/coreunix/metadata_test.go b/core/coreunix/metadata_test.go index bcd4855f264..b180927b26b 100644 --- a/core/coreunix/metadata_test.go +++ b/core/coreunix/metadata_test.go @@ -7,7 +7,7 @@ import ( ds "github.com/ipfs/go-ipfs/Godeps/_workspace/src/github.com/ipfs/go-datastore" dssync "github.com/ipfs/go-ipfs/Godeps/_workspace/src/github.com/ipfs/go-datastore/sync" - context "github.com/ipfs/go-ipfs/Godeps/_workspace/src/golang.org/x/net/context" + context "gx/ipfs/QmZy2y8t9zQH2a1b8q2ZSLKp17ATuJoCNxxyMFG5qFExpt/go-net/context" bstore "github.com/ipfs/go-ipfs/blocks/blockstore" key "github.com/ipfs/go-ipfs/blocks/key" diff --git a/core/mock/mock.go b/core/mock/mock.go index 74991477878..c9b3cea1054 100644 --- a/core/mock/mock.go +++ b/core/mock/mock.go @@ -5,18 +5,18 @@ import ( "github.com/ipfs/go-ipfs/Godeps/_workspace/src/github.com/ipfs/go-datastore" syncds "github.com/ipfs/go-ipfs/Godeps/_workspace/src/github.com/ipfs/go-datastore/sync" - context "github.com/ipfs/go-ipfs/Godeps/_workspace/src/golang.org/x/net/context" + context "gx/ipfs/QmZy2y8t9zQH2a1b8q2ZSLKp17ATuJoCNxxyMFG5qFExpt/go-net/context" commands "github.com/ipfs/go-ipfs/commands" core "github.com/ipfs/go-ipfs/core" - metrics "github.com/ipfs/go-ipfs/metrics" - host "github.com/ipfs/go-ipfs/p2p/host" - mocknet "github.com/ipfs/go-ipfs/p2p/net/mock" - peer "github.com/ipfs/go-ipfs/p2p/peer" "github.com/ipfs/go-ipfs/repo" config "github.com/ipfs/go-ipfs/repo/config" ds2 "github.com/ipfs/go-ipfs/util/datastore2" testutil "github.com/ipfs/go-ipfs/util/testutil" + host "gx/ipfs/QmUBogf4nUefBjmYjn6jfsfPJRkmDGSeMhNj4usRKq69f4/go-libp2p/p2p/host" + metrics "gx/ipfs/QmUBogf4nUefBjmYjn6jfsfPJRkmDGSeMhNj4usRKq69f4/go-libp2p/p2p/metrics" + mocknet "gx/ipfs/QmUBogf4nUefBjmYjn6jfsfPJRkmDGSeMhNj4usRKq69f4/go-libp2p/p2p/net/mock" + peer "gx/ipfs/QmUBogf4nUefBjmYjn6jfsfPJRkmDGSeMhNj4usRKq69f4/go-libp2p/p2p/peer" ) // NewMockNode constructs an IpfsNode for use in tests. diff --git a/core/pathresolver.go b/core/pathresolver.go index fce67b11d3d..dce650490a9 100644 --- a/core/pathresolver.go +++ b/core/pathresolver.go @@ -4,7 +4,7 @@ import ( "errors" "strings" - context "github.com/ipfs/go-ipfs/Godeps/_workspace/src/golang.org/x/net/context" + context "gx/ipfs/QmZy2y8t9zQH2a1b8q2ZSLKp17ATuJoCNxxyMFG5qFExpt/go-net/context" key "github.com/ipfs/go-ipfs/blocks/key" merkledag "github.com/ipfs/go-ipfs/merkledag" diff --git a/diagnostics/diag.go b/diagnostics/diag.go index 5ffa4ed9441..398322b6682 100644 --- a/diagnostics/diag.go +++ b/diagnostics/diag.go @@ -14,13 +14,13 @@ import ( ggio "github.com/ipfs/go-ipfs/Godeps/_workspace/src/github.com/gogo/protobuf/io" proto "github.com/ipfs/go-ipfs/Godeps/_workspace/src/github.com/gogo/protobuf/proto" ctxio "github.com/ipfs/go-ipfs/Godeps/_workspace/src/github.com/jbenet/go-context/io" - context "github.com/ipfs/go-ipfs/Godeps/_workspace/src/golang.org/x/net/context" pb "github.com/ipfs/go-ipfs/diagnostics/pb" - host "github.com/ipfs/go-ipfs/p2p/host" - inet "github.com/ipfs/go-ipfs/p2p/net" - peer "github.com/ipfs/go-ipfs/p2p/peer" - protocol "github.com/ipfs/go-ipfs/p2p/protocol" - logging "github.com/ipfs/go-ipfs/vendor/QmQg1J6vikuXF9oDvm4wpdeAUvvkVEKW1EYDw9HhTMnP2b/go-log" + host "gx/ipfs/QmUBogf4nUefBjmYjn6jfsfPJRkmDGSeMhNj4usRKq69f4/go-libp2p/p2p/host" + inet "gx/ipfs/QmUBogf4nUefBjmYjn6jfsfPJRkmDGSeMhNj4usRKq69f4/go-libp2p/p2p/net" + peer "gx/ipfs/QmUBogf4nUefBjmYjn6jfsfPJRkmDGSeMhNj4usRKq69f4/go-libp2p/p2p/peer" + protocol "gx/ipfs/QmUBogf4nUefBjmYjn6jfsfPJRkmDGSeMhNj4usRKq69f4/go-libp2p/p2p/protocol" + context "gx/ipfs/QmZy2y8t9zQH2a1b8q2ZSLKp17ATuJoCNxxyMFG5qFExpt/go-net/context" + logging "gx/ipfs/Qmazh5oNUVsDZTs2g59rq8aYQqwpss8tcUWQzor5sCCEuH/go-log" ) var log = logging.Logger("diagnostics") @@ -203,7 +203,7 @@ func (d *Diagnostics) getDiagnosticFromPeers(ctx context.Context, peers map[peer } func (d *Diagnostics) getDiagnosticFromPeer(ctx context.Context, p peer.ID, pmes *pb.Message) (<-chan *DiagInfo, error) { - s, err := d.host.NewStream(ProtocolDiag, p) + s, err := d.host.NewStream(ctx, ProtocolDiag, p) if err != nil { return nil, err } diff --git a/diagnostics/vis.go b/diagnostics/vis.go index b32609d2460..08e7224a44c 100644 --- a/diagnostics/vis.go +++ b/diagnostics/vis.go @@ -5,8 +5,8 @@ import ( "fmt" "io" - peer "github.com/ipfs/go-ipfs/p2p/peer" rtable "github.com/ipfs/go-ipfs/routing/kbucket" + peer "gx/ipfs/QmUBogf4nUefBjmYjn6jfsfPJRkmDGSeMhNj4usRKq69f4/go-libp2p/p2p/peer" ) type node struct { diff --git a/exchange/bitswap/bitswap.go b/exchange/bitswap/bitswap.go index 7d7954e47dd..17f4f36862f 100644 --- a/exchange/bitswap/bitswap.go +++ b/exchange/bitswap/bitswap.go @@ -10,7 +10,6 @@ import ( process "github.com/ipfs/go-ipfs/Godeps/_workspace/src/github.com/jbenet/goprocess" procctx "github.com/ipfs/go-ipfs/Godeps/_workspace/src/github.com/jbenet/goprocess/context" - context "github.com/ipfs/go-ipfs/Godeps/_workspace/src/golang.org/x/net/context" blocks "github.com/ipfs/go-ipfs/blocks" blockstore "github.com/ipfs/go-ipfs/blocks/blockstore" key "github.com/ipfs/go-ipfs/blocks/key" @@ -20,9 +19,10 @@ import ( bsnet "github.com/ipfs/go-ipfs/exchange/bitswap/network" notifications "github.com/ipfs/go-ipfs/exchange/bitswap/notifications" wantlist "github.com/ipfs/go-ipfs/exchange/bitswap/wantlist" - peer "github.com/ipfs/go-ipfs/p2p/peer" "github.com/ipfs/go-ipfs/thirdparty/delay" - logging "github.com/ipfs/go-ipfs/vendor/QmQg1J6vikuXF9oDvm4wpdeAUvvkVEKW1EYDw9HhTMnP2b/go-log" + peer "gx/ipfs/QmUBogf4nUefBjmYjn6jfsfPJRkmDGSeMhNj4usRKq69f4/go-libp2p/p2p/peer" + context "gx/ipfs/QmZy2y8t9zQH2a1b8q2ZSLKp17ATuJoCNxxyMFG5qFExpt/go-net/context" + logging "gx/ipfs/Qmazh5oNUVsDZTs2g59rq8aYQqwpss8tcUWQzor5sCCEuH/go-log" ) var log = logging.Logger("bitswap") diff --git a/exchange/bitswap/bitswap_test.go b/exchange/bitswap/bitswap_test.go index 3a2dba62f86..04a1fb7097d 100644 --- a/exchange/bitswap/bitswap_test.go +++ b/exchange/bitswap/bitswap_test.go @@ -7,16 +7,16 @@ import ( "time" detectrace "github.com/ipfs/go-ipfs/Godeps/_workspace/src/github.com/jbenet/go-detect-race" - context "github.com/ipfs/go-ipfs/Godeps/_workspace/src/golang.org/x/net/context" travis "github.com/ipfs/go-ipfs/util/testutil/ci/travis" + context "gx/ipfs/QmZy2y8t9zQH2a1b8q2ZSLKp17ATuJoCNxxyMFG5qFExpt/go-net/context" blocks "github.com/ipfs/go-ipfs/blocks" blocksutil "github.com/ipfs/go-ipfs/blocks/blocksutil" key "github.com/ipfs/go-ipfs/blocks/key" tn "github.com/ipfs/go-ipfs/exchange/bitswap/testnet" - p2ptestutil "github.com/ipfs/go-ipfs/p2p/test/util" mockrouting "github.com/ipfs/go-ipfs/routing/mock" delay "github.com/ipfs/go-ipfs/thirdparty/delay" + p2ptestutil "gx/ipfs/QmUBogf4nUefBjmYjn6jfsfPJRkmDGSeMhNj4usRKq69f4/go-libp2p/p2p/test/util" ) // FIXME the tests are really sensitive to the network delay. fix them to work diff --git a/exchange/bitswap/decision/bench_test.go b/exchange/bitswap/decision/bench_test.go index e64815338a0..7a230fa5786 100644 --- a/exchange/bitswap/decision/bench_test.go +++ b/exchange/bitswap/decision/bench_test.go @@ -6,8 +6,8 @@ import ( key "github.com/ipfs/go-ipfs/blocks/key" "github.com/ipfs/go-ipfs/exchange/bitswap/wantlist" - "github.com/ipfs/go-ipfs/p2p/peer" "github.com/ipfs/go-ipfs/util/testutil" + "gx/ipfs/QmUBogf4nUefBjmYjn6jfsfPJRkmDGSeMhNj4usRKq69f4/go-libp2p/p2p/peer" ) // FWIW: At the time of this commit, including a timestamp in task increases diff --git a/exchange/bitswap/decision/engine.go b/exchange/bitswap/decision/engine.go index 78e02dbd714..77c7f64283f 100644 --- a/exchange/bitswap/decision/engine.go +++ b/exchange/bitswap/decision/engine.go @@ -4,13 +4,13 @@ package decision import ( "sync" - context "github.com/ipfs/go-ipfs/Godeps/_workspace/src/golang.org/x/net/context" blocks "github.com/ipfs/go-ipfs/blocks" bstore "github.com/ipfs/go-ipfs/blocks/blockstore" bsmsg "github.com/ipfs/go-ipfs/exchange/bitswap/message" wl "github.com/ipfs/go-ipfs/exchange/bitswap/wantlist" - peer "github.com/ipfs/go-ipfs/p2p/peer" - logging "github.com/ipfs/go-ipfs/vendor/QmQg1J6vikuXF9oDvm4wpdeAUvvkVEKW1EYDw9HhTMnP2b/go-log" + peer "gx/ipfs/QmUBogf4nUefBjmYjn6jfsfPJRkmDGSeMhNj4usRKq69f4/go-libp2p/p2p/peer" + context "gx/ipfs/QmZy2y8t9zQH2a1b8q2ZSLKp17ATuJoCNxxyMFG5qFExpt/go-net/context" + logging "gx/ipfs/Qmazh5oNUVsDZTs2g59rq8aYQqwpss8tcUWQzor5sCCEuH/go-log" ) // TODO consider taking responsibility for other types of requests. For diff --git a/exchange/bitswap/decision/engine_test.go b/exchange/bitswap/decision/engine_test.go index d9e1fc202ab..53a660c7d23 100644 --- a/exchange/bitswap/decision/engine_test.go +++ b/exchange/bitswap/decision/engine_test.go @@ -10,12 +10,12 @@ import ( ds "github.com/ipfs/go-ipfs/Godeps/_workspace/src/github.com/ipfs/go-datastore" dssync "github.com/ipfs/go-ipfs/Godeps/_workspace/src/github.com/ipfs/go-datastore/sync" - context "github.com/ipfs/go-ipfs/Godeps/_workspace/src/golang.org/x/net/context" blocks "github.com/ipfs/go-ipfs/blocks" blockstore "github.com/ipfs/go-ipfs/blocks/blockstore" message "github.com/ipfs/go-ipfs/exchange/bitswap/message" - peer "github.com/ipfs/go-ipfs/p2p/peer" testutil "github.com/ipfs/go-ipfs/util/testutil" + peer "gx/ipfs/QmUBogf4nUefBjmYjn6jfsfPJRkmDGSeMhNj4usRKq69f4/go-libp2p/p2p/peer" + context "gx/ipfs/QmZy2y8t9zQH2a1b8q2ZSLKp17ATuJoCNxxyMFG5qFExpt/go-net/context" ) type peerAndEngine struct { diff --git a/exchange/bitswap/decision/ledger.go b/exchange/bitswap/decision/ledger.go index c0d1af8a50d..0cdd7e37bf5 100644 --- a/exchange/bitswap/decision/ledger.go +++ b/exchange/bitswap/decision/ledger.go @@ -5,7 +5,7 @@ import ( key "github.com/ipfs/go-ipfs/blocks/key" wl "github.com/ipfs/go-ipfs/exchange/bitswap/wantlist" - peer "github.com/ipfs/go-ipfs/p2p/peer" + peer "gx/ipfs/QmUBogf4nUefBjmYjn6jfsfPJRkmDGSeMhNj4usRKq69f4/go-libp2p/p2p/peer" ) // keySet is just a convenient alias for maps of keys, where we only care diff --git a/exchange/bitswap/decision/peer_request_queue.go b/exchange/bitswap/decision/peer_request_queue.go index 0ba74edafda..e0fc9198975 100644 --- a/exchange/bitswap/decision/peer_request_queue.go +++ b/exchange/bitswap/decision/peer_request_queue.go @@ -6,8 +6,8 @@ import ( key "github.com/ipfs/go-ipfs/blocks/key" wantlist "github.com/ipfs/go-ipfs/exchange/bitswap/wantlist" - peer "github.com/ipfs/go-ipfs/p2p/peer" pq "github.com/ipfs/go-ipfs/thirdparty/pq" + peer "gx/ipfs/QmUBogf4nUefBjmYjn6jfsfPJRkmDGSeMhNj4usRKq69f4/go-libp2p/p2p/peer" ) type peerRequestQueue interface { diff --git a/exchange/bitswap/message/message.go b/exchange/bitswap/message/message.go index 090970bd3ad..a0acf8d35d5 100644 --- a/exchange/bitswap/message/message.go +++ b/exchange/bitswap/message/message.go @@ -7,7 +7,7 @@ import ( key "github.com/ipfs/go-ipfs/blocks/key" pb "github.com/ipfs/go-ipfs/exchange/bitswap/message/pb" wantlist "github.com/ipfs/go-ipfs/exchange/bitswap/wantlist" - inet "github.com/ipfs/go-ipfs/p2p/net" + inet "gx/ipfs/QmUBogf4nUefBjmYjn6jfsfPJRkmDGSeMhNj4usRKq69f4/go-libp2p/p2p/net" ggio "github.com/ipfs/go-ipfs/Godeps/_workspace/src/github.com/gogo/protobuf/io" proto "github.com/ipfs/go-ipfs/Godeps/_workspace/src/github.com/gogo/protobuf/proto" diff --git a/exchange/bitswap/network/interface.go b/exchange/bitswap/network/interface.go index 35da0f84dc4..a81b5fcffab 100644 --- a/exchange/bitswap/network/interface.go +++ b/exchange/bitswap/network/interface.go @@ -1,11 +1,11 @@ package network import ( - context "github.com/ipfs/go-ipfs/Godeps/_workspace/src/golang.org/x/net/context" key "github.com/ipfs/go-ipfs/blocks/key" bsmsg "github.com/ipfs/go-ipfs/exchange/bitswap/message" - peer "github.com/ipfs/go-ipfs/p2p/peer" - protocol "github.com/ipfs/go-ipfs/p2p/protocol" + peer "gx/ipfs/QmUBogf4nUefBjmYjn6jfsfPJRkmDGSeMhNj4usRKq69f4/go-libp2p/p2p/peer" + protocol "gx/ipfs/QmUBogf4nUefBjmYjn6jfsfPJRkmDGSeMhNj4usRKq69f4/go-libp2p/p2p/protocol" + context "gx/ipfs/QmZy2y8t9zQH2a1b8q2ZSLKp17ATuJoCNxxyMFG5qFExpt/go-net/context" ) var ProtocolBitswap protocol.ID = "/ipfs/bitswap" diff --git a/exchange/bitswap/network/ipfs_impl.go b/exchange/bitswap/network/ipfs_impl.go index e97211f4849..b641b5e8f10 100644 --- a/exchange/bitswap/network/ipfs_impl.go +++ b/exchange/bitswap/network/ipfs_impl.go @@ -1,15 +1,15 @@ package network import ( - ma "github.com/ipfs/go-ipfs/Godeps/_workspace/src/github.com/jbenet/go-multiaddr" - context "github.com/ipfs/go-ipfs/Godeps/_workspace/src/golang.org/x/net/context" key "github.com/ipfs/go-ipfs/blocks/key" bsmsg "github.com/ipfs/go-ipfs/exchange/bitswap/message" - host "github.com/ipfs/go-ipfs/p2p/host" - inet "github.com/ipfs/go-ipfs/p2p/net" - peer "github.com/ipfs/go-ipfs/p2p/peer" routing "github.com/ipfs/go-ipfs/routing" - logging "github.com/ipfs/go-ipfs/vendor/QmQg1J6vikuXF9oDvm4wpdeAUvvkVEKW1EYDw9HhTMnP2b/go-log" + ma "gx/ipfs/QmR3JkmZBKYXgNMNsNZawm914455Qof3PEopwuVSeXG7aV/go-multiaddr" + host "gx/ipfs/QmUBogf4nUefBjmYjn6jfsfPJRkmDGSeMhNj4usRKq69f4/go-libp2p/p2p/host" + inet "gx/ipfs/QmUBogf4nUefBjmYjn6jfsfPJRkmDGSeMhNj4usRKq69f4/go-libp2p/p2p/net" + peer "gx/ipfs/QmUBogf4nUefBjmYjn6jfsfPJRkmDGSeMhNj4usRKq69f4/go-libp2p/p2p/peer" + context "gx/ipfs/QmZy2y8t9zQH2a1b8q2ZSLKp17ATuJoCNxxyMFG5qFExpt/go-net/context" + logging "gx/ipfs/Qmazh5oNUVsDZTs2g59rq8aYQqwpss8tcUWQzor5sCCEuH/go-log" ) var log = logging.Logger("bitswap_network") @@ -46,7 +46,7 @@ func (bsnet *impl) newStreamToPeer(ctx context.Context, p peer.ID) (inet.Stream, return nil, err } - return bsnet.host.NewStream(ProtocolBitswap, p) + return bsnet.host.NewStream(ctx, ProtocolBitswap, p) } func (bsnet *impl) SendMessage( diff --git a/exchange/bitswap/notifications/notifications.go b/exchange/bitswap/notifications/notifications.go index e9870940e42..8a83bba9b31 100644 --- a/exchange/bitswap/notifications/notifications.go +++ b/exchange/bitswap/notifications/notifications.go @@ -2,9 +2,9 @@ package notifications import ( pubsub "github.com/ipfs/go-ipfs/Godeps/_workspace/src/github.com/briantigerchow/pubsub" - context "github.com/ipfs/go-ipfs/Godeps/_workspace/src/golang.org/x/net/context" blocks "github.com/ipfs/go-ipfs/blocks" key "github.com/ipfs/go-ipfs/blocks/key" + context "gx/ipfs/QmZy2y8t9zQH2a1b8q2ZSLKp17ATuJoCNxxyMFG5qFExpt/go-net/context" ) const bufferSize = 16 diff --git a/exchange/bitswap/notifications/notifications_test.go b/exchange/bitswap/notifications/notifications_test.go index 96ed1c4e3f0..02acbd13fed 100644 --- a/exchange/bitswap/notifications/notifications_test.go +++ b/exchange/bitswap/notifications/notifications_test.go @@ -5,10 +5,10 @@ import ( "testing" "time" - context "github.com/ipfs/go-ipfs/Godeps/_workspace/src/golang.org/x/net/context" blocks "github.com/ipfs/go-ipfs/blocks" blocksutil "github.com/ipfs/go-ipfs/blocks/blocksutil" key "github.com/ipfs/go-ipfs/blocks/key" + context "gx/ipfs/QmZy2y8t9zQH2a1b8q2ZSLKp17ATuJoCNxxyMFG5qFExpt/go-net/context" ) func TestDuplicates(t *testing.T) { diff --git a/exchange/bitswap/testnet/interface.go b/exchange/bitswap/testnet/interface.go index b0d01b79f9b..f79af6d629f 100644 --- a/exchange/bitswap/testnet/interface.go +++ b/exchange/bitswap/testnet/interface.go @@ -2,8 +2,8 @@ package bitswap import ( bsnet "github.com/ipfs/go-ipfs/exchange/bitswap/network" - peer "github.com/ipfs/go-ipfs/p2p/peer" "github.com/ipfs/go-ipfs/util/testutil" + peer "gx/ipfs/QmUBogf4nUefBjmYjn6jfsfPJRkmDGSeMhNj4usRKq69f4/go-libp2p/p2p/peer" ) type Network interface { diff --git a/exchange/bitswap/testnet/network_test.go b/exchange/bitswap/testnet/network_test.go index 9624df5f8e8..69f1fa73efa 100644 --- a/exchange/bitswap/testnet/network_test.go +++ b/exchange/bitswap/testnet/network_test.go @@ -4,14 +4,14 @@ import ( "sync" "testing" - context "github.com/ipfs/go-ipfs/Godeps/_workspace/src/golang.org/x/net/context" blocks "github.com/ipfs/go-ipfs/blocks" bsmsg "github.com/ipfs/go-ipfs/exchange/bitswap/message" bsnet "github.com/ipfs/go-ipfs/exchange/bitswap/network" - peer "github.com/ipfs/go-ipfs/p2p/peer" mockrouting "github.com/ipfs/go-ipfs/routing/mock" delay "github.com/ipfs/go-ipfs/thirdparty/delay" testutil "github.com/ipfs/go-ipfs/util/testutil" + peer "gx/ipfs/QmUBogf4nUefBjmYjn6jfsfPJRkmDGSeMhNj4usRKq69f4/go-libp2p/p2p/peer" + context "gx/ipfs/QmZy2y8t9zQH2a1b8q2ZSLKp17ATuJoCNxxyMFG5qFExpt/go-net/context" ) func TestSendMessageAsyncButWaitForResponse(t *testing.T) { diff --git a/exchange/bitswap/testnet/peernet.go b/exchange/bitswap/testnet/peernet.go index 90f3412d214..8b0d7aabe0d 100644 --- a/exchange/bitswap/testnet/peernet.go +++ b/exchange/bitswap/testnet/peernet.go @@ -2,12 +2,12 @@ package bitswap import ( ds "github.com/ipfs/go-ipfs/Godeps/_workspace/src/github.com/ipfs/go-datastore" - context "github.com/ipfs/go-ipfs/Godeps/_workspace/src/golang.org/x/net/context" bsnet "github.com/ipfs/go-ipfs/exchange/bitswap/network" - mockpeernet "github.com/ipfs/go-ipfs/p2p/net/mock" - peer "github.com/ipfs/go-ipfs/p2p/peer" mockrouting "github.com/ipfs/go-ipfs/routing/mock" testutil "github.com/ipfs/go-ipfs/util/testutil" + mockpeernet "gx/ipfs/QmUBogf4nUefBjmYjn6jfsfPJRkmDGSeMhNj4usRKq69f4/go-libp2p/p2p/net/mock" + peer "gx/ipfs/QmUBogf4nUefBjmYjn6jfsfPJRkmDGSeMhNj4usRKq69f4/go-libp2p/p2p/peer" + context "gx/ipfs/QmZy2y8t9zQH2a1b8q2ZSLKp17ATuJoCNxxyMFG5qFExpt/go-net/context" ) type peernet struct { diff --git a/exchange/bitswap/testnet/virtual.go b/exchange/bitswap/testnet/virtual.go index eb342436606..b7b2e74724e 100644 --- a/exchange/bitswap/testnet/virtual.go +++ b/exchange/bitswap/testnet/virtual.go @@ -3,15 +3,15 @@ package bitswap import ( "errors" - context "github.com/ipfs/go-ipfs/Godeps/_workspace/src/golang.org/x/net/context" key "github.com/ipfs/go-ipfs/blocks/key" bsmsg "github.com/ipfs/go-ipfs/exchange/bitswap/message" bsnet "github.com/ipfs/go-ipfs/exchange/bitswap/network" - peer "github.com/ipfs/go-ipfs/p2p/peer" routing "github.com/ipfs/go-ipfs/routing" mockrouting "github.com/ipfs/go-ipfs/routing/mock" delay "github.com/ipfs/go-ipfs/thirdparty/delay" testutil "github.com/ipfs/go-ipfs/util/testutil" + peer "gx/ipfs/QmUBogf4nUefBjmYjn6jfsfPJRkmDGSeMhNj4usRKq69f4/go-libp2p/p2p/peer" + context "gx/ipfs/QmZy2y8t9zQH2a1b8q2ZSLKp17ATuJoCNxxyMFG5qFExpt/go-net/context" ) func VirtualNetwork(rs mockrouting.Server, d delay.D) Network { diff --git a/exchange/bitswap/testutils.go b/exchange/bitswap/testutils.go index f66a17e5051..8a886177193 100644 --- a/exchange/bitswap/testutils.go +++ b/exchange/bitswap/testutils.go @@ -5,14 +5,14 @@ import ( ds "github.com/ipfs/go-ipfs/Godeps/_workspace/src/github.com/ipfs/go-datastore" ds_sync "github.com/ipfs/go-ipfs/Godeps/_workspace/src/github.com/ipfs/go-datastore/sync" - context "github.com/ipfs/go-ipfs/Godeps/_workspace/src/golang.org/x/net/context" blockstore "github.com/ipfs/go-ipfs/blocks/blockstore" tn "github.com/ipfs/go-ipfs/exchange/bitswap/testnet" - peer "github.com/ipfs/go-ipfs/p2p/peer" - p2ptestutil "github.com/ipfs/go-ipfs/p2p/test/util" delay "github.com/ipfs/go-ipfs/thirdparty/delay" datastore2 "github.com/ipfs/go-ipfs/util/datastore2" testutil "github.com/ipfs/go-ipfs/util/testutil" + peer "gx/ipfs/QmUBogf4nUefBjmYjn6jfsfPJRkmDGSeMhNj4usRKq69f4/go-libp2p/p2p/peer" + p2ptestutil "gx/ipfs/QmUBogf4nUefBjmYjn6jfsfPJRkmDGSeMhNj4usRKq69f4/go-libp2p/p2p/test/util" + context "gx/ipfs/QmZy2y8t9zQH2a1b8q2ZSLKp17ATuJoCNxxyMFG5qFExpt/go-net/context" ) // WARNING: this uses RandTestBogusIdentity DO NOT USE for NON TESTS! diff --git a/exchange/bitswap/wantmanager.go b/exchange/bitswap/wantmanager.go index 2fae23515a2..243edac3707 100644 --- a/exchange/bitswap/wantmanager.go +++ b/exchange/bitswap/wantmanager.go @@ -4,13 +4,13 @@ import ( "sync" "time" - context "github.com/ipfs/go-ipfs/Godeps/_workspace/src/golang.org/x/net/context" key "github.com/ipfs/go-ipfs/blocks/key" engine "github.com/ipfs/go-ipfs/exchange/bitswap/decision" bsmsg "github.com/ipfs/go-ipfs/exchange/bitswap/message" bsnet "github.com/ipfs/go-ipfs/exchange/bitswap/network" wantlist "github.com/ipfs/go-ipfs/exchange/bitswap/wantlist" - peer "github.com/ipfs/go-ipfs/p2p/peer" + peer "gx/ipfs/QmUBogf4nUefBjmYjn6jfsfPJRkmDGSeMhNj4usRKq69f4/go-libp2p/p2p/peer" + context "gx/ipfs/QmZy2y8t9zQH2a1b8q2ZSLKp17ATuJoCNxxyMFG5qFExpt/go-net/context" ) type WantManager struct { diff --git a/exchange/bitswap/workers.go b/exchange/bitswap/workers.go index 0c8b8de5d1e..b9dc963bedd 100644 --- a/exchange/bitswap/workers.go +++ b/exchange/bitswap/workers.go @@ -5,10 +5,10 @@ import ( process "github.com/ipfs/go-ipfs/Godeps/_workspace/src/github.com/jbenet/goprocess" procctx "github.com/ipfs/go-ipfs/Godeps/_workspace/src/github.com/jbenet/goprocess/context" - context "github.com/ipfs/go-ipfs/Godeps/_workspace/src/golang.org/x/net/context" + context "gx/ipfs/QmZy2y8t9zQH2a1b8q2ZSLKp17ATuJoCNxxyMFG5qFExpt/go-net/context" key "github.com/ipfs/go-ipfs/blocks/key" - logging "github.com/ipfs/go-ipfs/vendor/QmQg1J6vikuXF9oDvm4wpdeAUvvkVEKW1EYDw9HhTMnP2b/go-log" + logging "gx/ipfs/Qmazh5oNUVsDZTs2g59rq8aYQqwpss8tcUWQzor5sCCEuH/go-log" ) var TaskWorkerCount = 8 diff --git a/exchange/interface.go b/exchange/interface.go index 05f52a64b79..dbc66e3b679 100644 --- a/exchange/interface.go +++ b/exchange/interface.go @@ -4,9 +4,9 @@ package exchange import ( "io" - context "github.com/ipfs/go-ipfs/Godeps/_workspace/src/golang.org/x/net/context" blocks "github.com/ipfs/go-ipfs/blocks" key "github.com/ipfs/go-ipfs/blocks/key" + context "gx/ipfs/QmZy2y8t9zQH2a1b8q2ZSLKp17ATuJoCNxxyMFG5qFExpt/go-net/context" ) // Any type that implements exchange.Interface may be used as an IPFS block diff --git a/exchange/offline/offline.go b/exchange/offline/offline.go index 9a448906e7c..8f857d93318 100644 --- a/exchange/offline/offline.go +++ b/exchange/offline/offline.go @@ -3,11 +3,11 @@ package offline import ( - context "github.com/ipfs/go-ipfs/Godeps/_workspace/src/golang.org/x/net/context" blocks "github.com/ipfs/go-ipfs/blocks" "github.com/ipfs/go-ipfs/blocks/blockstore" key "github.com/ipfs/go-ipfs/blocks/key" exchange "github.com/ipfs/go-ipfs/exchange" + context "gx/ipfs/QmZy2y8t9zQH2a1b8q2ZSLKp17ATuJoCNxxyMFG5qFExpt/go-net/context" ) func Exchange(bs blockstore.Blockstore) exchange.Interface { diff --git a/exchange/offline/offline_test.go b/exchange/offline/offline_test.go index 0a4787f071b..d7d17341e93 100644 --- a/exchange/offline/offline_test.go +++ b/exchange/offline/offline_test.go @@ -5,11 +5,11 @@ import ( ds "github.com/ipfs/go-ipfs/Godeps/_workspace/src/github.com/ipfs/go-datastore" ds_sync "github.com/ipfs/go-ipfs/Godeps/_workspace/src/github.com/ipfs/go-datastore/sync" - context "github.com/ipfs/go-ipfs/Godeps/_workspace/src/golang.org/x/net/context" blocks "github.com/ipfs/go-ipfs/blocks" "github.com/ipfs/go-ipfs/blocks/blockstore" "github.com/ipfs/go-ipfs/blocks/blocksutil" key "github.com/ipfs/go-ipfs/blocks/key" + context "gx/ipfs/QmZy2y8t9zQH2a1b8q2ZSLKp17ATuJoCNxxyMFG5qFExpt/go-net/context" ) func TestBlockReturnsErr(t *testing.T) { diff --git a/exchange/reprovide/reprovide.go b/exchange/reprovide/reprovide.go index 51daf6f1963..ca027b4aff5 100644 --- a/exchange/reprovide/reprovide.go +++ b/exchange/reprovide/reprovide.go @@ -5,10 +5,10 @@ import ( "time" backoff "github.com/ipfs/go-ipfs/Godeps/_workspace/src/github.com/cenkalti/backoff" - context "github.com/ipfs/go-ipfs/Godeps/_workspace/src/golang.org/x/net/context" blocks "github.com/ipfs/go-ipfs/blocks/blockstore" routing "github.com/ipfs/go-ipfs/routing" - logging "github.com/ipfs/go-ipfs/vendor/QmQg1J6vikuXF9oDvm4wpdeAUvvkVEKW1EYDw9HhTMnP2b/go-log" + context "gx/ipfs/QmZy2y8t9zQH2a1b8q2ZSLKp17ATuJoCNxxyMFG5qFExpt/go-net/context" + logging "gx/ipfs/Qmazh5oNUVsDZTs2g59rq8aYQqwpss8tcUWQzor5sCCEuH/go-log" ) var log = logging.Logger("reprovider") diff --git a/exchange/reprovide/reprovide_test.go b/exchange/reprovide/reprovide_test.go index eebdee76563..ea49ed93217 100644 --- a/exchange/reprovide/reprovide_test.go +++ b/exchange/reprovide/reprovide_test.go @@ -5,11 +5,11 @@ import ( ds "github.com/ipfs/go-ipfs/Godeps/_workspace/src/github.com/ipfs/go-datastore" dssync "github.com/ipfs/go-ipfs/Godeps/_workspace/src/github.com/ipfs/go-datastore/sync" - context "github.com/ipfs/go-ipfs/Godeps/_workspace/src/golang.org/x/net/context" blocks "github.com/ipfs/go-ipfs/blocks" blockstore "github.com/ipfs/go-ipfs/blocks/blockstore" mock "github.com/ipfs/go-ipfs/routing/mock" testutil "github.com/ipfs/go-ipfs/util/testutil" + context "gx/ipfs/QmZy2y8t9zQH2a1b8q2ZSLKp17ATuJoCNxxyMFG5qFExpt/go-net/context" . "github.com/ipfs/go-ipfs/exchange/reprovide" ) diff --git a/fuse/ipns/common.go b/fuse/ipns/common.go index 2ec4c7fb157..cb32058dd4d 100644 --- a/fuse/ipns/common.go +++ b/fuse/ipns/common.go @@ -1,14 +1,14 @@ package ipns import ( - context "github.com/ipfs/go-ipfs/Godeps/_workspace/src/golang.org/x/net/context" + context "gx/ipfs/QmZy2y8t9zQH2a1b8q2ZSLKp17ATuJoCNxxyMFG5qFExpt/go-net/context" "github.com/ipfs/go-ipfs/core" mdag "github.com/ipfs/go-ipfs/merkledag" nsys "github.com/ipfs/go-ipfs/namesys" - ci "github.com/ipfs/go-ipfs/p2p/crypto" path "github.com/ipfs/go-ipfs/path" ft "github.com/ipfs/go-ipfs/unixfs" + ci "gx/ipfs/QmUBogf4nUefBjmYjn6jfsfPJRkmDGSeMhNj4usRKq69f4/go-libp2p/p2p/crypto" ) // InitializeKeyspace sets the ipns record for the given key to diff --git a/fuse/ipns/ipns_test.go b/fuse/ipns/ipns_test.go index c5f8d6a7389..df11624cecd 100644 --- a/fuse/ipns/ipns_test.go +++ b/fuse/ipns/ipns_test.go @@ -14,8 +14,8 @@ import ( fstest "github.com/ipfs/go-ipfs/Godeps/_workspace/src/bazil.org/fuse/fs/fstestutil" racedet "github.com/ipfs/go-ipfs/Godeps/_workspace/src/github.com/jbenet/go-detect-race" - context "github.com/ipfs/go-ipfs/Godeps/_workspace/src/golang.org/x/net/context" core "github.com/ipfs/go-ipfs/core" + context "gx/ipfs/QmZy2y8t9zQH2a1b8q2ZSLKp17ATuJoCNxxyMFG5qFExpt/go-net/context" //mfs "github.com/ipfs/go-ipfs/mfs" namesys "github.com/ipfs/go-ipfs/namesys" offroute "github.com/ipfs/go-ipfs/routing/offline" diff --git a/fuse/ipns/ipns_unix.go b/fuse/ipns/ipns_unix.go index bd4b861e065..c9ccfe27140 100644 --- a/fuse/ipns/ipns_unix.go +++ b/fuse/ipns/ipns_unix.go @@ -11,16 +11,16 @@ import ( fuse "github.com/ipfs/go-ipfs/Godeps/_workspace/src/bazil.org/fuse" fs "github.com/ipfs/go-ipfs/Godeps/_workspace/src/bazil.org/fuse/fs" - "github.com/ipfs/go-ipfs/Godeps/_workspace/src/golang.org/x/net/context" - logging "github.com/ipfs/go-ipfs/vendor/QmQg1J6vikuXF9oDvm4wpdeAUvvkVEKW1EYDw9HhTMnP2b/go-log" + "gx/ipfs/QmZy2y8t9zQH2a1b8q2ZSLKp17ATuJoCNxxyMFG5qFExpt/go-net/context" + logging "gx/ipfs/Qmazh5oNUVsDZTs2g59rq8aYQqwpss8tcUWQzor5sCCEuH/go-log" key "github.com/ipfs/go-ipfs/blocks/key" core "github.com/ipfs/go-ipfs/core" dag "github.com/ipfs/go-ipfs/merkledag" mfs "github.com/ipfs/go-ipfs/mfs" - ci "github.com/ipfs/go-ipfs/p2p/crypto" path "github.com/ipfs/go-ipfs/path" ft "github.com/ipfs/go-ipfs/unixfs" + ci "gx/ipfs/QmUBogf4nUefBjmYjn6jfsfPJRkmDGSeMhNj4usRKq69f4/go-libp2p/p2p/crypto" ) var log = logging.Logger("fuse/ipns") diff --git a/fuse/ipns/link_unix.go b/fuse/ipns/link_unix.go index d45ce02836f..0c9b9e8511a 100644 --- a/fuse/ipns/link_unix.go +++ b/fuse/ipns/link_unix.go @@ -7,7 +7,7 @@ import ( "github.com/ipfs/go-ipfs/Godeps/_workspace/src/bazil.org/fuse" "github.com/ipfs/go-ipfs/Godeps/_workspace/src/bazil.org/fuse/fs" - "github.com/ipfs/go-ipfs/Godeps/_workspace/src/golang.org/x/net/context" + "gx/ipfs/QmZy2y8t9zQH2a1b8q2ZSLKp17ATuJoCNxxyMFG5qFExpt/go-net/context" ) type Link struct { diff --git a/fuse/mount/mount.go b/fuse/mount/mount.go index a732f679260..4404fa6e762 100644 --- a/fuse/mount/mount.go +++ b/fuse/mount/mount.go @@ -10,7 +10,7 @@ import ( goprocess "github.com/ipfs/go-ipfs/Godeps/_workspace/src/github.com/jbenet/goprocess" - logging "github.com/ipfs/go-ipfs/vendor/QmQg1J6vikuXF9oDvm4wpdeAUvvkVEKW1EYDw9HhTMnP2b/go-log" + logging "gx/ipfs/Qmazh5oNUVsDZTs2g59rq8aYQqwpss8tcUWQzor5sCCEuH/go-log" ) var log = logging.Logger("mount") diff --git a/fuse/readonly/readonly_unix.go b/fuse/readonly/readonly_unix.go index ac55359477b..7384e62c7d1 100644 --- a/fuse/readonly/readonly_unix.go +++ b/fuse/readonly/readonly_unix.go @@ -12,14 +12,14 @@ import ( fuse "github.com/ipfs/go-ipfs/Godeps/_workspace/src/bazil.org/fuse" fs "github.com/ipfs/go-ipfs/Godeps/_workspace/src/bazil.org/fuse/fs" proto "github.com/ipfs/go-ipfs/Godeps/_workspace/src/github.com/gogo/protobuf/proto" - "github.com/ipfs/go-ipfs/Godeps/_workspace/src/golang.org/x/net/context" core "github.com/ipfs/go-ipfs/core" mdag "github.com/ipfs/go-ipfs/merkledag" path "github.com/ipfs/go-ipfs/path" uio "github.com/ipfs/go-ipfs/unixfs/io" ftpb "github.com/ipfs/go-ipfs/unixfs/pb" lgbl "github.com/ipfs/go-ipfs/util/eventlog/loggables" - logging "github.com/ipfs/go-ipfs/vendor/QmQg1J6vikuXF9oDvm4wpdeAUvvkVEKW1EYDw9HhTMnP2b/go-log" + "gx/ipfs/QmZy2y8t9zQH2a1b8q2ZSLKp17ATuJoCNxxyMFG5qFExpt/go-net/context" + logging "gx/ipfs/Qmazh5oNUVsDZTs2g59rq8aYQqwpss8tcUWQzor5sCCEuH/go-log" ) var log = logging.Logger("fuse/ipfs") diff --git a/importer/balanced/balanced_test.go b/importer/balanced/balanced_test.go index b47fa0f9918..2182615c5fd 100644 --- a/importer/balanced/balanced_test.go +++ b/importer/balanced/balanced_test.go @@ -9,7 +9,6 @@ import ( "os" "testing" - "github.com/ipfs/go-ipfs/Godeps/_workspace/src/golang.org/x/net/context" chunk "github.com/ipfs/go-ipfs/importer/chunk" h "github.com/ipfs/go-ipfs/importer/helpers" dag "github.com/ipfs/go-ipfs/merkledag" @@ -17,6 +16,7 @@ import ( pin "github.com/ipfs/go-ipfs/pin" uio "github.com/ipfs/go-ipfs/unixfs/io" u "github.com/ipfs/go-ipfs/util" + "gx/ipfs/QmZy2y8t9zQH2a1b8q2ZSLKp17ATuJoCNxxyMFG5qFExpt/go-net/context" ) // TODO: extract these tests and more as a generic layout test suite diff --git a/importer/chunk/splitting.go b/importer/chunk/splitting.go index a2f1dac4f46..3b539fe7bf9 100644 --- a/importer/chunk/splitting.go +++ b/importer/chunk/splitting.go @@ -4,7 +4,7 @@ package chunk import ( "io" - logging "github.com/ipfs/go-ipfs/vendor/QmQg1J6vikuXF9oDvm4wpdeAUvvkVEKW1EYDw9HhTMnP2b/go-log" + logging "gx/ipfs/Qmazh5oNUVsDZTs2g59rq8aYQqwpss8tcUWQzor5sCCEuH/go-log" ) var log = logging.Logger("chunk") diff --git a/importer/helpers/helpers.go b/importer/helpers/helpers.go index 5c76cfdbe80..29983795c5f 100644 --- a/importer/helpers/helpers.go +++ b/importer/helpers/helpers.go @@ -3,10 +3,10 @@ package helpers import ( "fmt" - "github.com/ipfs/go-ipfs/Godeps/_workspace/src/golang.org/x/net/context" chunk "github.com/ipfs/go-ipfs/importer/chunk" dag "github.com/ipfs/go-ipfs/merkledag" ft "github.com/ipfs/go-ipfs/unixfs" + "gx/ipfs/QmZy2y8t9zQH2a1b8q2ZSLKp17ATuJoCNxxyMFG5qFExpt/go-net/context" ) // BlockSizeLimit specifies the maximum size an imported block can have. diff --git a/importer/importer.go b/importer/importer.go index d63773191ce..d8b063d99dc 100644 --- a/importer/importer.go +++ b/importer/importer.go @@ -12,7 +12,7 @@ import ( h "github.com/ipfs/go-ipfs/importer/helpers" trickle "github.com/ipfs/go-ipfs/importer/trickle" dag "github.com/ipfs/go-ipfs/merkledag" - logging "github.com/ipfs/go-ipfs/vendor/QmQg1J6vikuXF9oDvm4wpdeAUvvkVEKW1EYDw9HhTMnP2b/go-log" + logging "gx/ipfs/Qmazh5oNUVsDZTs2g59rq8aYQqwpss8tcUWQzor5sCCEuH/go-log" ) var log = logging.Logger("importer") diff --git a/importer/importer_test.go b/importer/importer_test.go index c41156f22c1..306e6221966 100644 --- a/importer/importer_test.go +++ b/importer/importer_test.go @@ -6,12 +6,12 @@ import ( "io/ioutil" "testing" - context "github.com/ipfs/go-ipfs/Godeps/_workspace/src/golang.org/x/net/context" chunk "github.com/ipfs/go-ipfs/importer/chunk" dag "github.com/ipfs/go-ipfs/merkledag" mdtest "github.com/ipfs/go-ipfs/merkledag/test" uio "github.com/ipfs/go-ipfs/unixfs/io" u "github.com/ipfs/go-ipfs/util" + context "gx/ipfs/QmZy2y8t9zQH2a1b8q2ZSLKp17ATuJoCNxxyMFG5qFExpt/go-net/context" ) func getBalancedDag(t testing.TB, size int64, blksize int64) (*dag.Node, dag.DAGService) { diff --git a/importer/trickle/trickle_test.go b/importer/trickle/trickle_test.go index 6b1e0f3468b..9581907ffd6 100644 --- a/importer/trickle/trickle_test.go +++ b/importer/trickle/trickle_test.go @@ -9,7 +9,6 @@ import ( "os" "testing" - "github.com/ipfs/go-ipfs/Godeps/_workspace/src/golang.org/x/net/context" chunk "github.com/ipfs/go-ipfs/importer/chunk" h "github.com/ipfs/go-ipfs/importer/helpers" merkledag "github.com/ipfs/go-ipfs/merkledag" @@ -18,6 +17,7 @@ import ( ft "github.com/ipfs/go-ipfs/unixfs" uio "github.com/ipfs/go-ipfs/unixfs/io" u "github.com/ipfs/go-ipfs/util" + "gx/ipfs/QmZy2y8t9zQH2a1b8q2ZSLKp17ATuJoCNxxyMFG5qFExpt/go-net/context" ) func buildTestDag(ds merkledag.DAGService, spl chunk.Splitter) (*merkledag.Node, error) { diff --git a/importer/trickle/trickledag.go b/importer/trickle/trickledag.go index 1b37e1d1d2a..8955568da10 100644 --- a/importer/trickle/trickledag.go +++ b/importer/trickle/trickledag.go @@ -3,7 +3,7 @@ package trickle import ( "errors" - context "github.com/ipfs/go-ipfs/Godeps/_workspace/src/golang.org/x/net/context" + context "gx/ipfs/QmZy2y8t9zQH2a1b8q2ZSLKp17ATuJoCNxxyMFG5qFExpt/go-net/context" h "github.com/ipfs/go-ipfs/importer/helpers" dag "github.com/ipfs/go-ipfs/merkledag" diff --git a/merkledag/merkledag.go b/merkledag/merkledag.go index b84327dfdf3..e324ceb883a 100644 --- a/merkledag/merkledag.go +++ b/merkledag/merkledag.go @@ -4,11 +4,11 @@ package merkledag import ( "fmt" - "github.com/ipfs/go-ipfs/Godeps/_workspace/src/golang.org/x/net/context" blocks "github.com/ipfs/go-ipfs/blocks" key "github.com/ipfs/go-ipfs/blocks/key" bserv "github.com/ipfs/go-ipfs/blockservice" - logging "github.com/ipfs/go-ipfs/vendor/QmQg1J6vikuXF9oDvm4wpdeAUvvkVEKW1EYDw9HhTMnP2b/go-log" + "gx/ipfs/QmZy2y8t9zQH2a1b8q2ZSLKp17ATuJoCNxxyMFG5qFExpt/go-net/context" + logging "gx/ipfs/Qmazh5oNUVsDZTs2g59rq8aYQqwpss8tcUWQzor5sCCEuH/go-log" ) var log = logging.Logger("merkledag") diff --git a/merkledag/merkledag_test.go b/merkledag/merkledag_test.go index 1df3182d40d..d9622082e03 100644 --- a/merkledag/merkledag_test.go +++ b/merkledag/merkledag_test.go @@ -12,7 +12,6 @@ import ( ds "github.com/ipfs/go-ipfs/Godeps/_workspace/src/github.com/ipfs/go-datastore" dssync "github.com/ipfs/go-ipfs/Godeps/_workspace/src/github.com/ipfs/go-datastore/sync" - "github.com/ipfs/go-ipfs/Godeps/_workspace/src/golang.org/x/net/context" bstore "github.com/ipfs/go-ipfs/blocks/blockstore" key "github.com/ipfs/go-ipfs/blocks/key" bserv "github.com/ipfs/go-ipfs/blockservice" @@ -24,6 +23,7 @@ import ( "github.com/ipfs/go-ipfs/pin" uio "github.com/ipfs/go-ipfs/unixfs/io" u "github.com/ipfs/go-ipfs/util" + "gx/ipfs/QmZy2y8t9zQH2a1b8q2ZSLKp17ATuJoCNxxyMFG5qFExpt/go-net/context" ) type dagservAndPinner struct { diff --git a/merkledag/node.go b/merkledag/node.go index b644cae1216..c5e1c4e33cd 100644 --- a/merkledag/node.go +++ b/merkledag/node.go @@ -3,7 +3,7 @@ package merkledag import ( "fmt" - "github.com/ipfs/go-ipfs/Godeps/_workspace/src/golang.org/x/net/context" + "gx/ipfs/QmZy2y8t9zQH2a1b8q2ZSLKp17ATuJoCNxxyMFG5qFExpt/go-net/context" mh "github.com/ipfs/go-ipfs/Godeps/_workspace/src/github.com/jbenet/go-multihash" key "github.com/ipfs/go-ipfs/blocks/key" diff --git a/merkledag/traverse/traverse.go b/merkledag/traverse/traverse.go index aa71ad2f2bc..d0735461734 100644 --- a/merkledag/traverse/traverse.go +++ b/merkledag/traverse/traverse.go @@ -4,7 +4,7 @@ package traverse import ( "errors" - "github.com/ipfs/go-ipfs/Godeps/_workspace/src/golang.org/x/net/context" + "gx/ipfs/QmZy2y8t9zQH2a1b8q2ZSLKp17ATuJoCNxxyMFG5qFExpt/go-net/context" mdag "github.com/ipfs/go-ipfs/merkledag" ) diff --git a/merkledag/utils/diff.go b/merkledag/utils/diff.go index 8ee50819c53..3237ad913c1 100644 --- a/merkledag/utils/diff.go +++ b/merkledag/utils/diff.go @@ -5,9 +5,9 @@ import ( "fmt" "path" - context "github.com/ipfs/go-ipfs/Godeps/_workspace/src/golang.org/x/net/context" key "github.com/ipfs/go-ipfs/blocks/key" dag "github.com/ipfs/go-ipfs/merkledag" + context "gx/ipfs/QmZy2y8t9zQH2a1b8q2ZSLKp17ATuJoCNxxyMFG5qFExpt/go-net/context" ) const ( diff --git a/merkledag/utils/utils.go b/merkledag/utils/utils.go index 3536e35cce1..231397fe355 100644 --- a/merkledag/utils/utils.go +++ b/merkledag/utils/utils.go @@ -5,7 +5,7 @@ import ( ds "github.com/ipfs/go-ipfs/Godeps/_workspace/src/github.com/ipfs/go-datastore" syncds "github.com/ipfs/go-ipfs/Godeps/_workspace/src/github.com/ipfs/go-datastore/sync" - context "github.com/ipfs/go-ipfs/Godeps/_workspace/src/golang.org/x/net/context" + context "gx/ipfs/QmZy2y8t9zQH2a1b8q2ZSLKp17ATuJoCNxxyMFG5qFExpt/go-net/context" bstore "github.com/ipfs/go-ipfs/blocks/blockstore" bserv "github.com/ipfs/go-ipfs/blockservice" diff --git a/merkledag/utils/utils_test.go b/merkledag/utils/utils_test.go index d4b2af5f3d4..b225a3dfff3 100644 --- a/merkledag/utils/utils_test.go +++ b/merkledag/utils/utils_test.go @@ -8,7 +8,7 @@ import ( mdtest "github.com/ipfs/go-ipfs/merkledag/test" path "github.com/ipfs/go-ipfs/path" - context "github.com/ipfs/go-ipfs/Godeps/_workspace/src/golang.org/x/net/context" + context "gx/ipfs/QmZy2y8t9zQH2a1b8q2ZSLKp17ATuJoCNxxyMFG5qFExpt/go-net/context" ) func TestAddLink(t *testing.T) { diff --git a/metrics/bw_stats.go b/metrics/bw_stats.go deleted file mode 100644 index 4c28ddffc22..00000000000 --- a/metrics/bw_stats.go +++ /dev/null @@ -1,89 +0,0 @@ -package metrics - -import ( - gm "github.com/ipfs/go-ipfs/Godeps/_workspace/src/github.com/whyrusleeping/go-metrics" - "sync" - - peer "github.com/ipfs/go-ipfs/p2p/peer" - protocol "github.com/ipfs/go-ipfs/p2p/protocol" -) - -type Stats struct { - TotalIn int64 - TotalOut int64 - RateIn float64 - RateOut float64 -} - -type BandwidthCounter struct { - lock sync.Mutex - totalIn gm.Meter - totalOut gm.Meter - reg gm.Registry -} - -func NewBandwidthCounter() *BandwidthCounter { - reg := gm.NewRegistry() - return &BandwidthCounter{ - totalIn: gm.GetOrRegisterMeter("totalIn", reg), - totalOut: gm.GetOrRegisterMeter("totalOut", reg), - reg: reg, - } -} - -func (bwc *BandwidthCounter) LogSentMessage(size int64) { - bwc.totalOut.Mark(size) -} - -func (bwc *BandwidthCounter) LogRecvMessage(size int64) { - bwc.totalIn.Mark(size) -} - -func (bwc *BandwidthCounter) LogSentMessageStream(size int64, proto protocol.ID, p peer.ID) { - meter := gm.GetOrRegisterMeter("/peer/out/"+string(p), bwc.reg) - meter.Mark(size) - - pmeter := gm.GetOrRegisterMeter("/proto/out/"+string(proto), bwc.reg) - pmeter.Mark(size) -} - -func (bwc *BandwidthCounter) LogRecvMessageStream(size int64, proto protocol.ID, p peer.ID) { - meter := gm.GetOrRegisterMeter("/peer/in/"+string(p), bwc.reg) - meter.Mark(size) - - pmeter := gm.GetOrRegisterMeter("/proto/in/"+string(proto), bwc.reg) - pmeter.Mark(size) -} - -func (bwc *BandwidthCounter) GetBandwidthForPeer(p peer.ID) (out Stats) { - inMeter := gm.GetOrRegisterMeter("/peer/in/"+string(p), bwc.reg).Snapshot() - outMeter := gm.GetOrRegisterMeter("/peer/out/"+string(p), bwc.reg).Snapshot() - - return Stats{ - TotalIn: inMeter.Count(), - TotalOut: outMeter.Count(), - RateIn: inMeter.RateFine(), - RateOut: outMeter.RateFine(), - } -} - -func (bwc *BandwidthCounter) GetBandwidthForProtocol(proto protocol.ID) (out Stats) { - inMeter := gm.GetOrRegisterMeter(string("/proto/in/"+proto), bwc.reg).Snapshot() - outMeter := gm.GetOrRegisterMeter(string("/proto/out/"+proto), bwc.reg).Snapshot() - - return Stats{ - TotalIn: inMeter.Count(), - TotalOut: outMeter.Count(), - RateIn: inMeter.RateFine(), - RateOut: outMeter.RateFine(), - } -} - -func (bwc *BandwidthCounter) GetBandwidthTotals() (out Stats) { - return Stats{ - TotalIn: bwc.totalIn.Count(), - TotalOut: bwc.totalOut.Count(), - RateIn: bwc.totalIn.RateFine(), - RateOut: bwc.totalOut.RateFine(), - } -} diff --git a/metrics/conn/conn.go b/metrics/conn/conn.go deleted file mode 100644 index d209745923d..00000000000 --- a/metrics/conn/conn.go +++ /dev/null @@ -1,39 +0,0 @@ -package meterconn - -import ( - metrics "github.com/ipfs/go-ipfs/metrics" - transport "github.com/ipfs/go-ipfs/p2p/net/transport" -) - -type MeteredConn struct { - mesRecv metrics.MeterCallback - mesSent metrics.MeterCallback - - transport.Conn -} - -func WrapConn(bwc metrics.Reporter, c transport.Conn) transport.Conn { - return newMeteredConn(c, bwc.LogRecvMessage, bwc.LogSentMessage) -} - -func newMeteredConn(base transport.Conn, rcb metrics.MeterCallback, scb metrics.MeterCallback) transport.Conn { - return &MeteredConn{ - Conn: base, - mesRecv: rcb, - mesSent: scb, - } -} - -func (mc *MeteredConn) Read(b []byte) (int, error) { - n, err := mc.Conn.Read(b) - - mc.mesRecv(int64(n)) - return n, err -} - -func (mc *MeteredConn) Write(b []byte) (int, error) { - n, err := mc.Conn.Write(b) - - mc.mesSent(int64(n)) - return n, err -} diff --git a/metrics/interface.go b/metrics/interface.go deleted file mode 100644 index b9e1af91cc0..00000000000 --- a/metrics/interface.go +++ /dev/null @@ -1,19 +0,0 @@ -package metrics - -import ( - peer "github.com/ipfs/go-ipfs/p2p/peer" - protocol "github.com/ipfs/go-ipfs/p2p/protocol" -) - -type StreamMeterCallback func(int64, protocol.ID, peer.ID) -type MeterCallback func(int64) - -type Reporter interface { - LogSentMessage(int64) - LogRecvMessage(int64) - LogSentMessageStream(int64, protocol.ID, peer.ID) - LogRecvMessageStream(int64, protocol.ID, peer.ID) - GetBandwidthForPeer(peer.ID) Stats - GetBandwidthForProtocol(protocol.ID) Stats - GetBandwidthTotals() Stats -} diff --git a/metrics/stream/metered.go b/metrics/stream/metered.go deleted file mode 100644 index b24f55a56e8..00000000000 --- a/metrics/stream/metered.go +++ /dev/null @@ -1,52 +0,0 @@ -package meterstream - -import ( - metrics "github.com/ipfs/go-ipfs/metrics" - inet "github.com/ipfs/go-ipfs/p2p/net" - peer "github.com/ipfs/go-ipfs/p2p/peer" - protocol "github.com/ipfs/go-ipfs/p2p/protocol" -) - -type meteredStream struct { - // keys for accessing metrics data - protoKey protocol.ID - peerKey peer.ID - - inet.Stream - - // callbacks for reporting bandwidth usage - mesSent metrics.StreamMeterCallback - mesRecv metrics.StreamMeterCallback -} - -func newMeteredStream(base inet.Stream, pid protocol.ID, p peer.ID, recvCB, sentCB metrics.StreamMeterCallback) inet.Stream { - return &meteredStream{ - Stream: base, - mesSent: sentCB, - mesRecv: recvCB, - protoKey: pid, - peerKey: p, - } -} - -func WrapStream(base inet.Stream, pid protocol.ID, bwc metrics.Reporter) inet.Stream { - return newMeteredStream(base, pid, base.Conn().RemotePeer(), bwc.LogRecvMessageStream, bwc.LogSentMessageStream) -} - -func (s *meteredStream) Read(b []byte) (int, error) { - n, err := s.Stream.Read(b) - - // Log bytes read - s.mesRecv(int64(n), s.protoKey, s.peerKey) - - return n, err -} - -func (s *meteredStream) Write(b []byte) (int, error) { - n, err := s.Stream.Write(b) - - // Log bytes written - s.mesSent(int64(n), s.protoKey, s.peerKey) - - return n, err -} diff --git a/metrics/stream/metered_test.go b/metrics/stream/metered_test.go deleted file mode 100644 index eaefcfa00f1..00000000000 --- a/metrics/stream/metered_test.go +++ /dev/null @@ -1,74 +0,0 @@ -package meterstream - -import ( - "io" - "io/ioutil" - "testing" - - inet "github.com/ipfs/go-ipfs/p2p/net" - peer "github.com/ipfs/go-ipfs/p2p/peer" - protocol "github.com/ipfs/go-ipfs/p2p/protocol" - u "github.com/ipfs/go-ipfs/util" -) - -type FakeStream struct { - ReadBuf io.Reader - inet.Stream -} - -func (fs *FakeStream) Read(b []byte) (int, error) { - return fs.ReadBuf.Read(b) -} - -func (fs *FakeStream) Write(b []byte) (int, error) { - return len(b), nil -} - -func TestCallbacksWork(t *testing.T) { - fake := new(FakeStream) - - var sent int64 - var recv int64 - - sentCB := func(n int64, proto protocol.ID, p peer.ID) { - sent += n - } - - recvCB := func(n int64, proto protocol.ID, p peer.ID) { - recv += n - } - - ms := newMeteredStream(fake, protocol.ID("TEST"), peer.ID("PEER"), recvCB, sentCB) - - toWrite := int64(100000) - toRead := int64(100000) - - fake.ReadBuf = io.LimitReader(u.NewTimeSeededRand(), toRead) - writeData := io.LimitReader(u.NewTimeSeededRand(), toWrite) - - n, err := io.Copy(ms, writeData) - if err != nil { - t.Fatal(err) - } - - if n != toWrite { - t.Fatal("incorrect write amount") - } - - if toWrite != sent { - t.Fatal("incorrectly reported writes", toWrite, sent) - } - - n, err = io.Copy(ioutil.Discard, ms) - if err != nil { - t.Fatal(err) - } - - if n != toRead { - t.Fatal("incorrect read amount") - } - - if toRead != recv { - t.Fatal("incorrectly reported reads") - } -} diff --git a/mfs/dir.go b/mfs/dir.go index 15b4ea777ec..28d9f730684 100644 --- a/mfs/dir.go +++ b/mfs/dir.go @@ -8,7 +8,7 @@ import ( "sync" "time" - context "github.com/ipfs/go-ipfs/Godeps/_workspace/src/golang.org/x/net/context" + context "gx/ipfs/QmZy2y8t9zQH2a1b8q2ZSLKp17ATuJoCNxxyMFG5qFExpt/go-net/context" dag "github.com/ipfs/go-ipfs/merkledag" ft "github.com/ipfs/go-ipfs/unixfs" diff --git a/mfs/file.go b/mfs/file.go index 15aecb805e9..da473714065 100644 --- a/mfs/file.go +++ b/mfs/file.go @@ -7,7 +7,7 @@ import ( dag "github.com/ipfs/go-ipfs/merkledag" mod "github.com/ipfs/go-ipfs/unixfs/mod" - context "github.com/ipfs/go-ipfs/Godeps/_workspace/src/golang.org/x/net/context" + context "gx/ipfs/QmZy2y8t9zQH2a1b8q2ZSLKp17ATuJoCNxxyMFG5qFExpt/go-net/context" ) type File struct { diff --git a/mfs/mfs_test.go b/mfs/mfs_test.go index ff6c9d03c67..917845f5afa 100644 --- a/mfs/mfs_test.go +++ b/mfs/mfs_test.go @@ -14,8 +14,8 @@ import ( randbo "github.com/ipfs/go-ipfs/Godeps/_workspace/src/github.com/dustin/randbo" ds "github.com/ipfs/go-ipfs/Godeps/_workspace/src/github.com/ipfs/go-datastore" dssync "github.com/ipfs/go-ipfs/Godeps/_workspace/src/github.com/ipfs/go-datastore/sync" - "github.com/ipfs/go-ipfs/Godeps/_workspace/src/golang.org/x/net/context" "github.com/ipfs/go-ipfs/path" + "gx/ipfs/QmZy2y8t9zQH2a1b8q2ZSLKp17ATuJoCNxxyMFG5qFExpt/go-net/context" bstore "github.com/ipfs/go-ipfs/blocks/blockstore" key "github.com/ipfs/go-ipfs/blocks/key" diff --git a/mfs/repub_test.go b/mfs/repub_test.go index 36db90e8051..4ba7bae4fb0 100644 --- a/mfs/repub_test.go +++ b/mfs/repub_test.go @@ -7,7 +7,7 @@ import ( key "github.com/ipfs/go-ipfs/blocks/key" ci "github.com/ipfs/go-ipfs/util/testutil/ci" - "github.com/ipfs/go-ipfs/Godeps/_workspace/src/golang.org/x/net/context" + "gx/ipfs/QmZy2y8t9zQH2a1b8q2ZSLKp17ATuJoCNxxyMFG5qFExpt/go-net/context" ) func TestRepublisher(t *testing.T) { diff --git a/mfs/system.go b/mfs/system.go index d3e70527390..c059bf5ce5a 100644 --- a/mfs/system.go +++ b/mfs/system.go @@ -18,8 +18,8 @@ import ( dag "github.com/ipfs/go-ipfs/merkledag" ft "github.com/ipfs/go-ipfs/unixfs" - context "github.com/ipfs/go-ipfs/Godeps/_workspace/src/golang.org/x/net/context" - logging "github.com/ipfs/go-ipfs/vendor/QmQg1J6vikuXF9oDvm4wpdeAUvvkVEKW1EYDw9HhTMnP2b/go-log" + context "gx/ipfs/QmZy2y8t9zQH2a1b8q2ZSLKp17ATuJoCNxxyMFG5qFExpt/go-net/context" + logging "gx/ipfs/Qmazh5oNUVsDZTs2g59rq8aYQqwpss8tcUWQzor5sCCEuH/go-log" ) var ErrNotExist = errors.New("no such rootfs") diff --git a/namesys/base.go b/namesys/base.go index e552fce464a..569cb4bb373 100644 --- a/namesys/base.go +++ b/namesys/base.go @@ -3,7 +3,7 @@ package namesys import ( "strings" - context "github.com/ipfs/go-ipfs/Godeps/_workspace/src/golang.org/x/net/context" + context "gx/ipfs/QmZy2y8t9zQH2a1b8q2ZSLKp17ATuJoCNxxyMFG5qFExpt/go-net/context" path "github.com/ipfs/go-ipfs/path" ) diff --git a/namesys/dns.go b/namesys/dns.go index a02a73ad8c5..bb9ebdfb31c 100644 --- a/namesys/dns.go +++ b/namesys/dns.go @@ -6,7 +6,7 @@ import ( "strings" isd "github.com/ipfs/go-ipfs/Godeps/_workspace/src/github.com/jbenet/go-is-domain" - context "github.com/ipfs/go-ipfs/Godeps/_workspace/src/golang.org/x/net/context" + context "gx/ipfs/QmZy2y8t9zQH2a1b8q2ZSLKp17ATuJoCNxxyMFG5qFExpt/go-net/context" path "github.com/ipfs/go-ipfs/path" ) diff --git a/namesys/interface.go b/namesys/interface.go index 09c296c23af..68933bfe05d 100644 --- a/namesys/interface.go +++ b/namesys/interface.go @@ -33,9 +33,9 @@ import ( "errors" "time" - context "github.com/ipfs/go-ipfs/Godeps/_workspace/src/golang.org/x/net/context" - ci "github.com/ipfs/go-ipfs/p2p/crypto" path "github.com/ipfs/go-ipfs/path" + ci "gx/ipfs/QmUBogf4nUefBjmYjn6jfsfPJRkmDGSeMhNj4usRKq69f4/go-libp2p/p2p/crypto" + context "gx/ipfs/QmZy2y8t9zQH2a1b8q2ZSLKp17ATuJoCNxxyMFG5qFExpt/go-net/context" ) const ( diff --git a/namesys/ipns_select_test.go b/namesys/ipns_select_test.go index ebd81e86d64..beeb0ac7c9b 100644 --- a/namesys/ipns_select_test.go +++ b/namesys/ipns_select_test.go @@ -9,9 +9,9 @@ import ( proto "github.com/ipfs/go-ipfs/Godeps/_workspace/src/github.com/gogo/protobuf/proto" pb "github.com/ipfs/go-ipfs/namesys/pb" - ci "github.com/ipfs/go-ipfs/p2p/crypto" path "github.com/ipfs/go-ipfs/path" u "github.com/ipfs/go-ipfs/util" + ci "gx/ipfs/QmUBogf4nUefBjmYjn6jfsfPJRkmDGSeMhNj4usRKq69f4/go-libp2p/p2p/crypto" ) func shuffle(a []*pb.IpnsEntry) { diff --git a/namesys/namesys.go b/namesys/namesys.go index 6dea9864e6c..b9c75388182 100644 --- a/namesys/namesys.go +++ b/namesys/namesys.go @@ -5,10 +5,10 @@ import ( "time" ds "github.com/ipfs/go-ipfs/Godeps/_workspace/src/github.com/ipfs/go-datastore" - context "github.com/ipfs/go-ipfs/Godeps/_workspace/src/golang.org/x/net/context" - ci "github.com/ipfs/go-ipfs/p2p/crypto" path "github.com/ipfs/go-ipfs/path" routing "github.com/ipfs/go-ipfs/routing" + ci "gx/ipfs/QmUBogf4nUefBjmYjn6jfsfPJRkmDGSeMhNj4usRKq69f4/go-libp2p/p2p/crypto" + context "gx/ipfs/QmZy2y8t9zQH2a1b8q2ZSLKp17ATuJoCNxxyMFG5qFExpt/go-net/context" ) // mpns (a multi-protocol NameSystem) implements generic IPFS naming. diff --git a/namesys/namesys_test.go b/namesys/namesys_test.go index 256228c3e65..f44f17ef5a6 100644 --- a/namesys/namesys_test.go +++ b/namesys/namesys_test.go @@ -4,7 +4,7 @@ import ( "fmt" "testing" - context "github.com/ipfs/go-ipfs/Godeps/_workspace/src/golang.org/x/net/context" + context "gx/ipfs/QmZy2y8t9zQH2a1b8q2ZSLKp17ATuJoCNxxyMFG5qFExpt/go-net/context" path "github.com/ipfs/go-ipfs/path" ) diff --git a/namesys/proquint.go b/namesys/proquint.go index 2ad3275a4ad..ce17181e83f 100644 --- a/namesys/proquint.go +++ b/namesys/proquint.go @@ -4,8 +4,8 @@ import ( "errors" proquint "github.com/ipfs/go-ipfs/Godeps/_workspace/src/github.com/bren2010/proquint" - context "github.com/ipfs/go-ipfs/Godeps/_workspace/src/golang.org/x/net/context" path "github.com/ipfs/go-ipfs/path" + context "gx/ipfs/QmZy2y8t9zQH2a1b8q2ZSLKp17ATuJoCNxxyMFG5qFExpt/go-net/context" ) type ProquintResolver struct{} diff --git a/namesys/publisher.go b/namesys/publisher.go index 1197d7217fe..981814f52d2 100644 --- a/namesys/publisher.go +++ b/namesys/publisher.go @@ -8,13 +8,11 @@ import ( proto "github.com/ipfs/go-ipfs/Godeps/_workspace/src/github.com/gogo/protobuf/proto" ds "github.com/ipfs/go-ipfs/Godeps/_workspace/src/github.com/ipfs/go-datastore" - context "github.com/ipfs/go-ipfs/Godeps/_workspace/src/golang.org/x/net/context" + context "gx/ipfs/QmZy2y8t9zQH2a1b8q2ZSLKp17ATuJoCNxxyMFG5qFExpt/go-net/context" key "github.com/ipfs/go-ipfs/blocks/key" dag "github.com/ipfs/go-ipfs/merkledag" pb "github.com/ipfs/go-ipfs/namesys/pb" - ci "github.com/ipfs/go-ipfs/p2p/crypto" - peer "github.com/ipfs/go-ipfs/p2p/peer" path "github.com/ipfs/go-ipfs/path" pin "github.com/ipfs/go-ipfs/pin" routing "github.com/ipfs/go-ipfs/routing" @@ -22,6 +20,8 @@ import ( record "github.com/ipfs/go-ipfs/routing/record" ft "github.com/ipfs/go-ipfs/unixfs" u "github.com/ipfs/go-ipfs/util" + ci "gx/ipfs/QmUBogf4nUefBjmYjn6jfsfPJRkmDGSeMhNj4usRKq69f4/go-libp2p/p2p/crypto" + peer "gx/ipfs/QmUBogf4nUefBjmYjn6jfsfPJRkmDGSeMhNj4usRKq69f4/go-libp2p/p2p/peer" ) // ErrExpiredRecord should be returned when an ipns record is diff --git a/namesys/republisher/repub.go b/namesys/republisher/repub.go index 11b47d0f1e5..37d4d19e23c 100644 --- a/namesys/republisher/repub.go +++ b/namesys/republisher/repub.go @@ -8,17 +8,17 @@ import ( key "github.com/ipfs/go-ipfs/blocks/key" namesys "github.com/ipfs/go-ipfs/namesys" pb "github.com/ipfs/go-ipfs/namesys/pb" - peer "github.com/ipfs/go-ipfs/p2p/peer" path "github.com/ipfs/go-ipfs/path" "github.com/ipfs/go-ipfs/routing" dhtpb "github.com/ipfs/go-ipfs/routing/dht/pb" + peer "gx/ipfs/QmUBogf4nUefBjmYjn6jfsfPJRkmDGSeMhNj4usRKq69f4/go-libp2p/p2p/peer" proto "github.com/ipfs/go-ipfs/Godeps/_workspace/src/github.com/gogo/protobuf/proto" ds "github.com/ipfs/go-ipfs/Godeps/_workspace/src/github.com/ipfs/go-datastore" goprocess "github.com/ipfs/go-ipfs/Godeps/_workspace/src/github.com/jbenet/goprocess" gpctx "github.com/ipfs/go-ipfs/Godeps/_workspace/src/github.com/jbenet/goprocess/context" - context "github.com/ipfs/go-ipfs/Godeps/_workspace/src/golang.org/x/net/context" - logging "github.com/ipfs/go-ipfs/vendor/QmQg1J6vikuXF9oDvm4wpdeAUvvkVEKW1EYDw9HhTMnP2b/go-log" + context "gx/ipfs/QmZy2y8t9zQH2a1b8q2ZSLKp17ATuJoCNxxyMFG5qFExpt/go-net/context" + logging "gx/ipfs/Qmazh5oNUVsDZTs2g59rq8aYQqwpss8tcUWQzor5sCCEuH/go-log" ) var errNoEntry = errors.New("no previous entry") diff --git a/namesys/republisher/repub_test.go b/namesys/republisher/repub_test.go index 92c224a738e..a56111874eb 100644 --- a/namesys/republisher/repub_test.go +++ b/namesys/republisher/repub_test.go @@ -6,15 +6,15 @@ import ( "time" goprocess "github.com/ipfs/go-ipfs/Godeps/_workspace/src/github.com/jbenet/goprocess" - context "github.com/ipfs/go-ipfs/Godeps/_workspace/src/golang.org/x/net/context" + context "gx/ipfs/QmZy2y8t9zQH2a1b8q2ZSLKp17ATuJoCNxxyMFG5qFExpt/go-net/context" "github.com/ipfs/go-ipfs/core" mock "github.com/ipfs/go-ipfs/core/mock" namesys "github.com/ipfs/go-ipfs/namesys" . "github.com/ipfs/go-ipfs/namesys/republisher" - mocknet "github.com/ipfs/go-ipfs/p2p/net/mock" - peer "github.com/ipfs/go-ipfs/p2p/peer" path "github.com/ipfs/go-ipfs/path" + mocknet "gx/ipfs/QmUBogf4nUefBjmYjn6jfsfPJRkmDGSeMhNj4usRKq69f4/go-libp2p/p2p/net/mock" + peer "gx/ipfs/QmUBogf4nUefBjmYjn6jfsfPJRkmDGSeMhNj4usRKq69f4/go-libp2p/p2p/peer" ) func TestRepublish(t *testing.T) { diff --git a/namesys/resolve_test.go b/namesys/resolve_test.go index 219efda0f26..ff1b27f540c 100644 --- a/namesys/resolve_test.go +++ b/namesys/resolve_test.go @@ -6,13 +6,13 @@ import ( "time" ds "github.com/ipfs/go-ipfs/Godeps/_workspace/src/github.com/ipfs/go-datastore" - context "github.com/ipfs/go-ipfs/Godeps/_workspace/src/golang.org/x/net/context" key "github.com/ipfs/go-ipfs/blocks/key" - peer "github.com/ipfs/go-ipfs/p2p/peer" path "github.com/ipfs/go-ipfs/path" mockrouting "github.com/ipfs/go-ipfs/routing/mock" u "github.com/ipfs/go-ipfs/util" testutil "github.com/ipfs/go-ipfs/util/testutil" + peer "gx/ipfs/QmUBogf4nUefBjmYjn6jfsfPJRkmDGSeMhNj4usRKq69f4/go-libp2p/p2p/peer" + context "gx/ipfs/QmZy2y8t9zQH2a1b8q2ZSLKp17ATuJoCNxxyMFG5qFExpt/go-net/context" ) func TestRoutingResolve(t *testing.T) { diff --git a/namesys/routing.go b/namesys/routing.go index a288f75576d..933bdd041b7 100644 --- a/namesys/routing.go +++ b/namesys/routing.go @@ -7,15 +7,15 @@ import ( proto "github.com/ipfs/go-ipfs/Godeps/_workspace/src/github.com/gogo/protobuf/proto" lru "github.com/ipfs/go-ipfs/Godeps/_workspace/src/github.com/hashicorp/golang-lru" mh "github.com/ipfs/go-ipfs/Godeps/_workspace/src/github.com/jbenet/go-multihash" - "github.com/ipfs/go-ipfs/Godeps/_workspace/src/golang.org/x/net/context" + "gx/ipfs/QmZy2y8t9zQH2a1b8q2ZSLKp17ATuJoCNxxyMFG5qFExpt/go-net/context" key "github.com/ipfs/go-ipfs/blocks/key" pb "github.com/ipfs/go-ipfs/namesys/pb" - ci "github.com/ipfs/go-ipfs/p2p/crypto" path "github.com/ipfs/go-ipfs/path" routing "github.com/ipfs/go-ipfs/routing" u "github.com/ipfs/go-ipfs/util" - logging "github.com/ipfs/go-ipfs/vendor/QmQg1J6vikuXF9oDvm4wpdeAUvvkVEKW1EYDw9HhTMnP2b/go-log" + ci "gx/ipfs/QmUBogf4nUefBjmYjn6jfsfPJRkmDGSeMhNj4usRKq69f4/go-libp2p/p2p/crypto" + logging "gx/ipfs/Qmazh5oNUVsDZTs2g59rq8aYQqwpss8tcUWQzor5sCCEuH/go-log" ) var log = logging.Logger("namesys") diff --git a/notifications/query.go b/notifications/query.go index 6a9d08da320..5679476df3f 100644 --- a/notifications/query.go +++ b/notifications/query.go @@ -3,8 +3,8 @@ package notifications import ( "encoding/json" - context "github.com/ipfs/go-ipfs/Godeps/_workspace/src/golang.org/x/net/context" - peer "github.com/ipfs/go-ipfs/p2p/peer" + peer "gx/ipfs/QmUBogf4nUefBjmYjn6jfsfPJRkmDGSeMhNj4usRKq69f4/go-libp2p/p2p/peer" + context "gx/ipfs/QmZy2y8t9zQH2a1b8q2ZSLKp17ATuJoCNxxyMFG5qFExpt/go-net/context" ) const RoutingQueryKey = "RoutingQueryEvent" diff --git a/p2p/crypto/bench_test.go b/p2p/crypto/bench_test.go deleted file mode 100644 index 7a3818a7c95..00000000000 --- a/p2p/crypto/bench_test.go +++ /dev/null @@ -1,54 +0,0 @@ -package crypto - -import "testing" - -func BenchmarkSign1B(b *testing.B) { RunBenchmarkSign(b, 1) } -func BenchmarkSign10B(b *testing.B) { RunBenchmarkSign(b, 10) } -func BenchmarkSign100B(b *testing.B) { RunBenchmarkSign(b, 100) } -func BenchmarkSign1000B(b *testing.B) { RunBenchmarkSign(b, 1000) } -func BenchmarkSign10000B(b *testing.B) { RunBenchmarkSign(b, 10000) } -func BenchmarkSign100000B(b *testing.B) { RunBenchmarkSign(b, 100000) } - -func BenchmarkVerify1B(b *testing.B) { RunBenchmarkVerify(b, 1) } -func BenchmarkVerify10B(b *testing.B) { RunBenchmarkVerify(b, 10) } -func BenchmarkVerify100B(b *testing.B) { RunBenchmarkVerify(b, 100) } -func BenchmarkVerify1000B(b *testing.B) { RunBenchmarkVerify(b, 1000) } -func BenchmarkVerify10000B(b *testing.B) { RunBenchmarkVerify(b, 10000) } -func BenchmarkVerify100000B(b *testing.B) { RunBenchmarkVerify(b, 100000) } - -func RunBenchmarkSign(b *testing.B, numBytes int) { - secret, _, err := GenerateKeyPair(RSA, 1024) - if err != nil { - b.Fatal(err) - } - someData := make([]byte, numBytes) - b.ResetTimer() - for i := 0; i < b.N; i++ { - _, err := secret.Sign(someData) - if err != nil { - b.Fatal(err) - } - } -} - -func RunBenchmarkVerify(b *testing.B, numBytes int) { - secret, public, err := GenerateKeyPair(RSA, 1024) - if err != nil { - b.Fatal(err) - } - someData := make([]byte, numBytes) - signature, err := secret.Sign(someData) - if err != nil { - b.Fatal(err) - } - b.ResetTimer() - for i := 0; i < b.N; i++ { - valid, err := public.Verify(someData, signature) - if err != nil { - b.Fatal(err) - } - if !valid { - b.Fatal("signature should be valid") - } - } -} diff --git a/p2p/crypto/key.go b/p2p/crypto/key.go deleted file mode 100644 index 7c7fa7b1da9..00000000000 --- a/p2p/crypto/key.go +++ /dev/null @@ -1,316 +0,0 @@ -// package crypto implements various cryptographic utilities used by ipfs. -// This includes a Public and Private key interface and an RSA key implementation -// that satisfies it. -package crypto - -import ( - "bytes" - "encoding/base64" - "errors" - "fmt" - "io" - - "crypto/elliptic" - "crypto/hmac" - "crypto/rand" - "crypto/rsa" - "crypto/sha1" - "crypto/sha256" - "crypto/sha512" - "hash" - - proto "github.com/ipfs/go-ipfs/Godeps/_workspace/src/github.com/gogo/protobuf/proto" - - pb "github.com/ipfs/go-ipfs/p2p/crypto/pb" - u "github.com/ipfs/go-ipfs/util" - logging "github.com/ipfs/go-ipfs/vendor/QmQg1J6vikuXF9oDvm4wpdeAUvvkVEKW1EYDw9HhTMnP2b/go-log" -) - -var log = logging.Logger("crypto") - -var ErrBadKeyType = errors.New("invalid or unsupported key type") - -const ( - RSA = iota -) - -// Key represents a crypto key that can be compared to another key -type Key interface { - // Bytes returns a serialized, storeable representation of this key - Bytes() ([]byte, error) - - // Hash returns the hash of this key - Hash() ([]byte, error) - - // Equals checks whether two PubKeys are the same - Equals(Key) bool -} - -// PrivKey represents a private key that can be used to generate a public key, -// sign data, and decrypt data that was encrypted with a public key -type PrivKey interface { - Key - - // Cryptographically sign the given bytes - Sign([]byte) ([]byte, error) - - // Return a public key paired with this private key - GetPublic() PubKey - - // Generate a secret string of bytes - GenSecret() []byte - - Decrypt(b []byte) ([]byte, error) -} - -type PubKey interface { - Key - - // Verify that 'sig' is the signed hash of 'data' - Verify(data []byte, sig []byte) (bool, error) - - // Encrypt data in a way that can be decrypted by a paired private key - Encrypt(data []byte) ([]byte, error) -} - -// Given a public key, generates the shared key. -type GenSharedKey func([]byte) ([]byte, error) - -func GenerateKeyPair(typ, bits int) (PrivKey, PubKey, error) { - return GenerateKeyPairWithReader(typ, bits, rand.Reader) -} - -// Generates a keypair of the given type and bitsize -func GenerateKeyPairWithReader(typ, bits int, src io.Reader) (PrivKey, PubKey, error) { - switch typ { - case RSA: - priv, err := rsa.GenerateKey(src, bits) - if err != nil { - return nil, nil, err - } - pk := &priv.PublicKey - return &RsaPrivateKey{sk: priv}, &RsaPublicKey{pk}, nil - default: - return nil, nil, ErrBadKeyType - } -} - -// Generates an ephemeral public key and returns a function that will compute -// the shared secret key. Used in the identify module. -// -// Focuses only on ECDH now, but can be made more general in the future. -func GenerateEKeyPair(curveName string) ([]byte, GenSharedKey, error) { - var curve elliptic.Curve - - switch curveName { - case "P-256": - curve = elliptic.P256() - case "P-384": - curve = elliptic.P384() - case "P-521": - curve = elliptic.P521() - } - - priv, x, y, err := elliptic.GenerateKey(curve, rand.Reader) - if err != nil { - return nil, nil, err - } - - pubKey := elliptic.Marshal(curve, x, y) - // log.Debug("GenerateEKeyPair %d", len(pubKey)) - - done := func(theirPub []byte) ([]byte, error) { - // Verify and unpack node's public key. - x, y := elliptic.Unmarshal(curve, theirPub) - if x == nil { - return nil, fmt.Errorf("Malformed public key: %d %v", len(theirPub), theirPub) - } - - if !curve.IsOnCurve(x, y) { - return nil, errors.New("Invalid public key.") - } - - // Generate shared secret. - secret, _ := curve.ScalarMult(x, y, priv) - - return secret.Bytes(), nil - } - - return pubKey, done, nil -} - -type StretchedKeys struct { - IV []byte - MacKey []byte - CipherKey []byte -} - -// Generates a set of keys for each party by stretching the shared key. -// (myIV, theirIV, myCipherKey, theirCipherKey, myMACKey, theirMACKey) -func KeyStretcher(cipherType string, hashType string, secret []byte) (StretchedKeys, StretchedKeys) { - var cipherKeySize int - var ivSize int - switch cipherType { - case "AES-128": - ivSize = 16 - cipherKeySize = 16 - case "AES-256": - ivSize = 16 - cipherKeySize = 32 - case "Blowfish": - ivSize = 8 - // Note: 24 arbitrarily selected, needs more thought - cipherKeySize = 32 - } - - hmacKeySize := 20 - - seed := []byte("key expansion") - - result := make([]byte, 2*(ivSize+cipherKeySize+hmacKeySize)) - - var h func() hash.Hash - - switch hashType { - case "SHA1": - h = sha1.New - case "SHA256": - h = sha256.New - case "SHA512": - h = sha512.New - default: - panic("Unrecognized hash function, programmer error?") - } - - m := hmac.New(h, secret) - m.Write(seed) - - a := m.Sum(nil) - - j := 0 - for j < len(result) { - m.Reset() - m.Write(a) - m.Write(seed) - b := m.Sum(nil) - - todo := len(b) - - if j+todo > len(result) { - todo = len(result) - j - } - - copy(result[j:j+todo], b) - - j += todo - - m.Reset() - m.Write(a) - a = m.Sum(nil) - } - - half := len(result) / 2 - r1 := result[:half] - r2 := result[half:] - - var k1 StretchedKeys - var k2 StretchedKeys - - k1.IV = r1[:ivSize] - k1.CipherKey = r1[ivSize : ivSize+cipherKeySize] - k1.MacKey = r1[ivSize+cipherKeySize:] - - k2.IV = r2[:ivSize] - k2.CipherKey = r2[ivSize : ivSize+cipherKeySize] - k2.MacKey = r2[ivSize+cipherKeySize:] - - return k1, k2 -} - -// UnmarshalPublicKey converts a protobuf serialized public key into its -// representative object -func UnmarshalPublicKey(data []byte) (PubKey, error) { - pmes := new(pb.PublicKey) - err := proto.Unmarshal(data, pmes) - if err != nil { - return nil, err - } - - switch pmes.GetType() { - case pb.KeyType_RSA: - return UnmarshalRsaPublicKey(pmes.GetData()) - default: - return nil, ErrBadKeyType - } -} - -// MarshalPublicKey converts a public key object into a protobuf serialized -// public key -func MarshalPublicKey(k PubKey) ([]byte, error) { - b, err := MarshalRsaPublicKey(k.(*RsaPublicKey)) - if err != nil { - return nil, err - } - pmes := new(pb.PublicKey) - typ := pb.KeyType_RSA // for now only type. - pmes.Type = &typ - pmes.Data = b - return proto.Marshal(pmes) -} - -// UnmarshalPrivateKey converts a protobuf serialized private key into its -// representative object -func UnmarshalPrivateKey(data []byte) (PrivKey, error) { - pmes := new(pb.PrivateKey) - err := proto.Unmarshal(data, pmes) - if err != nil { - return nil, err - } - - switch pmes.GetType() { - case pb.KeyType_RSA: - return UnmarshalRsaPrivateKey(pmes.GetData()) - default: - return nil, ErrBadKeyType - } -} - -// MarshalPrivateKey converts a key object into its protobuf serialized form. -func MarshalPrivateKey(k PrivKey) ([]byte, error) { - b := MarshalRsaPrivateKey(k.(*RsaPrivateKey)) - pmes := new(pb.PrivateKey) - typ := pb.KeyType_RSA // for now only type. - pmes.Type = &typ - pmes.Data = b - return proto.Marshal(pmes) -} - -// ConfigDecodeKey decodes from b64 (for config file), and unmarshals. -func ConfigDecodeKey(b string) ([]byte, error) { - return base64.StdEncoding.DecodeString(b) -} - -// ConfigEncodeKey encodes to b64 (for config file), and marshals. -func ConfigEncodeKey(b []byte) string { - return base64.StdEncoding.EncodeToString(b) -} - -// KeyEqual checks whether two -func KeyEqual(k1, k2 Key) bool { - if k1 == k2 { - return true - } - - b1, err1 := k1.Bytes() - b2, err2 := k2.Bytes() - return bytes.Equal(b1, b2) && err1 == err2 -} - -// KeyHash hashes a key. -func KeyHash(k Key) ([]byte, error) { - kb, err := k.Bytes() - if err != nil { - return nil, err - } - return u.Hash(kb), nil -} diff --git a/p2p/crypto/key_test.go b/p2p/crypto/key_test.go deleted file mode 100644 index fb83f77f678..00000000000 --- a/p2p/crypto/key_test.go +++ /dev/null @@ -1,122 +0,0 @@ -package crypto_test - -import ( - . "github.com/ipfs/go-ipfs/p2p/crypto" - - "bytes" - tu "github.com/ipfs/go-ipfs/util/testutil" - "testing" -) - -func TestRsaKeys(t *testing.T) { - sk, pk, err := tu.RandTestKeyPair(512) - if err != nil { - t.Fatal(err) - } - testKeySignature(t, sk) - testKeyEncoding(t, sk) - testKeyEquals(t, sk) - testKeyEquals(t, pk) -} - -func testKeySignature(t *testing.T, sk PrivKey) { - pk := sk.GetPublic() - - text := sk.GenSecret() - sig, err := sk.Sign(text) - if err != nil { - t.Fatal(err) - } - - valid, err := pk.Verify(text, sig) - if err != nil { - t.Fatal(err) - } - - if !valid { - t.Fatal("Invalid signature.") - } -} - -func testKeyEncoding(t *testing.T, sk PrivKey) { - skbm, err := MarshalPrivateKey(sk) - if err != nil { - t.Fatal(err) - } - - sk2, err := UnmarshalPrivateKey(skbm) - if err != nil { - t.Fatal(err) - } - - skbm2, err := MarshalPrivateKey(sk2) - if err != nil { - t.Fatal(err) - } - - if !bytes.Equal(skbm, skbm2) { - t.Error("skb -> marshal -> unmarshal -> skb failed.\n", skbm, "\n", skbm2) - } - - pk := sk.GetPublic() - pkbm, err := MarshalPublicKey(pk) - if err != nil { - t.Fatal(err) - } - - _, err = UnmarshalPublicKey(pkbm) - if err != nil { - t.Fatal(err) - } - - pkbm2, err := MarshalPublicKey(pk) - if err != nil { - t.Fatal(err) - } - - if !bytes.Equal(pkbm, pkbm2) { - t.Error("skb -> marshal -> unmarshal -> skb failed.\n", pkbm, "\n", pkbm2) - } -} - -func testKeyEquals(t *testing.T, k Key) { - kb, err := k.Bytes() - if err != nil { - t.Fatal(err) - } - - if !KeyEqual(k, k) { - t.Fatal("Key not equal to itself.") - } - - if !KeyEqual(k, testkey(kb)) { - t.Fatal("Key not equal to key with same bytes.") - } - - sk, pk, err := tu.RandTestKeyPair(512) - if err != nil { - t.Fatal(err) - } - - if KeyEqual(k, sk) { - t.Fatal("Keys should not equal.") - } - - if KeyEqual(k, pk) { - t.Fatal("Keys should not equal.") - } -} - -type testkey []byte - -func (pk testkey) Bytes() ([]byte, error) { - return pk, nil -} - -func (pk testkey) Equals(k Key) bool { - return KeyEqual(pk, k) -} - -func (pk testkey) Hash() ([]byte, error) { - return KeyHash(pk) -} diff --git a/p2p/crypto/pb/Makefile b/p2p/crypto/pb/Makefile deleted file mode 100644 index 0b987a38e72..00000000000 --- a/p2p/crypto/pb/Makefile +++ /dev/null @@ -1,10 +0,0 @@ -PB = $(wildcard *.proto) -GO = $(PB:.proto=.pb.go) - -all: $(GO) - -%.pb.go: %.proto - protoc --go_out=. --proto_path=../../../../../../:/usr/local/opt/protobuf/include:. $< - -clean: - rm *.pb.go diff --git a/p2p/crypto/pb/crypto.pb.go b/p2p/crypto/pb/crypto.pb.go deleted file mode 100644 index 08425452b88..00000000000 --- a/p2p/crypto/pb/crypto.pb.go +++ /dev/null @@ -1,104 +0,0 @@ -// Code generated by protoc-gen-go. -// source: crypto.proto -// DO NOT EDIT! - -/* -Package crypto_pb is a generated protocol buffer package. - -It is generated from these files: - crypto.proto - -It has these top-level messages: - PublicKey - PrivateKey -*/ -package crypto_pb - -import proto "github.com/ipfs/go-ipfs/Godeps/_workspace/src/github.com/golang/protobuf/proto" -import math "math" - -// Reference imports to suppress errors if they are not otherwise used. -var _ = proto.Marshal -var _ = math.Inf - -type KeyType int32 - -const ( - KeyType_RSA KeyType = 0 -) - -var KeyType_name = map[int32]string{ - 0: "RSA", -} -var KeyType_value = map[string]int32{ - "RSA": 0, -} - -func (x KeyType) Enum() *KeyType { - p := new(KeyType) - *p = x - return p -} -func (x KeyType) String() string { - return proto.EnumName(KeyType_name, int32(x)) -} -func (x *KeyType) UnmarshalJSON(data []byte) error { - value, err := proto.UnmarshalJSONEnum(KeyType_value, data, "KeyType") - if err != nil { - return err - } - *x = KeyType(value) - return nil -} - -type PublicKey struct { - Type *KeyType `protobuf:"varint,1,req,enum=crypto.pb.KeyType" json:"Type,omitempty"` - Data []byte `protobuf:"bytes,2,req" json:"Data,omitempty"` - XXX_unrecognized []byte `json:"-"` -} - -func (m *PublicKey) Reset() { *m = PublicKey{} } -func (m *PublicKey) String() string { return proto.CompactTextString(m) } -func (*PublicKey) ProtoMessage() {} - -func (m *PublicKey) GetType() KeyType { - if m != nil && m.Type != nil { - return *m.Type - } - return KeyType_RSA -} - -func (m *PublicKey) GetData() []byte { - if m != nil { - return m.Data - } - return nil -} - -type PrivateKey struct { - Type *KeyType `protobuf:"varint,1,req,enum=crypto.pb.KeyType" json:"Type,omitempty"` - Data []byte `protobuf:"bytes,2,req" json:"Data,omitempty"` - XXX_unrecognized []byte `json:"-"` -} - -func (m *PrivateKey) Reset() { *m = PrivateKey{} } -func (m *PrivateKey) String() string { return proto.CompactTextString(m) } -func (*PrivateKey) ProtoMessage() {} - -func (m *PrivateKey) GetType() KeyType { - if m != nil && m.Type != nil { - return *m.Type - } - return KeyType_RSA -} - -func (m *PrivateKey) GetData() []byte { - if m != nil { - return m.Data - } - return nil -} - -func init() { - proto.RegisterEnum("crypto.pb.KeyType", KeyType_name, KeyType_value) -} diff --git a/p2p/crypto/pb/crypto.proto b/p2p/crypto/pb/crypto.proto deleted file mode 100644 index 7491362d6dc..00000000000 --- a/p2p/crypto/pb/crypto.proto +++ /dev/null @@ -1,15 +0,0 @@ -package crypto.pb; - -enum KeyType { - RSA = 0; -} - -message PublicKey { - required KeyType Type = 1; - required bytes Data = 2; -} - -message PrivateKey { - required KeyType Type = 1; - required bytes Data = 2; -} diff --git a/p2p/crypto/rsa.go b/p2p/crypto/rsa.go deleted file mode 100644 index a730f02f5c8..00000000000 --- a/p2p/crypto/rsa.go +++ /dev/null @@ -1,126 +0,0 @@ -package crypto - -import ( - "crypto" - "crypto/rand" - "crypto/rsa" - "crypto/sha256" - "crypto/x509" - "errors" - - proto "github.com/ipfs/go-ipfs/Godeps/_workspace/src/github.com/gogo/protobuf/proto" - - pb "github.com/ipfs/go-ipfs/p2p/crypto/pb" -) - -type RsaPrivateKey struct { - sk *rsa.PrivateKey - pk *rsa.PublicKey -} - -type RsaPublicKey struct { - k *rsa.PublicKey -} - -func (pk *RsaPublicKey) Verify(data, sig []byte) (bool, error) { - hashed := sha256.Sum256(data) - err := rsa.VerifyPKCS1v15(pk.k, crypto.SHA256, hashed[:], sig) - if err != nil { - return false, err - } - return true, nil -} - -func (pk *RsaPublicKey) Bytes() ([]byte, error) { - b, err := x509.MarshalPKIXPublicKey(pk.k) - if err != nil { - return nil, err - } - - pbmes := new(pb.PublicKey) - typ := pb.KeyType_RSA - pbmes.Type = &typ - pbmes.Data = b - return proto.Marshal(pbmes) -} - -func (pk *RsaPublicKey) Encrypt(b []byte) ([]byte, error) { - return rsa.EncryptPKCS1v15(rand.Reader, pk.k, b) -} - -// Equals checks whether this key is equal to another -func (pk *RsaPublicKey) Equals(k Key) bool { - return KeyEqual(pk, k) -} - -func (pk *RsaPublicKey) Hash() ([]byte, error) { - return KeyHash(pk) -} - -func (sk *RsaPrivateKey) GenSecret() []byte { - buf := make([]byte, 16) - rand.Read(buf) - return buf -} - -func (sk *RsaPrivateKey) Sign(message []byte) ([]byte, error) { - hashed := sha256.Sum256(message) - return rsa.SignPKCS1v15(rand.Reader, sk.sk, crypto.SHA256, hashed[:]) -} - -func (sk *RsaPrivateKey) GetPublic() PubKey { - if sk.pk == nil { - sk.pk = &sk.sk.PublicKey - } - return &RsaPublicKey{sk.pk} -} - -func (sk *RsaPrivateKey) Decrypt(b []byte) ([]byte, error) { - return rsa.DecryptPKCS1v15(rand.Reader, sk.sk, b) -} - -func (sk *RsaPrivateKey) Bytes() ([]byte, error) { - b := x509.MarshalPKCS1PrivateKey(sk.sk) - pbmes := new(pb.PrivateKey) - typ := pb.KeyType_RSA - pbmes.Type = &typ - pbmes.Data = b - return proto.Marshal(pbmes) -} - -// Equals checks whether this key is equal to another -func (sk *RsaPrivateKey) Equals(k Key) bool { - return KeyEqual(sk, k) -} - -func (sk *RsaPrivateKey) Hash() ([]byte, error) { - return KeyHash(sk) -} - -func UnmarshalRsaPrivateKey(b []byte) (*RsaPrivateKey, error) { - sk, err := x509.ParsePKCS1PrivateKey(b) - if err != nil { - return nil, err - } - return &RsaPrivateKey{sk: sk}, nil -} - -func MarshalRsaPrivateKey(k *RsaPrivateKey) []byte { - return x509.MarshalPKCS1PrivateKey(k.sk) -} - -func UnmarshalRsaPublicKey(b []byte) (*RsaPublicKey, error) { - pub, err := x509.ParsePKIXPublicKey(b) - if err != nil { - return nil, err - } - pk, ok := pub.(*rsa.PublicKey) - if !ok { - return nil, errors.New("Not actually an rsa public key.") - } - return &RsaPublicKey{pk}, nil -} - -func MarshalRsaPublicKey(k *RsaPublicKey) ([]byte, error) { - return x509.MarshalPKIXPublicKey(k.k) -} diff --git a/p2p/crypto/secio/al.go b/p2p/crypto/secio/al.go deleted file mode 100644 index 9fc3833e325..00000000000 --- a/p2p/crypto/secio/al.go +++ /dev/null @@ -1,115 +0,0 @@ -package secio - -import ( - "errors" - "fmt" - "strings" - - "crypto/aes" - "crypto/cipher" - "crypto/hmac" - "crypto/sha1" - "crypto/sha256" - "crypto/sha512" - "hash" - - bfish "github.com/ipfs/go-ipfs/Godeps/_workspace/src/golang.org/x/crypto/blowfish" - ci "github.com/ipfs/go-ipfs/p2p/crypto" -) - -// List of supported ECDH curves -var SupportedExchanges = "P-256,P-384,P-521" - -// List of supported Ciphers -var SupportedCiphers = "AES-256,AES-128,Blowfish" - -// List of supported Hashes -var SupportedHashes = "SHA256,SHA512" - -type HMAC struct { - hash.Hash - size int -} - -// encParams represent encryption parameters -type encParams struct { - // keys - permanentPubKey ci.PubKey - ephemeralPubKey []byte - keys ci.StretchedKeys - - // selections - curveT string - cipherT string - hashT string - - // cipher + mac - cipher cipher.Stream - mac HMAC -} - -func (e *encParams) makeMacAndCipher() error { - m, err := newMac(e.hashT, e.keys.MacKey) - if err != nil { - return err - } - - bc, err := newBlockCipher(e.cipherT, e.keys.CipherKey) - if err != nil { - return err - } - - e.cipher = cipher.NewCTR(bc, e.keys.IV) - e.mac = m - return nil -} - -func newMac(hashType string, key []byte) (HMAC, error) { - switch hashType { - case "SHA1": - return HMAC{hmac.New(sha1.New, key), sha1.Size}, nil - case "SHA512": - return HMAC{hmac.New(sha512.New, key), sha512.Size}, nil - case "SHA256": - return HMAC{hmac.New(sha256.New, key), sha256.Size}, nil - default: - return HMAC{}, fmt.Errorf("Unrecognized hash type: %s", hashType) - } -} - -func newBlockCipher(cipherT string, key []byte) (cipher.Block, error) { - switch cipherT { - case "AES-128", "AES-256": - return aes.NewCipher(key) - case "Blowfish": - return bfish.NewCipher(key) - default: - return nil, fmt.Errorf("Unrecognized cipher type: %s", cipherT) - } -} - -// Determines which algorithm to use. Note: f(a, b) = f(b, a) -func selectBest(order int, p1, p2 string) (string, error) { - var f, s []string - switch { - case order < 0: - f = strings.Split(p2, ",") - s = strings.Split(p1, ",") - case order > 0: - f = strings.Split(p1, ",") - s = strings.Split(p2, ",") - default: // Exact same preferences. - p := strings.Split(p1, ",") - return p[0], nil - } - - for _, fc := range f { - for _, sc := range s { - if fc == sc { - return fc, nil - } - } - } - - return "", errors.New("No algorithms in common!") -} diff --git a/p2p/crypto/secio/interface.go b/p2p/crypto/secio/interface.go deleted file mode 100644 index 3fc54875f53..00000000000 --- a/p2p/crypto/secio/interface.go +++ /dev/null @@ -1,126 +0,0 @@ -// package secio handles establishing secure communication between two peers. -package secio - -import ( - "io" - - ci "github.com/ipfs/go-ipfs/p2p/crypto" - - msgio "github.com/ipfs/go-ipfs/Godeps/_workspace/src/github.com/jbenet/go-msgio" - context "github.com/ipfs/go-ipfs/Godeps/_workspace/src/golang.org/x/net/context" - peer "github.com/ipfs/go-ipfs/p2p/peer" -) - -// SessionGenerator constructs secure communication sessions for a peer. -type SessionGenerator struct { - LocalID peer.ID - PrivateKey ci.PrivKey -} - -// NewSession takes an insecure io.ReadWriter, sets up a TLS-like -// handshake with the other side, and returns a secure session. -// The handshake isn't run until the connection is read or written to. -// See the source for the protocol details and security implementation. -// The provided Context is only needed for the duration of this function. -func (sg *SessionGenerator) NewSession(ctx context.Context, insecure io.ReadWriteCloser) (Session, error) { - return newSecureSession(ctx, sg.LocalID, sg.PrivateKey, insecure) -} - -type Session interface { - // ReadWriter returns the encrypted communication channel - ReadWriter() msgio.ReadWriteCloser - - // LocalPeer retrieves the local peer. - LocalPeer() peer.ID - - // LocalPrivateKey retrieves the local private key - LocalPrivateKey() ci.PrivKey - - // RemotePeer retrieves the remote peer. - RemotePeer() peer.ID - - // RemotePublicKey retrieves the remote's public key - // which was received during the handshake. - RemotePublicKey() ci.PubKey - - // Close closes the secure session - Close() error -} - -// SecureReadWriter returns the encrypted communication channel -func (s *secureSession) ReadWriter() msgio.ReadWriteCloser { - if err := s.Handshake(); err != nil { - return &closedRW{err} - } - return s.secure -} - -// LocalPeer retrieves the local peer. -func (s *secureSession) LocalPeer() peer.ID { - return s.localPeer -} - -// LocalPrivateKey retrieves the local peer's PrivateKey -func (s *secureSession) LocalPrivateKey() ci.PrivKey { - return s.localKey -} - -// RemotePeer retrieves the remote peer. -func (s *secureSession) RemotePeer() peer.ID { - if err := s.Handshake(); err != nil { - return "" - } - return s.remotePeer -} - -// RemotePeer retrieves the remote peer. -func (s *secureSession) RemotePublicKey() ci.PubKey { - if err := s.Handshake(); err != nil { - return nil - } - return s.remote.permanentPubKey -} - -// Close closes the secure session -func (s *secureSession) Close() error { - s.cancel() - s.handshakeMu.Lock() - defer s.handshakeMu.Unlock() - if s.secure == nil { - return s.insecure.Close() // hadn't secured yet. - } - return s.secure.Close() -} - -// closedRW implements a stub msgio interface that's already -// closed and errored. -type closedRW struct { - err error -} - -func (c *closedRW) Read(buf []byte) (int, error) { - return 0, c.err -} - -func (c *closedRW) Write(buf []byte) (int, error) { - return 0, c.err -} - -func (c *closedRW) NextMsgLen() (int, error) { - return 0, c.err -} - -func (c *closedRW) ReadMsg() ([]byte, error) { - return nil, c.err -} - -func (c *closedRW) WriteMsg(buf []byte) error { - return c.err -} - -func (c *closedRW) Close() error { - return c.err -} - -func (c *closedRW) ReleaseMsg(m []byte) { -} diff --git a/p2p/crypto/secio/io_test.go b/p2p/crypto/secio/io_test.go deleted file mode 100644 index 5ad06f12ae2..00000000000 --- a/p2p/crypto/secio/io_test.go +++ /dev/null @@ -1 +0,0 @@ -package secio diff --git a/p2p/crypto/secio/pb/Makefile b/p2p/crypto/secio/pb/Makefile deleted file mode 100644 index 334feee7411..00000000000 --- a/p2p/crypto/secio/pb/Makefile +++ /dev/null @@ -1,10 +0,0 @@ -PB = $(wildcard *.proto) -GO = $(PB:.proto=.pb.go) - -all: $(GO) - -%.pb.go: %.proto - protoc --gogo_out=. --proto_path=../../../../../../:/usr/local/opt/protobuf/include:. $< - -clean: - rm *.pb.go diff --git a/p2p/crypto/secio/pb/spipe.pb.go b/p2p/crypto/secio/pb/spipe.pb.go deleted file mode 100644 index a0d749bc690..00000000000 --- a/p2p/crypto/secio/pb/spipe.pb.go +++ /dev/null @@ -1,97 +0,0 @@ -// Code generated by protoc-gen-gogo. -// source: spipe.proto -// DO NOT EDIT! - -/* -Package spipe_pb is a generated protocol buffer package. - -It is generated from these files: - spipe.proto - -It has these top-level messages: - Propose - Exchange -*/ -package spipe_pb - -import proto "github.com/ipfs/go-ipfs/Godeps/_workspace/src/github.com/gogo/protobuf/proto" -import math "math" - -// Reference imports to suppress errors if they are not otherwise used. -var _ = proto.Marshal -var _ = math.Inf - -type Propose struct { - Rand []byte `protobuf:"bytes,1,opt,name=rand" json:"rand,omitempty"` - Pubkey []byte `protobuf:"bytes,2,opt,name=pubkey" json:"pubkey,omitempty"` - Exchanges *string `protobuf:"bytes,3,opt,name=exchanges" json:"exchanges,omitempty"` - Ciphers *string `protobuf:"bytes,4,opt,name=ciphers" json:"ciphers,omitempty"` - Hashes *string `protobuf:"bytes,5,opt,name=hashes" json:"hashes,omitempty"` - XXX_unrecognized []byte `json:"-"` -} - -func (m *Propose) Reset() { *m = Propose{} } -func (m *Propose) String() string { return proto.CompactTextString(m) } -func (*Propose) ProtoMessage() {} - -func (m *Propose) GetRand() []byte { - if m != nil { - return m.Rand - } - return nil -} - -func (m *Propose) GetPubkey() []byte { - if m != nil { - return m.Pubkey - } - return nil -} - -func (m *Propose) GetExchanges() string { - if m != nil && m.Exchanges != nil { - return *m.Exchanges - } - return "" -} - -func (m *Propose) GetCiphers() string { - if m != nil && m.Ciphers != nil { - return *m.Ciphers - } - return "" -} - -func (m *Propose) GetHashes() string { - if m != nil && m.Hashes != nil { - return *m.Hashes - } - return "" -} - -type Exchange struct { - Epubkey []byte `protobuf:"bytes,1,opt,name=epubkey" json:"epubkey,omitempty"` - Signature []byte `protobuf:"bytes,2,opt,name=signature" json:"signature,omitempty"` - XXX_unrecognized []byte `json:"-"` -} - -func (m *Exchange) Reset() { *m = Exchange{} } -func (m *Exchange) String() string { return proto.CompactTextString(m) } -func (*Exchange) ProtoMessage() {} - -func (m *Exchange) GetEpubkey() []byte { - if m != nil { - return m.Epubkey - } - return nil -} - -func (m *Exchange) GetSignature() []byte { - if m != nil { - return m.Signature - } - return nil -} - -func init() { -} diff --git a/p2p/crypto/secio/pb/spipe.proto b/p2p/crypto/secio/pb/spipe.proto deleted file mode 100644 index a7a46773729..00000000000 --- a/p2p/crypto/secio/pb/spipe.proto +++ /dev/null @@ -1,14 +0,0 @@ -package spipe.pb; - -message Propose { - optional bytes rand = 1; - optional bytes pubkey = 2; - optional string exchanges = 3; - optional string ciphers = 4; - optional string hashes = 5; -} - -message Exchange { - optional bytes epubkey = 1; - optional bytes signature = 2; -} diff --git a/p2p/crypto/secio/protocol.go b/p2p/crypto/secio/protocol.go deleted file mode 100644 index ddb223307d1..00000000000 --- a/p2p/crypto/secio/protocol.go +++ /dev/null @@ -1,341 +0,0 @@ -package secio - -import ( - "bytes" - "crypto/rand" - "errors" - "fmt" - "io" - "sync" - "time" - - msgio "github.com/ipfs/go-ipfs/Godeps/_workspace/src/github.com/jbenet/go-msgio" - context "github.com/ipfs/go-ipfs/Godeps/_workspace/src/golang.org/x/net/context" - ci "github.com/ipfs/go-ipfs/p2p/crypto" - pb "github.com/ipfs/go-ipfs/p2p/crypto/secio/pb" - peer "github.com/ipfs/go-ipfs/p2p/peer" - u "github.com/ipfs/go-ipfs/util" - logging "github.com/ipfs/go-ipfs/vendor/QmQg1J6vikuXF9oDvm4wpdeAUvvkVEKW1EYDw9HhTMnP2b/go-log" -) - -var log = logging.Logger("secio") - -// ErrUnsupportedKeyType is returned when a private key cast/type switch fails. -var ErrUnsupportedKeyType = errors.New("unsupported key type") - -// ErrClosed signals the closing of a connection. -var ErrClosed = errors.New("connection closed") - -// ErrEcho is returned when we're attempting to handshake with the same keys and nonces. -var ErrEcho = errors.New("same keys and nonces. one side talking to self.") - -// HandshakeTimeout governs how long the handshake will be allowed to take place for. -// Making this number large means there could be many bogus connections waiting to -// timeout in flight. Typical handshakes take ~3RTTs, so it should be completed within -// seconds across a typical planet in the solar system. -var HandshakeTimeout = time.Second * 30 - -// nonceSize is the size of our nonces (in bytes) -const nonceSize = 16 - -// secureSession encapsulates all the parameters needed for encrypting -// and decrypting traffic from an insecure channel. -type secureSession struct { - ctx context.Context - cancel context.CancelFunc - - secure msgio.ReadWriteCloser - insecure io.ReadWriteCloser - insecureM msgio.ReadWriter - - localKey ci.PrivKey - localPeer peer.ID - remotePeer peer.ID - - local encParams - remote encParams - - sharedSecret []byte - - handshakeMu sync.Mutex // guards handshakeDone + handshakeErr - handshakeDone bool - handshakeErr error -} - -func (s *secureSession) Loggable() map[string]interface{} { - m := make(map[string]interface{}) - m["localPeer"] = s.localPeer.Pretty() - m["remotePeer"] = s.remotePeer.Pretty() - m["established"] = (s.secure != nil) - return m -} - -func newSecureSession(ctx context.Context, local peer.ID, key ci.PrivKey, insecure io.ReadWriteCloser) (*secureSession, error) { - s := &secureSession{localPeer: local, localKey: key} - s.ctx, s.cancel = context.WithCancel(ctx) - - switch { - case s.localPeer == "": - return nil, errors.New("no local id provided") - case s.localKey == nil: - return nil, errors.New("no local private key provided") - case !s.localPeer.MatchesPrivateKey(s.localKey): - return nil, fmt.Errorf("peer.ID does not match PrivateKey") - case insecure == nil: - return nil, fmt.Errorf("insecure ReadWriter is nil") - } - - s.ctx = ctx - s.insecure = insecure - s.insecureM = msgio.NewReadWriter(insecure) - return s, nil -} - -func (s *secureSession) Handshake() error { - s.handshakeMu.Lock() - defer s.handshakeMu.Unlock() - - if s.handshakeErr != nil { - return s.handshakeErr - } - - if !s.handshakeDone { - s.handshakeErr = s.runHandshake() - s.handshakeDone = true - } - return s.handshakeErr -} - -// runHandshake performs initial communication over insecure channel to share -// keys, IDs, and initiate communication, assigning all necessary params. -// requires the duplex channel to be a msgio.ReadWriter (for framed messaging) -func (s *secureSession) runHandshake() error { - ctx, cancel := context.WithTimeout(s.ctx, HandshakeTimeout) // remove - defer cancel() - - // ============================================================================= - // step 1. Propose -- propose cipher suite + send pubkeys + nonce - - // Generate and send Hello packet. - // Hello = (rand, PublicKey, Supported) - nonceOut := make([]byte, nonceSize) - _, err := rand.Read(nonceOut) - if err != nil { - return err - } - - defer log.EventBegin(ctx, "secureHandshake", s).Done() - - s.local.permanentPubKey = s.localKey.GetPublic() - myPubKeyBytes, err := s.local.permanentPubKey.Bytes() - if err != nil { - return err - } - - proposeOut := new(pb.Propose) - proposeOut.Rand = nonceOut - proposeOut.Pubkey = myPubKeyBytes - proposeOut.Exchanges = &SupportedExchanges - proposeOut.Ciphers = &SupportedCiphers - proposeOut.Hashes = &SupportedHashes - - // log.Debugf("1.0 Propose: nonce:%s exchanges:%s ciphers:%s hashes:%s", - // nonceOut, SupportedExchanges, SupportedCiphers, SupportedHashes) - - // Send Propose packet (respects ctx) - proposeOutBytes, err := writeMsgCtx(ctx, s.insecureM, proposeOut) - if err != nil { - return err - } - - // Receive + Parse their Propose packet and generate an Exchange packet. - proposeIn := new(pb.Propose) - proposeInBytes, err := readMsgCtx(ctx, s.insecureM, proposeIn) - if err != nil { - return err - } - - // log.Debugf("1.0.1 Propose recv: nonce:%s exchanges:%s ciphers:%s hashes:%s", - // proposeIn.GetRand(), proposeIn.GetExchanges(), proposeIn.GetCiphers(), proposeIn.GetHashes()) - - // ============================================================================= - // step 1.1 Identify -- get identity from their key - - // get remote identity - s.remote.permanentPubKey, err = ci.UnmarshalPublicKey(proposeIn.GetPubkey()) - if err != nil { - return err - } - - // get peer id - s.remotePeer, err = peer.IDFromPublicKey(s.remote.permanentPubKey) - if err != nil { - return err - } - - log.Debugf("1.1 Identify: %s Remote Peer Identified as %s", s.localPeer, s.remotePeer) - - // ============================================================================= - // step 1.2 Selection -- select/agree on best encryption parameters - - // to determine order, use cmp(H(remote_pubkey||local_rand), H(local_pubkey||remote_rand)). - oh1 := u.Hash(append(proposeIn.GetPubkey(), nonceOut...)) - oh2 := u.Hash(append(myPubKeyBytes, proposeIn.GetRand()...)) - order := bytes.Compare(oh1, oh2) - if order == 0 { - return ErrEcho // talking to self (same socket. must be reuseport + dialing self) - } - - s.local.curveT, err = selectBest(order, SupportedExchanges, proposeIn.GetExchanges()) - if err != nil { - return err - } - - s.local.cipherT, err = selectBest(order, SupportedCiphers, proposeIn.GetCiphers()) - if err != nil { - return err - } - - s.local.hashT, err = selectBest(order, SupportedHashes, proposeIn.GetHashes()) - if err != nil { - return err - } - - // we use the same params for both directions (must choose same curve) - // WARNING: if they dont SelectBest the same way, this won't work... - s.remote.curveT = s.local.curveT - s.remote.cipherT = s.local.cipherT - s.remote.hashT = s.local.hashT - - // log.Debugf("1.2 selection: exchange:%s cipher:%s hash:%s", - // s.local.curveT, s.local.cipherT, s.local.hashT) - - // ============================================================================= - // step 2. Exchange -- exchange (signed) ephemeral keys. verify signatures. - - // Generate EphemeralPubKey - var genSharedKey ci.GenSharedKey - s.local.ephemeralPubKey, genSharedKey, err = ci.GenerateEKeyPair(s.local.curveT) - - // Gather corpus to sign. - selectionOut := new(bytes.Buffer) - selectionOut.Write(proposeOutBytes) - selectionOut.Write(proposeInBytes) - selectionOut.Write(s.local.ephemeralPubKey) - selectionOutBytes := selectionOut.Bytes() - - // log.Debugf("2.0 exchange: %v", selectionOutBytes) - exchangeOut := new(pb.Exchange) - exchangeOut.Epubkey = s.local.ephemeralPubKey - exchangeOut.Signature, err = s.localKey.Sign(selectionOutBytes) - if err != nil { - return err - } - - // Send Propose packet (respects ctx) - if _, err := writeMsgCtx(ctx, s.insecureM, exchangeOut); err != nil { - return err - } - - // Receive + Parse their Exchange packet. - exchangeIn := new(pb.Exchange) - if _, err := readMsgCtx(ctx, s.insecureM, exchangeIn); err != nil { - return err - } - - // ============================================================================= - // step 2.1. Verify -- verify their exchange packet is good. - - // get their ephemeral pub key - s.remote.ephemeralPubKey = exchangeIn.GetEpubkey() - - selectionIn := new(bytes.Buffer) - selectionIn.Write(proposeInBytes) - selectionIn.Write(proposeOutBytes) - selectionIn.Write(s.remote.ephemeralPubKey) - selectionInBytes := selectionIn.Bytes() - // log.Debugf("2.0.1 exchange recv: %v", selectionInBytes) - - // u.POut("Remote Peer Identified as %s\n", s.remote) - sigOK, err := s.remote.permanentPubKey.Verify(selectionInBytes, exchangeIn.GetSignature()) - if err != nil { - // log.Error("2.1 Verify: failed: %s", err) - return err - } - - if !sigOK { - err := errors.New("Bad signature!") - // log.Error("2.1 Verify: failed: %s", err) - return err - } - // log.Debugf("2.1 Verify: signature verified.") - - // ============================================================================= - // step 2.2. Keys -- generate keys for mac + encryption - - // OK! seems like we're good to go. - s.sharedSecret, err = genSharedKey(exchangeIn.GetEpubkey()) - if err != nil { - return err - } - - // generate two sets of keys (stretching) - k1, k2 := ci.KeyStretcher(s.local.cipherT, s.local.hashT, s.sharedSecret) - - // use random nonces to decide order. - switch { - case order > 0: - // just break - case order < 0: - k1, k2 = k2, k1 // swap - default: - // we should've bailed before this. but if not, bail here. - return ErrEcho - } - s.local.keys = k1 - s.remote.keys = k2 - - // log.Debug("2.2 keys:\n\tshared: %v\n\tk1: %v\n\tk2: %v", - // s.sharedSecret, s.local.keys, s.remote.keys) - - // ============================================================================= - // step 2.3. MAC + Cipher -- prepare MAC + cipher - - if err := s.local.makeMacAndCipher(); err != nil { - return err - } - - if err := s.remote.makeMacAndCipher(); err != nil { - return err - } - - // log.Debug("2.3 mac + cipher.") - - // ============================================================================= - // step 3. Finish -- send expected message to verify encryption works (send local nonce) - - // setup ETM ReadWriter - w := NewETMWriter(s.insecure, s.local.cipher, s.local.mac) - r := NewETMReader(s.insecure, s.remote.cipher, s.remote.mac) - s.secure = msgio.Combine(w, r).(msgio.ReadWriteCloser) - - // log.Debug("3.0 finish. sending: %v", proposeIn.GetRand()) - // send their Nonce. - if _, err := s.secure.Write(proposeIn.GetRand()); err != nil { - return fmt.Errorf("Failed to write Finish nonce: %s", err) - } - - // read our Nonce - nonceOut2 := make([]byte, len(nonceOut)) - if _, err := io.ReadFull(s.secure, nonceOut2); err != nil { - return fmt.Errorf("Failed to read Finish nonce: %s", err) - } - - // log.Debug("3.0 finish.\n\texpect: %v\n\tactual: %v", nonceOut, nonceOut2) - if !bytes.Equal(nonceOut, nonceOut2) { - return fmt.Errorf("Failed to read our encrypted nonce: %s != %s", nonceOut2, nonceOut) - } - - // Whew! ok, that's all folks. - return nil -} diff --git a/p2p/crypto/secio/rw.go b/p2p/crypto/secio/rw.go deleted file mode 100644 index 959fd634a39..00000000000 --- a/p2p/crypto/secio/rw.go +++ /dev/null @@ -1,273 +0,0 @@ -package secio - -import ( - "crypto/cipher" - "errors" - "fmt" - "io" - "sync" - - "crypto/hmac" - - proto "github.com/ipfs/go-ipfs/Godeps/_workspace/src/github.com/gogo/protobuf/proto" - msgio "github.com/ipfs/go-ipfs/Godeps/_workspace/src/github.com/jbenet/go-msgio" - mpool "github.com/ipfs/go-ipfs/Godeps/_workspace/src/github.com/jbenet/go-msgio/mpool" - context "github.com/ipfs/go-ipfs/Godeps/_workspace/src/golang.org/x/net/context" -) - -const MaxMsgSize = 8 * 1024 * 1024 - -var ErrMaxMessageSize = errors.New("attempted to read message larger than max size") - -// ErrMACInvalid signals that a MAC verification failed -var ErrMACInvalid = errors.New("MAC verification failed") - -// bufPool is a ByteSlicePool for messages. we need buffers because (sadly) -// we cannot encrypt in place-- the user needs their buffer back. -var bufPool = mpool.ByteSlicePool - -type etmWriter struct { - // params - pool mpool.Pool // for the buffers with encrypted data - msg msgio.WriteCloser // msgio for knowing where boundaries lie - str cipher.Stream // the stream cipher to encrypt with - mac HMAC // the mac to authenticate data with - - sync.Mutex -} - -// NewETMWriter Encrypt-Then-MAC -func NewETMWriter(w io.Writer, s cipher.Stream, mac HMAC) msgio.WriteCloser { - return &etmWriter{msg: msgio.NewWriter(w), str: s, mac: mac, pool: bufPool} -} - -// Write writes passed in buffer as a single message. -func (w *etmWriter) Write(b []byte) (int, error) { - if err := w.WriteMsg(b); err != nil { - return 0, err - } - return len(b), nil -} - -// WriteMsg writes the msg in the passed in buffer. -func (w *etmWriter) WriteMsg(b []byte) error { - w.Lock() - defer w.Unlock() - - // encrypt. - data := w.pool.Get(uint32(len(b))).([]byte) - data = data[:len(b)] // the pool's buffer may be larger - w.str.XORKeyStream(data, b) - - // log.Debugf("ENC plaintext (%d): %s %v", len(b), b, b) - // log.Debugf("ENC ciphertext (%d): %s %v", len(data), data, data) - - // then, mac. - if _, err := w.mac.Write(data); err != nil { - return err - } - - // Sum appends. - data = w.mac.Sum(data) - w.mac.Reset() - // it's sad to append here. our buffers are -- hopefully -- coming from - // a shared buffer pool, so the append may not actually cause allocation - // one can only hope. i guess we'll see. - - return w.msg.WriteMsg(data) -} - -func (w *etmWriter) Close() error { - return w.msg.Close() -} - -type etmReader struct { - msgio.Reader - io.Closer - - // buffer - buf []byte - - // params - msg msgio.ReadCloser // msgio for knowing where boundaries lie - str cipher.Stream // the stream cipher to encrypt with - mac HMAC // the mac to authenticate data with - - sync.Mutex -} - -// NewETMReader Encrypt-Then-MAC -func NewETMReader(r io.Reader, s cipher.Stream, mac HMAC) msgio.ReadCloser { - return &etmReader{msg: msgio.NewReader(r), str: s, mac: mac} -} - -func (r *etmReader) NextMsgLen() (int, error) { - return r.msg.NextMsgLen() -} - -func (r *etmReader) drainBuf(buf []byte) int { - if r.buf == nil { - return 0 - } - - n := copy(buf, r.buf) - r.buf = r.buf[n:] - return n -} - -func (r *etmReader) Read(buf []byte) (int, error) { - r.Lock() - defer r.Unlock() - - // first, check if we have anything in the buffer - copied := r.drainBuf(buf) - buf = buf[copied:] - if copied > 0 { - return copied, nil - // return here to avoid complicating the rest... - // user can call io.ReadFull. - } - - // check the buffer has enough space for the next msg - fullLen, err := r.msg.NextMsgLen() - if err != nil { - return 0, err - } - - if fullLen > MaxMsgSize { - return 0, ErrMaxMessageSize - } - - buf2 := buf - changed := false - // if not enough space, allocate a new buffer. - if cap(buf) < fullLen { - buf2 = make([]byte, fullLen) - changed = true - } - buf2 = buf2[:fullLen] - - n, err := io.ReadFull(r.msg, buf2) - if err != nil { - return n, err - } - - m, err := r.macCheckThenDecrypt(buf2) - if err != nil { - return 0, err - } - buf2 = buf2[:m] - if !changed { - return m, nil - } - - n = copy(buf, buf2) - if len(buf2) > len(buf) { - r.buf = buf2[len(buf):] // had some left over? save it. - } - return n, nil -} - -func (r *etmReader) ReadMsg() ([]byte, error) { - r.Lock() - defer r.Unlock() - - msg, err := r.msg.ReadMsg() - if err != nil { - return nil, err - } - - n, err := r.macCheckThenDecrypt(msg) - if err != nil { - return nil, err - } - return msg[:n], nil -} - -func (r *etmReader) macCheckThenDecrypt(m []byte) (int, error) { - l := len(m) - if l < r.mac.size { - return 0, fmt.Errorf("buffer (%d) shorter than MAC size (%d)", l, r.mac.size) - } - - mark := l - r.mac.size - data := m[:mark] - macd := m[mark:] - - r.mac.Write(data) - expected := r.mac.Sum(nil) - r.mac.Reset() - - // check mac. if failed, return error. - if !hmac.Equal(macd, expected) { - log.Debug("MAC Invalid:", expected, "!=", macd) - return 0, ErrMACInvalid - } - - // ok seems good. decrypt. (can decrypt in place, yay!) - // log.Debugf("DEC ciphertext (%d): %s %v", len(data), data, data) - r.str.XORKeyStream(data, data) - // log.Debugf("DEC plaintext (%d): %s %v", len(data), data, data) - - return mark, nil -} - -func (w *etmReader) Close() error { - return w.msg.Close() -} - -// ReleaseMsg signals a buffer can be reused. -func (r *etmReader) ReleaseMsg(b []byte) { - r.msg.ReleaseMsg(b) -} - -// writeMsgCtx is used by the -func writeMsgCtx(ctx context.Context, w msgio.Writer, msg proto.Message) ([]byte, error) { - enc, err := proto.Marshal(msg) - if err != nil { - return nil, err - } - - // write in a goroutine so we can exit when our context is cancelled. - done := make(chan error) - go func(m []byte) { - err := w.WriteMsg(m) - select { - case done <- err: - case <-ctx.Done(): - } - }(enc) - - select { - case <-ctx.Done(): - return nil, ctx.Err() - case e := <-done: - return enc, e - } -} - -func readMsgCtx(ctx context.Context, r msgio.Reader, p proto.Message) ([]byte, error) { - var msg []byte - - // read in a goroutine so we can exit when our context is cancelled. - done := make(chan error) - go func() { - var err error - msg, err = r.ReadMsg() - select { - case done <- err: - case <-ctx.Done(): - } - }() - - select { - case <-ctx.Done(): - return nil, ctx.Err() - case e := <-done: - if e != nil { - return nil, e - } - } - - return msg, proto.Unmarshal(msg, p) -} diff --git a/p2p/discovery/mdns.go b/p2p/discovery/mdns.go deleted file mode 100644 index 61312fefa5d..00000000000 --- a/p2p/discovery/mdns.go +++ /dev/null @@ -1,189 +0,0 @@ -package discovery - -import ( - "errors" - "io" - "io/ioutil" - golog "log" - "net" - "sync" - "time" - - "github.com/ipfs/go-ipfs/Godeps/_workspace/src/github.com/cryptix/mdns" - ma "github.com/ipfs/go-ipfs/Godeps/_workspace/src/github.com/jbenet/go-multiaddr" - manet "github.com/ipfs/go-ipfs/Godeps/_workspace/src/github.com/jbenet/go-multiaddr-net" - - "github.com/ipfs/go-ipfs/p2p/host" - "github.com/ipfs/go-ipfs/p2p/peer" - logging "github.com/ipfs/go-ipfs/vendor/QmQg1J6vikuXF9oDvm4wpdeAUvvkVEKW1EYDw9HhTMnP2b/go-log" -) - -var log = logging.Logger("mdns") - -const ServiceTag = "discovery.ipfs.io" - -type Service interface { - io.Closer - RegisterNotifee(Notifee) - UnregisterNotifee(Notifee) -} - -type Notifee interface { - HandlePeerFound(peer.PeerInfo) -} - -type mdnsService struct { - server *mdns.Server - service *mdns.MDNSService - host host.Host - - lk sync.Mutex - notifees []Notifee - interval time.Duration -} - -func getDialableListenAddrs(ph host.Host) ([]*net.TCPAddr, error) { - var out []*net.TCPAddr - for _, addr := range ph.Addrs() { - na, err := manet.ToNetAddr(addr) - if err != nil { - continue - } - tcp, ok := na.(*net.TCPAddr) - if ok { - out = append(out, tcp) - } - } - if len(out) == 0 { - return nil, errors.New("failed to find good external addr from peerhost") - } - return out, nil -} - -func NewMdnsService(peerhost host.Host, interval time.Duration) (Service, error) { - - // TODO: dont let mdns use logging... - golog.SetOutput(ioutil.Discard) - - var ipaddrs []net.IP - port := 4001 - - addrs, err := getDialableListenAddrs(peerhost) - if err != nil { - log.Warning(err) - } else { - port = addrs[0].Port - for _, a := range addrs { - ipaddrs = append(ipaddrs, a.IP) - } - } - - myid := peerhost.ID().Pretty() - - info := []string{myid} - service, err := mdns.NewMDNSService(myid, ServiceTag, "", "", port, ipaddrs, info) - if err != nil { - return nil, err - } - - // Create the mDNS server, defer shutdown - server, err := mdns.NewServer(&mdns.Config{Zone: service}) - if err != nil { - return nil, err - } - - s := &mdnsService{ - server: server, - service: service, - host: peerhost, - interval: interval, - } - - go s.pollForEntries() - - return s, nil -} - -func (m *mdnsService) Close() error { - return m.server.Shutdown() -} - -func (m *mdnsService) pollForEntries() { - ticker := time.NewTicker(m.interval) - for { - select { - case <-ticker.C: - entriesCh := make(chan *mdns.ServiceEntry, 16) - go func() { - for entry := range entriesCh { - m.handleEntry(entry) - } - }() - - qp := mdns.QueryParam{} - qp.Domain = "local" - qp.Entries = entriesCh - qp.Service = ServiceTag - qp.Timeout = time.Second * 5 - - err := mdns.Query(&qp) - if err != nil { - log.Error("mdns lookup error: ", err) - } - close(entriesCh) - } - } -} - -func (m *mdnsService) handleEntry(e *mdns.ServiceEntry) { - mpeer, err := peer.IDB58Decode(e.Info) - if err != nil { - log.Warning("Error parsing peer ID from mdns entry: ", err) - return - } - - if mpeer == m.host.ID() { - return - } - - maddr, err := manet.FromNetAddr(&net.TCPAddr{ - IP: e.AddrV4, - Port: e.Port, - }) - if err != nil { - log.Warning("Error parsing multiaddr from mdns entry: ", err) - return - } - - pi := peer.PeerInfo{ - ID: mpeer, - Addrs: []ma.Multiaddr{maddr}, - } - - m.lk.Lock() - for _, n := range m.notifees { - n.HandlePeerFound(pi) - } - m.lk.Unlock() -} - -func (m *mdnsService) RegisterNotifee(n Notifee) { - m.lk.Lock() - m.notifees = append(m.notifees, n) - m.lk.Unlock() -} - -func (m *mdnsService) UnregisterNotifee(n Notifee) { - m.lk.Lock() - found := -1 - for i, notif := range m.notifees { - if notif == n { - found = i - break - } - } - if found != -1 { - m.notifees = append(m.notifees[:found], m.notifees[found+1:]...) - } - m.lk.Unlock() -} diff --git a/p2p/host/basic/basic_host.go b/p2p/host/basic/basic_host.go deleted file mode 100644 index 65987e7d803..00000000000 --- a/p2p/host/basic/basic_host.go +++ /dev/null @@ -1,268 +0,0 @@ -package basichost - -import ( - "io" - - ma "github.com/ipfs/go-ipfs/Godeps/_workspace/src/github.com/jbenet/go-multiaddr" - goprocess "github.com/ipfs/go-ipfs/Godeps/_workspace/src/github.com/jbenet/goprocess" - context "github.com/ipfs/go-ipfs/Godeps/_workspace/src/golang.org/x/net/context" - metrics "github.com/ipfs/go-ipfs/metrics" - mstream "github.com/ipfs/go-ipfs/metrics/stream" - logging "github.com/ipfs/go-ipfs/vendor/QmQg1J6vikuXF9oDvm4wpdeAUvvkVEKW1EYDw9HhTMnP2b/go-log" - - inet "github.com/ipfs/go-ipfs/p2p/net" - peer "github.com/ipfs/go-ipfs/p2p/peer" - protocol "github.com/ipfs/go-ipfs/p2p/protocol" - identify "github.com/ipfs/go-ipfs/p2p/protocol/identify" - relay "github.com/ipfs/go-ipfs/p2p/protocol/relay" - - msmux "github.com/ipfs/go-ipfs/Godeps/_workspace/src/github.com/whyrusleeping/go-multistream" -) - -var log = logging.Logger("p2p/host/basic") - -// Option is a type used to pass in options to the host. -type Option int - -const ( - // NATPortMap makes the host attempt to open port-mapping in NAT devices - // for all its listeners. Pass in this option in the constructor to - // asynchronously a) find a gateway, b) open port mappings, c) republish - // port mappings periodically. The NATed addresses are included in the - // Host's Addrs() list. - NATPortMap Option = iota -) - -// BasicHost is the basic implementation of the host.Host interface. This -// particular host implementation: -// * uses a protocol muxer to mux per-protocol streams -// * uses an identity service to send + receive node information -// * uses a relay service to allow hosts to relay conns for each other -// * uses a nat service to establish NAT port mappings -type BasicHost struct { - network inet.Network - mux *msmux.MultistreamMuxer - ids *identify.IDService - relay *relay.RelayService - natmgr *natManager - - proc goprocess.Process - - bwc metrics.Reporter -} - -// New constructs and sets up a new *BasicHost with given Network -func New(net inet.Network, opts ...interface{}) *BasicHost { - h := &BasicHost{ - network: net, - mux: msmux.NewMultistreamMuxer(), - bwc: metrics.NewBandwidthCounter(), - } - - h.proc = goprocess.WithTeardown(func() error { - if h.natmgr != nil { - h.natmgr.Close() - } - - return h.Network().Close() - }) - - // setup host services - h.ids = identify.NewIDService(h) - - muxh := h.Mux().Handle - handle := func(s inet.Stream) { - muxh(s) - } - h.relay = relay.NewRelayService(h, handle) - - for _, o := range opts { - switch o := o.(type) { - case Option: - switch o { - case NATPortMap: - h.natmgr = newNatManager(h) - } - case metrics.Reporter: - h.bwc = o - } - } - - net.SetConnHandler(h.newConnHandler) - net.SetStreamHandler(h.newStreamHandler) - - return h -} - -// newConnHandler is the remote-opened conn handler for inet.Network -func (h *BasicHost) newConnHandler(c inet.Conn) { - h.ids.IdentifyConn(c) -} - -// newStreamHandler is the remote-opened stream handler for inet.Network -// TODO: this feels a bit wonky -func (h *BasicHost) newStreamHandler(s inet.Stream) { - protoID, handle, err := h.Mux().Negotiate(s) - if err != nil { - if err == io.EOF { - log.Debugf("protocol EOF: %s", s.Conn().RemotePeer()) - } else { - log.Warning("protocol mux failed: %s", err) - } - return - } - - logStream := mstream.WrapStream(s, protocol.ID(protoID), h.bwc) - - go handle(logStream) -} - -// ID returns the (local) peer.ID associated with this Host -func (h *BasicHost) ID() peer.ID { - return h.Network().LocalPeer() -} - -// Peerstore returns the Host's repository of Peer Addresses and Keys. -func (h *BasicHost) Peerstore() peer.Peerstore { - return h.Network().Peerstore() -} - -// Network returns the Network interface of the Host -func (h *BasicHost) Network() inet.Network { - return h.network -} - -// Mux returns the Mux multiplexing incoming streams to protocol handlers -func (h *BasicHost) Mux() *msmux.MultistreamMuxer { - return h.mux -} - -// IDService returns -func (h *BasicHost) IDService() *identify.IDService { - return h.ids -} - -// SetStreamHandler sets the protocol handler on the Host's Mux. -// This is equivalent to: -// host.Mux().SetHandler(proto, handler) -// (Threadsafe) -func (h *BasicHost) SetStreamHandler(pid protocol.ID, handler inet.StreamHandler) { - h.Mux().AddHandler(string(pid), func(rwc io.ReadWriteCloser) error { - handler(rwc.(inet.Stream)) - return nil - }) -} - -// RemoveStreamHandler returns .. -func (h *BasicHost) RemoveStreamHandler(pid protocol.ID) { - h.Mux().RemoveHandler(string(pid)) -} - -// NewStream opens a new stream to given peer p, and writes a p2p/protocol -// header with given protocol.ID. If there is no connection to p, attempts -// to create one. If ProtocolID is "", writes no header. -// (Threadsafe) -func (h *BasicHost) NewStream(pid protocol.ID, p peer.ID) (inet.Stream, error) { - s, err := h.Network().NewStream(p) - if err != nil { - return nil, err - } - - logStream := mstream.WrapStream(s, pid, h.bwc) - - lzcon := msmux.NewMSSelect(logStream, string(pid)) - return &streamWrapper{ - Stream: logStream, - rw: lzcon, - }, nil -} - -// Connect ensures there is a connection between this host and the peer with -// given peer.ID. Connect will absorb the addresses in pi into its internal -// peerstore. If there is not an active connection, Connect will issue a -// h.Network.Dial, and block until a connection is open, or an error is -// returned. // TODO: Relay + NAT. -func (h *BasicHost) Connect(ctx context.Context, pi peer.PeerInfo) error { - - // absorb addresses into peerstore - h.Peerstore().AddAddrs(pi.ID, pi.Addrs, peer.TempAddrTTL) - - cs := h.Network().ConnsToPeer(pi.ID) - if len(cs) > 0 { - return nil - } - - return h.dialPeer(ctx, pi.ID) -} - -// dialPeer opens a connection to peer, and makes sure to identify -// the connection once it has been opened. -func (h *BasicHost) dialPeer(ctx context.Context, p peer.ID) error { - log.Debugf("host %s dialing %s", h.ID, p) - c, err := h.Network().DialPeer(ctx, p) - if err != nil { - return err - } - - // identify the connection before returning. - done := make(chan struct{}) - go func() { - h.ids.IdentifyConn(c) - close(done) - }() - - // respect don contexteone - select { - case <-done: - case <-ctx.Done(): - return ctx.Err() - } - - log.Debugf("host %s finished dialing %s", h.ID, p) - return nil -} - -// Addrs returns all the addresses of BasicHost at this moment in time. -// It's ok to not include addresses if they're not available to be used now. -func (h *BasicHost) Addrs() []ma.Multiaddr { - addrs, err := h.Network().InterfaceListenAddresses() - if err != nil { - log.Debug("error retrieving network interface addrs") - } - - if h.ids != nil { // add external observed addresses - addrs = append(addrs, h.ids.OwnObservedAddrs()...) - } - - if h.natmgr != nil { // natmgr is nil if we do not use nat option. - nat := h.natmgr.NAT() - if nat != nil { // nat is nil if not ready, or no nat is available. - addrs = append(addrs, nat.ExternalAddrs()...) - } - } - - return addrs -} - -// Close shuts down the Host's services (network, etc). -func (h *BasicHost) Close() error { - return h.proc.Close() -} - -// GetBandwidthReporter exposes the Host's bandiwth metrics reporter -func (h *BasicHost) GetBandwidthReporter() metrics.Reporter { - return h.bwc -} - -type streamWrapper struct { - inet.Stream - rw io.ReadWriter -} - -func (s *streamWrapper) Read(b []byte) (int, error) { - return s.rw.Read(b) -} - -func (s *streamWrapper) Write(b []byte) (int, error) { - return s.rw.Write(b) -} diff --git a/p2p/host/basic/basic_host_test.go b/p2p/host/basic/basic_host_test.go deleted file mode 100644 index bb4408d6f12..00000000000 --- a/p2p/host/basic/basic_host_test.go +++ /dev/null @@ -1,63 +0,0 @@ -package basichost_test - -import ( - "bytes" - "io" - "testing" - - inet "github.com/ipfs/go-ipfs/p2p/net" - protocol "github.com/ipfs/go-ipfs/p2p/protocol" - testutil "github.com/ipfs/go-ipfs/p2p/test/util" - - context "github.com/ipfs/go-ipfs/Godeps/_workspace/src/golang.org/x/net/context" -) - -func TestHostSimple(t *testing.T) { - - ctx := context.Background() - h1 := testutil.GenHostSwarm(t, ctx) - h2 := testutil.GenHostSwarm(t, ctx) - defer h1.Close() - defer h2.Close() - - h2pi := h2.Peerstore().PeerInfo(h2.ID()) - if err := h1.Connect(ctx, h2pi); err != nil { - t.Fatal(err) - } - - piper, pipew := io.Pipe() - h2.SetStreamHandler(protocol.TestingID, func(s inet.Stream) { - defer s.Close() - w := io.MultiWriter(s, pipew) - io.Copy(w, s) // mirror everything - }) - - s, err := h1.NewStream(protocol.TestingID, h2pi.ID) - if err != nil { - t.Fatal(err) - } - - // write to the stream - buf1 := []byte("abcdefghijkl") - if _, err := s.Write(buf1); err != nil { - t.Fatal(err) - } - - // get it from the stream (echoed) - buf2 := make([]byte, len(buf1)) - if _, err := io.ReadFull(s, buf2); err != nil { - t.Fatal(err) - } - if !bytes.Equal(buf1, buf2) { - t.Fatal("buf1 != buf2 -- %x != %x", buf1, buf2) - } - - // get it from the pipe (tee) - buf3 := make([]byte, len(buf1)) - if _, err := io.ReadFull(piper, buf3); err != nil { - t.Fatal(err) - } - if !bytes.Equal(buf1, buf3) { - t.Fatal("buf1 != buf3 -- %x != %x", buf1, buf3) - } -} diff --git a/p2p/host/basic/natmgr.go b/p2p/host/basic/natmgr.go deleted file mode 100644 index 04fa5a140df..00000000000 --- a/p2p/host/basic/natmgr.go +++ /dev/null @@ -1,228 +0,0 @@ -package basichost - -import ( - "sync" - - ma "github.com/ipfs/go-ipfs/Godeps/_workspace/src/github.com/jbenet/go-multiaddr" - goprocess "github.com/ipfs/go-ipfs/Godeps/_workspace/src/github.com/jbenet/goprocess" - context "github.com/ipfs/go-ipfs/Godeps/_workspace/src/golang.org/x/net/context" - - inat "github.com/ipfs/go-ipfs/p2p/nat" - inet "github.com/ipfs/go-ipfs/p2p/net" - lgbl "github.com/ipfs/go-ipfs/util/eventlog/loggables" -) - -// natManager takes care of adding + removing port mappings to the nat. -// Initialized with the host if it has a NATPortMap option enabled. -// natManager receives signals from the network, and check on nat mappings: -// * natManager listens to the network and adds or closes port mappings -// as the network signals Listen() or ListenClose(). -// * closing the natManager closes the nat and its mappings. -type natManager struct { - host *BasicHost - natmu sync.RWMutex // guards nat (ready could obviate this mutex, but safety first.) - nat *inat.NAT - - ready chan struct{} // closed once the nat is ready to process port mappings - proc goprocess.Process // natManager has a process + children. can be closed. -} - -func newNatManager(host *BasicHost) *natManager { - nmgr := &natManager{ - host: host, - ready: make(chan struct{}), - proc: goprocess.WithParent(host.proc), - } - - // teardown - nmgr.proc = goprocess.WithTeardown(func() error { - // on closing, unregister from network notifications. - host.Network().StopNotify((*nmgrNetNotifiee)(nmgr)) - return nil - }) - - // host is our parent. close when host closes. - host.proc.AddChild(nmgr.proc) - - // discover the nat. - nmgr.discoverNAT() - return nmgr -} - -// Close closes the natManager, closing the underlying nat -// and unregistering from network events. -func (nmgr *natManager) Close() error { - return nmgr.proc.Close() -} - -// Ready returns a channel which will be closed when the NAT has been found -// and is ready to be used, or the search process is done. -func (nmgr *natManager) Ready() <-chan struct{} { - return nmgr.ready -} - -func (nmgr *natManager) discoverNAT() { - - nmgr.proc.Go(func(worker goprocess.Process) { - // inat.DiscoverNAT blocks until the nat is found or a timeout - // is reached. we unfortunately cannot specify timeouts-- the - // library we're using just blocks. - // - // Note: on early shutdown, there may be a case where we're trying - // to close before DiscoverNAT() returns. Since we cant cancel it - // (library) we can choose to (1) drop the result and return early, - // or (2) wait until it times out to exit. For now we choose (2), - // to avoid leaking resources in a non-obvious way. the only case - // this affects is when the daemon is being started up and _immediately_ - // asked to close. other services are also starting up, so ok to wait. - discoverdone := make(chan struct{}) - var nat *inat.NAT - go func() { - defer close(discoverdone) - nat = inat.DiscoverNAT() - }() - - // by this point -- after finding the NAT -- we may have already - // be closing. if so, just exit. - select { - case <-worker.Closing(): - return - case <-discoverdone: - if nat == nil { // no nat, or failed to get it. - return - } - } - - // wire up the nat to close when nmgr closes. - // nmgr.proc is our parent, and waiting for us. - nmgr.proc.AddChild(nat.Process()) - - // set the nat. - nmgr.natmu.Lock() - nmgr.nat = nat - nmgr.natmu.Unlock() - - // signal that we're ready to process nat mappings: - close(nmgr.ready) - - // sign natManager up for network notifications - // we need to sign up here to avoid missing some notifs - // before the NAT has been found. - nmgr.host.Network().Notify((*nmgrNetNotifiee)(nmgr)) - - // if any interfaces were brought up while we were setting up - // the nat, now is the time to setup port mappings for them. - // we release ready, then grab them to avoid losing any. adding - // a port mapping is idempotent, so its ok to add the same twice. - addrs := nmgr.host.Network().ListenAddresses() - for _, addr := range addrs { - // we do it async because it's slow and we may want to close beforehand - go addPortMapping(nmgr, addr) - } - }) -} - -// NAT returns the natManager's nat object. this may be nil, if -// (a) the search process is still ongoing, or (b) the search process -// found no nat. Clients must check whether the return value is nil. -func (nmgr *natManager) NAT() *inat.NAT { - nmgr.natmu.Lock() - defer nmgr.natmu.Unlock() - return nmgr.nat -} - -func addPortMapping(nmgr *natManager, intaddr ma.Multiaddr) { - nat := nmgr.NAT() - if nat == nil { - panic("natManager addPortMapping called without a nat.") - } - - // first, check if the port mapping already exists. - for _, mapping := range nat.Mappings() { - if mapping.InternalAddr().Equal(intaddr) { - return // it exists! return. - } - } - - ctx := context.TODO() - lm := make(lgbl.DeferredMap) - lm["internalAddr"] = func() interface{} { return intaddr.String() } - - defer log.EventBegin(ctx, "natMgrAddPortMappingWait", lm).Done() - - select { - case <-nmgr.proc.Closing(): - lm["outcome"] = "cancelled" - return // no use. - case <-nmgr.ready: // wait until it's ready. - } - - // actually start the port map (sub-event because waiting may take a while) - defer log.EventBegin(ctx, "natMgrAddPortMapping", lm).Done() - - // get the nat - m, err := nat.NewMapping(intaddr) - if err != nil { - lm["outcome"] = "failure" - lm["error"] = err - return - } - - extaddr, err := m.ExternalAddr() - if err != nil { - lm["outcome"] = "failure" - lm["error"] = err - return - } - - lm["outcome"] = "success" - lm["externalAddr"] = func() interface{} { return extaddr.String() } - log.Infof("established nat port mapping: %s <--> %s", intaddr, extaddr) -} - -func rmPortMapping(nmgr *natManager, intaddr ma.Multiaddr) { - nat := nmgr.NAT() - if nat == nil { - panic("natManager rmPortMapping called without a nat.") - } - - // list the port mappings (it may be gone on it's own, so we need to - // check this list, and not store it ourselves behind the scenes) - - // close mappings for this internal address. - for _, mapping := range nat.Mappings() { - if mapping.InternalAddr().Equal(intaddr) { - mapping.Close() - } - } -} - -// nmgrNetNotifiee implements the network notification listening part -// of the natManager. this is merely listening to Listen() and ListenClose() -// events. -type nmgrNetNotifiee natManager - -func (nn *nmgrNetNotifiee) natManager() *natManager { - return (*natManager)(nn) -} - -func (nn *nmgrNetNotifiee) Listen(n inet.Network, addr ma.Multiaddr) { - if nn.natManager().NAT() == nil { - return // not ready or doesnt exist. - } - - addPortMapping(nn.natManager(), addr) -} - -func (nn *nmgrNetNotifiee) ListenClose(n inet.Network, addr ma.Multiaddr) { - if nn.natManager().NAT() == nil { - return // not ready or doesnt exist. - } - - rmPortMapping(nn.natManager(), addr) -} - -func (nn *nmgrNetNotifiee) Connected(inet.Network, inet.Conn) {} -func (nn *nmgrNetNotifiee) Disconnected(inet.Network, inet.Conn) {} -func (nn *nmgrNetNotifiee) OpenedStream(inet.Network, inet.Stream) {} -func (nn *nmgrNetNotifiee) ClosedStream(inet.Network, inet.Stream) {} diff --git a/p2p/host/host.go b/p2p/host/host.go deleted file mode 100644 index 014aa0a1a3d..00000000000 --- a/p2p/host/host.go +++ /dev/null @@ -1,65 +0,0 @@ -package host - -import ( - ma "github.com/ipfs/go-ipfs/Godeps/_workspace/src/github.com/jbenet/go-multiaddr" - context "github.com/ipfs/go-ipfs/Godeps/_workspace/src/golang.org/x/net/context" - metrics "github.com/ipfs/go-ipfs/metrics" - inet "github.com/ipfs/go-ipfs/p2p/net" - peer "github.com/ipfs/go-ipfs/p2p/peer" - protocol "github.com/ipfs/go-ipfs/p2p/protocol" - logging "github.com/ipfs/go-ipfs/vendor/QmQg1J6vikuXF9oDvm4wpdeAUvvkVEKW1EYDw9HhTMnP2b/go-log" - - msmux "github.com/ipfs/go-ipfs/Godeps/_workspace/src/github.com/whyrusleeping/go-multistream" -) - -var log = logging.Logger("p2p/host") - -// Host is an object participating in a p2p network, which -// implements protocols or provides services. It handles -// requests like a Server, and issues requests like a Client. -// It is called Host because it is both Server and Client (and Peer -// may be confusing). -type Host interface { - // ID returns the (local) peer.ID associated with this Host - ID() peer.ID - - // Peerstore returns the Host's repository of Peer Addresses and Keys. - Peerstore() peer.Peerstore - - // Returns the listen addresses of the Host - Addrs() []ma.Multiaddr - - // Networks returns the Network interface of the Host - Network() inet.Network - - // Mux returns the Mux multiplexing incoming streams to protocol handlers - Mux() *msmux.MultistreamMuxer - - // Connect ensures there is a connection between this host and the peer with - // given peer.ID. Connect will absorb the addresses in pi into its internal - // peerstore. If there is not an active connection, Connect will issue a - // h.Network.Dial, and block until a connection is open, or an error is - // returned. // TODO: Relay + NAT. - Connect(ctx context.Context, pi peer.PeerInfo) error - - // SetStreamHandler sets the protocol handler on the Host's Mux. - // This is equivalent to: - // host.Mux().SetHandler(proto, handler) - // (Threadsafe) - SetStreamHandler(pid protocol.ID, handler inet.StreamHandler) - - // RemoveStreamHandler removes a handler on the mux that was set by - // SetStreamHandler - RemoveStreamHandler(pid protocol.ID) - - // NewStream opens a new stream to given peer p, and writes a p2p/protocol - // header with given protocol.ID. If there is no connection to p, attempts - // to create one. If ProtocolID is "", writes no header. - // (Threadsafe) - NewStream(pid protocol.ID, p peer.ID) (inet.Stream, error) - - // Close shuts down the host, its Network, and services. - Close() error - - GetBandwidthReporter() metrics.Reporter -} diff --git a/p2p/host/routed/routed.go b/p2p/host/routed/routed.go deleted file mode 100644 index 5723f1b2eeb..00000000000 --- a/p2p/host/routed/routed.go +++ /dev/null @@ -1,124 +0,0 @@ -package routedhost - -import ( - "fmt" - "time" - - ma "github.com/ipfs/go-ipfs/Godeps/_workspace/src/github.com/jbenet/go-multiaddr" - context "github.com/ipfs/go-ipfs/Godeps/_workspace/src/golang.org/x/net/context" - lgbl "github.com/ipfs/go-ipfs/util/eventlog/loggables" - logging "github.com/ipfs/go-ipfs/vendor/QmQg1J6vikuXF9oDvm4wpdeAUvvkVEKW1EYDw9HhTMnP2b/go-log" - - metrics "github.com/ipfs/go-ipfs/metrics" - host "github.com/ipfs/go-ipfs/p2p/host" - inet "github.com/ipfs/go-ipfs/p2p/net" - peer "github.com/ipfs/go-ipfs/p2p/peer" - protocol "github.com/ipfs/go-ipfs/p2p/protocol" - routing "github.com/ipfs/go-ipfs/routing" - - msmux "github.com/ipfs/go-ipfs/Godeps/_workspace/src/github.com/whyrusleeping/go-multistream" -) - -var log = logging.Logger("p2p/host/routed") - -// AddressTTL is the expiry time for our addresses. -// We expire them quickly. -const AddressTTL = time.Second * 10 - -// RoutedHost is a p2p Host that includes a routing system. -// This allows the Host to find the addresses for peers when -// it does not have them. -type RoutedHost struct { - host host.Host // embedded other host. - route routing.IpfsRouting -} - -func Wrap(h host.Host, r routing.IpfsRouting) *RoutedHost { - return &RoutedHost{h, r} -} - -// Connect ensures there is a connection between this host and the peer with -// given peer.ID. See (host.Host).Connect for more information. -// -// RoutedHost's Connect differs in that if the host has no addresses for a -// given peer, it will use its routing system to try to find some. -func (rh *RoutedHost) Connect(ctx context.Context, pi peer.PeerInfo) error { - // first, check if we're already connected. - if len(rh.Network().ConnsToPeer(pi.ID)) > 0 { - return nil - } - - // if we were given some addresses, keep + use them. - if len(pi.Addrs) > 0 { - rh.Peerstore().AddAddrs(pi.ID, pi.Addrs, peer.TempAddrTTL) - } - - // Check if we have some addresses in our recent memory. - addrs := rh.Peerstore().Addrs(pi.ID) - if len(addrs) < 1 { - - // no addrs? find some with the routing system. - pi2, err := rh.route.FindPeer(ctx, pi.ID) - if err != nil { - return err // couldnt find any :( - } - if pi2.ID != pi.ID { - err = fmt.Errorf("routing failure: provided addrs for different peer") - logRoutingErrDifferentPeers(ctx, pi.ID, pi2.ID, err) - return err - } - addrs = pi2.Addrs - } - - // if we're here, we got some addrs. let's use our wrapped host to connect. - pi.Addrs = addrs - return rh.host.Connect(ctx, pi) -} - -func logRoutingErrDifferentPeers(ctx context.Context, wanted, got peer.ID, err error) { - lm := make(lgbl.DeferredMap) - lm["error"] = err - lm["wantedPeer"] = func() interface{} { return wanted.Pretty() } - lm["gotPeer"] = func() interface{} { return got.Pretty() } - log.Event(ctx, "routingError", lm) -} - -func (rh *RoutedHost) ID() peer.ID { - return rh.host.ID() -} - -func (rh *RoutedHost) Peerstore() peer.Peerstore { - return rh.host.Peerstore() -} - -func (rh *RoutedHost) Addrs() []ma.Multiaddr { - return rh.host.Addrs() -} - -func (rh *RoutedHost) Network() inet.Network { - return rh.host.Network() -} - -func (rh *RoutedHost) Mux() *msmux.MultistreamMuxer { - return rh.host.Mux() -} - -func (rh *RoutedHost) SetStreamHandler(pid protocol.ID, handler inet.StreamHandler) { - rh.host.SetStreamHandler(pid, handler) -} - -func (rh *RoutedHost) RemoveStreamHandler(pid protocol.ID) { - rh.host.RemoveStreamHandler(pid) -} - -func (rh *RoutedHost) NewStream(pid protocol.ID, p peer.ID) (inet.Stream, error) { - return rh.host.NewStream(pid, p) -} -func (rh *RoutedHost) Close() error { - // no need to close IpfsRouting. we dont own it. - return rh.host.Close() -} - -func (rh *RoutedHost) GetBandwidthReporter() metrics.Reporter { - return rh.host.GetBandwidthReporter() -} diff --git a/p2p/nat/nat.go b/p2p/nat/nat.go deleted file mode 100644 index 7ba84994d10..00000000000 --- a/p2p/nat/nat.go +++ /dev/null @@ -1,439 +0,0 @@ -package nat - -import ( - "errors" - "fmt" - "strconv" - "strings" - "sync" - "time" - - ma "github.com/ipfs/go-ipfs/Godeps/_workspace/src/github.com/jbenet/go-multiaddr" - manet "github.com/ipfs/go-ipfs/Godeps/_workspace/src/github.com/jbenet/go-multiaddr-net" - - nat "github.com/ipfs/go-ipfs/Godeps/_workspace/src/github.com/fd/go-nat" - goprocess "github.com/ipfs/go-ipfs/Godeps/_workspace/src/github.com/jbenet/goprocess" - periodic "github.com/ipfs/go-ipfs/Godeps/_workspace/src/github.com/jbenet/goprocess/periodic" - notifier "github.com/ipfs/go-ipfs/thirdparty/notifier" - logging "github.com/ipfs/go-ipfs/vendor/QmQg1J6vikuXF9oDvm4wpdeAUvvkVEKW1EYDw9HhTMnP2b/go-log" -) - -var ( - // ErrNoMapping signals no mapping exists for an address - ErrNoMapping = errors.New("mapping not established") -) - -var log = logging.Logger("nat") - -// MappingDuration is a default port mapping duration. -// Port mappings are renewed every (MappingDuration / 3) -const MappingDuration = time.Second * 60 - -// CacheTime is the time a mapping will cache an external address for -const CacheTime = time.Second * 15 - -// DiscoverNAT looks for a NAT device in the network and -// returns an object that can manage port mappings. -func DiscoverNAT() *NAT { - nat, err := nat.DiscoverGateway() - if err != nil { - log.Debug("DiscoverGateway error:", err) - return nil - } - addr, err := nat.GetDeviceAddress() - if err != nil { - log.Debug("DiscoverGateway address error:", err) - } else { - log.Debug("DiscoverGateway address:", addr) - } - return newNAT(nat) -} - -// NAT is an object that manages address port mappings in -// NATs (Network Address Translators). It is a long-running -// service that will periodically renew port mappings, -// and keep an up-to-date list of all the external addresses. -type NAT struct { - nat nat.NAT - proc goprocess.Process // manages nat mappings lifecycle - - mappingmu sync.RWMutex // guards mappings - mappings map[*mapping]struct{} - - Notifier -} - -func newNAT(realNAT nat.NAT) *NAT { - return &NAT{ - nat: realNAT, - proc: goprocess.WithParent(goprocess.Background()), - mappings: make(map[*mapping]struct{}), - } -} - -// Close shuts down all port mappings. NAT can no longer be used. -func (nat *NAT) Close() error { - return nat.proc.Close() -} - -// Process returns the nat's life-cycle manager, for making it listen -// to close signals. -func (nat *NAT) Process() goprocess.Process { - return nat.proc -} - -// Notifier is an object that assists NAT in notifying listeners. -// It is implemented using github.com/ipfs/go-ipfs/thirdparty/notifier -type Notifier struct { - n notifier.Notifier -} - -func (n *Notifier) notifyAll(notify func(n Notifiee)) { - n.n.NotifyAll(func(n notifier.Notifiee) { - notify(n.(Notifiee)) - }) -} - -// Notify signs up notifiee to listen to NAT events. -func (n *Notifier) Notify(notifiee Notifiee) { - n.n.Notify(n) -} - -// StopNotify stops signaling events to notifiee. -func (n *Notifier) StopNotify(notifiee Notifiee) { - n.n.StopNotify(notifiee) -} - -// Notifiee is an interface objects must implement to listen to NAT events. -type Notifiee interface { - - // Called every time a successful mapping happens - // Warning: the port mapping may have changed. If that is the - // case, both MappingSuccess and MappingChanged are called. - MappingSuccess(nat *NAT, m Mapping) - - // Called when mapping a port succeeds, but the mapping is - // with a different port than an earlier success. - MappingChanged(nat *NAT, m Mapping, oldport int, newport int) - - // Called when a port mapping fails. NAT will continue attempting after - // the next period. To stop trying, use: mapping.Close(). After this failure, - // mapping.ExternalPort() will be zero, and nat.ExternalAddrs() will not - // return the address for this mapping. With luck, the next attempt will - // succeed, without the client needing to do anything. - MappingFailed(nat *NAT, m Mapping, oldport int, err error) -} - -// Mapping represents a port mapping in a NAT. -type Mapping interface { - // NAT returns the NAT object this Mapping belongs to. - NAT() *NAT - - // Protocol returns the protocol of this port mapping. This is either - // "tcp" or "udp" as no other protocols are likely to be NAT-supported. - Protocol() string - - // InternalPort returns the internal device port. Mapping will continue to - // try to map InternalPort() to an external facing port. - InternalPort() int - - // ExternalPort returns the external facing port. If the mapping is not - // established, port will be 0 - ExternalPort() int - - // InternalAddr returns the internal address. - InternalAddr() ma.Multiaddr - - // ExternalAddr returns the external facing address. If the mapping is not - // established, addr will be nil, and and ErrNoMapping will be returned. - ExternalAddr() (addr ma.Multiaddr, err error) - - // Close closes the port mapping - Close() error -} - -// keeps republishing -type mapping struct { - sync.Mutex // guards all fields - - nat *NAT - proto string - intport int - extport int - intaddr ma.Multiaddr - proc goprocess.Process - - cached ma.Multiaddr - cacheTime time.Time -} - -func (m *mapping) NAT() *NAT { - m.Lock() - defer m.Unlock() - return m.nat -} - -func (m *mapping) Protocol() string { - m.Lock() - defer m.Unlock() - return m.proto -} - -func (m *mapping) InternalPort() int { - m.Lock() - defer m.Unlock() - return m.intport -} - -func (m *mapping) ExternalPort() int { - m.Lock() - defer m.Unlock() - return m.extport -} - -func (m *mapping) setExternalPort(p int) { - m.Lock() - defer m.Unlock() - m.extport = p -} - -func (m *mapping) InternalAddr() ma.Multiaddr { - m.Lock() - defer m.Unlock() - return m.intaddr -} - -func (m *mapping) ExternalAddr() (ma.Multiaddr, error) { - if time.Now().Sub(m.cacheTime) < CacheTime { - return m.cached, nil - } - - if m.ExternalPort() == 0 { // dont even try right now. - return nil, ErrNoMapping - } - - ip, err := m.nat.nat.GetExternalAddress() - if err != nil { - return nil, err - } - - ipmaddr, err := manet.FromIP(ip) - if err != nil { - return nil, fmt.Errorf("error parsing ip") - } - - // call m.ExternalPort again, as mapping may have changed under our feet. (tocttou) - extport := m.ExternalPort() - if extport == 0 { - return nil, ErrNoMapping - } - - tcp, err := ma.NewMultiaddr(fmt.Sprintf("/%s/%d", m.Protocol(), extport)) - if err != nil { - return nil, err - } - - maddr2 := ipmaddr.Encapsulate(tcp) - - m.cached = maddr2 - m.cacheTime = time.Now() - return maddr2, nil -} - -func (m *mapping) Close() error { - return m.proc.Close() -} - -// Mappings returns a slice of all NAT mappings -func (nat *NAT) Mappings() []Mapping { - nat.mappingmu.Lock() - maps2 := make([]Mapping, 0, len(nat.mappings)) - for m := range nat.mappings { - maps2 = append(maps2, m) - } - nat.mappingmu.Unlock() - return maps2 -} - -func (nat *NAT) addMapping(m *mapping) { - // make mapping automatically close when nat is closed. - nat.proc.AddChild(m.proc) - - nat.mappingmu.Lock() - nat.mappings[m] = struct{}{} - nat.mappingmu.Unlock() -} - -func (nat *NAT) rmMapping(m *mapping) { - nat.mappingmu.Lock() - delete(nat.mappings, m) - nat.mappingmu.Unlock() -} - -// NewMapping attemps to construct a mapping on protocol and internal port -// It will also periodically renew the mapping until the returned Mapping -// -- or its parent NAT -- is Closed. -// -// May not succeed, and mappings may change over time; -// NAT devices may not respect our port requests, and even lie. -// Clients should not store the mapped results, but rather always -// poll our object for the latest mappings. -func (nat *NAT) NewMapping(maddr ma.Multiaddr) (Mapping, error) { - if nat == nil { - return nil, fmt.Errorf("no nat available") - } - - network, addr, err := manet.DialArgs(maddr) - if err != nil { - return nil, fmt.Errorf("DialArgs failed on addr:", maddr.String()) - } - - switch network { - case "tcp", "tcp4", "tcp6": - network = "tcp" - case "udp", "udp4", "udp6": - network = "udp" - default: - return nil, fmt.Errorf("transport not supported by NAT: %s", network) - } - - intports := strings.Split(addr, ":")[1] - intport, err := strconv.Atoi(intports) - if err != nil { - return nil, err - } - - m := &mapping{ - nat: nat, - proto: network, - intport: intport, - intaddr: maddr, - } - m.proc = goprocess.WithTeardown(func() error { - nat.rmMapping(m) - return nil - }) - nat.addMapping(m) - - m.proc.AddChild(periodic.Every(MappingDuration/3, func(worker goprocess.Process) { - nat.establishMapping(m) - })) - - // do it once synchronously, so first mapping is done right away, and before exiting, - // allowing users -- in the optimistic case -- to use results right after. - nat.establishMapping(m) - return m, nil -} - -func (nat *NAT) establishMapping(m *mapping) { - oldport := m.ExternalPort() - log.Debugf("Attempting port map: %s/%d", m.Protocol(), m.InternalPort()) - newport, err := nat.nat.AddPortMapping(m.Protocol(), m.InternalPort(), "http", MappingDuration) - - failure := func() { - m.setExternalPort(0) // clear mapping - // TODO: log.Event - log.Debugf("failed to establish port mapping: %s", err) - nat.Notifier.notifyAll(func(n Notifiee) { - n.MappingFailed(nat, m, oldport, err) - }) - - // we do not close if the mapping failed, - // because it may work again next time. - } - - if err != nil || newport == 0 { - failure() - return - } - - m.setExternalPort(newport) - ext, err := m.ExternalAddr() - if err != nil { - log.Debugf("NAT Mapping addr error: %s %s", m.InternalAddr(), err) - failure() - return - } - - log.Debugf("NAT Mapping: %s --> %s", m.InternalAddr(), ext) - if oldport != 0 && newport != oldport { - log.Debugf("failed to renew same port mapping: ch %d -> %d", oldport, newport) - nat.Notifier.notifyAll(func(n Notifiee) { - n.MappingChanged(nat, m, oldport, newport) - }) - } - - nat.Notifier.notifyAll(func(n Notifiee) { - n.MappingSuccess(nat, m) - }) -} - -// PortMapAddrs attempts to open (and continue to keep open) -// port mappings for given addrs. This function blocks until -// all addresses have been tried. This allows clients to -// retrieve results immediately after: -// -// nat.PortMapAddrs(addrs) -// mapped := nat.ExternalAddrs() -// -// Some may not succeed, and mappings may change over time; -// NAT devices may not respect our port requests, and even lie. -// Clients should not store the mapped results, but rather always -// poll our object for the latest mappings. -func (nat *NAT) PortMapAddrs(addrs []ma.Multiaddr) { - // spin off addr mappings independently. - var wg sync.WaitGroup - for _, addr := range addrs { - // do all of them concurrently - wg.Add(1) - go func() { - defer wg.Done() - nat.NewMapping(addr) - }() - } - wg.Wait() -} - -// MappedAddrs returns address mappings NAT believes have been -// successfully established. Unsuccessful mappings are nil. This is: -// -// map[internalAddr]externalAddr -// -// This set of mappings _may not_ be correct, as NAT devices are finicky. -// Consider this with _best effort_ semantics. -func (nat *NAT) MappedAddrs() map[ma.Multiaddr]ma.Multiaddr { - - mappings := nat.Mappings() - addrmap := make(map[ma.Multiaddr]ma.Multiaddr, len(mappings)) - - for _, m := range mappings { - i := m.InternalAddr() - e, err := m.ExternalAddr() - if err != nil { - addrmap[i] = nil - } else { - addrmap[i] = e - } - } - return addrmap -} - -// ExternalAddrs returns a list of addresses that NAT believes have -// been successfully established. Unsuccessful mappings are omitted, -// so nat.ExternalAddrs() may return less addresses than nat.InternalAddrs(). -// To see which addresses are mapped, use nat.MappedAddrs(). -// -// This set of mappings _may not_ be correct, as NAT devices are finicky. -// Consider this with _best effort_ semantics. -func (nat *NAT) ExternalAddrs() []ma.Multiaddr { - mappings := nat.Mappings() - addrs := make([]ma.Multiaddr, 0, len(mappings)) - for _, m := range mappings { - a, err := m.ExternalAddr() - if err != nil { - continue // this mapping not currently successful. - } - addrs = append(addrs, a) - } - return addrs -} diff --git a/p2p/net/README.md b/p2p/net/README.md deleted file mode 100644 index a1cf6aacf20..00000000000 --- a/p2p/net/README.md +++ /dev/null @@ -1,17 +0,0 @@ -# Network - -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: - -- `Conn` - a connection to a single Peer - - `MultiConn` - a set of connections to a single Peer - - `SecureConn` - an encrypted (tls-like) connection -- `Swarm` - holds connections to Peers, multiplexes from/to each `MultiConn` -- `Muxer` - multiplexes between `Services` and `Swarm`. Handles `Requet/Reply`. - - `Service` - connects between an outside client service and Network. - - `Handler` - the client service part that handles requests - -It looks a bit like this: - -
-![](https://docs.google.com/drawings/d/1FvU7GImRsb9GvAWDDo1le85jIrnFJNVB_OTPXC15WwM/pub?h=480) -
diff --git a/p2p/net/conn/conn.go b/p2p/net/conn/conn.go deleted file mode 100644 index c195b93a20b..00000000000 --- a/p2p/net/conn/conn.go +++ /dev/null @@ -1,145 +0,0 @@ -package conn - -import ( - "fmt" - "io" - "net" - "time" - - mpool "github.com/ipfs/go-ipfs/Godeps/_workspace/src/github.com/jbenet/go-msgio/mpool" - ma "github.com/ipfs/go-ipfs/Godeps/_workspace/src/github.com/jbenet/go-multiaddr" - manet "github.com/ipfs/go-ipfs/Godeps/_workspace/src/github.com/jbenet/go-multiaddr-net" - context "github.com/ipfs/go-ipfs/Godeps/_workspace/src/golang.org/x/net/context" - ic "github.com/ipfs/go-ipfs/p2p/crypto" - peer "github.com/ipfs/go-ipfs/p2p/peer" - u "github.com/ipfs/go-ipfs/util" - lgbl "github.com/ipfs/go-ipfs/util/eventlog/loggables" - logging "github.com/ipfs/go-ipfs/vendor/QmQg1J6vikuXF9oDvm4wpdeAUvvkVEKW1EYDw9HhTMnP2b/go-log" -) - -var log = logging.Logger("conn") - -// ReleaseBuffer puts the given byte array back into the buffer pool, -// first verifying that it is the correct size -func ReleaseBuffer(b []byte) { - log.Debugf("Releasing buffer! (cap,size = %d, %d)", cap(b), len(b)) - mpool.ByteSlicePool.Put(uint32(cap(b)), b) -} - -// singleConn represents a single connection to another Peer (IPFS Node). -type singleConn struct { - local peer.ID - remote peer.ID - maconn manet.Conn - event io.Closer -} - -// newConn constructs a new connection -func newSingleConn(ctx context.Context, local, remote peer.ID, maconn manet.Conn) (Conn, error) { - ml := lgbl.Dial("conn", local, remote, maconn.LocalMultiaddr(), maconn.RemoteMultiaddr()) - - conn := &singleConn{ - local: local, - remote: remote, - maconn: maconn, - event: log.EventBegin(ctx, "connLifetime", ml), - } - - log.Debugf("newSingleConn %p: %v to %v", conn, local, remote) - return conn, nil -} - -// close is the internal close function, called by ContextCloser.Close -func (c *singleConn) Close() error { - defer func() { - if c.event != nil { - c.event.Close() - c.event = nil - } - }() - - // close underlying connection - return c.maconn.Close() -} - -// ID is an identifier unique to this connection. -func (c *singleConn) ID() string { - return ID(c) -} - -func (c *singleConn) String() string { - return String(c, "singleConn") -} - -func (c *singleConn) LocalAddr() net.Addr { - return c.maconn.LocalAddr() -} - -func (c *singleConn) RemoteAddr() net.Addr { - return c.maconn.RemoteAddr() -} - -func (c *singleConn) LocalPrivateKey() ic.PrivKey { - return nil -} - -func (c *singleConn) RemotePublicKey() ic.PubKey { - return nil -} - -func (c *singleConn) SetDeadline(t time.Time) error { - return c.maconn.SetDeadline(t) -} -func (c *singleConn) SetReadDeadline(t time.Time) error { - return c.maconn.SetReadDeadline(t) -} - -func (c *singleConn) SetWriteDeadline(t time.Time) error { - return c.maconn.SetWriteDeadline(t) -} - -// LocalMultiaddr is the Multiaddr on this side -func (c *singleConn) LocalMultiaddr() ma.Multiaddr { - return c.maconn.LocalMultiaddr() -} - -// RemoteMultiaddr is the Multiaddr on the remote side -func (c *singleConn) RemoteMultiaddr() ma.Multiaddr { - return c.maconn.RemoteMultiaddr() -} - -// LocalPeer is the Peer on this side -func (c *singleConn) LocalPeer() peer.ID { - return c.local -} - -// RemotePeer is the Peer on the remote side -func (c *singleConn) RemotePeer() peer.ID { - return c.remote -} - -// Read reads data, net.Conn style -func (c *singleConn) Read(buf []byte) (int, error) { - return c.maconn.Read(buf) -} - -// Write writes data, net.Conn style -func (c *singleConn) Write(buf []byte) (int, error) { - return c.maconn.Write(buf) -} - -// ID returns the ID of a given Conn. -func ID(c Conn) string { - l := fmt.Sprintf("%s/%s", c.LocalMultiaddr(), c.LocalPeer().Pretty()) - r := fmt.Sprintf("%s/%s", c.RemoteMultiaddr(), c.RemotePeer().Pretty()) - lh := u.Hash([]byte(l)) - rh := u.Hash([]byte(r)) - ch := u.XOR(lh, rh) - return peer.ID(ch).Pretty() -} - -// String returns the user-friendly String representation of a conn -func String(c Conn, typ string) string { - return fmt.Sprintf("%s (%s) <-- %s %p --> (%s) %s", - c.LocalPeer(), c.LocalMultiaddr(), typ, c, c.RemoteMultiaddr(), c.RemotePeer()) -} diff --git a/p2p/net/conn/conn_test.go b/p2p/net/conn/conn_test.go deleted file mode 100644 index 25b23072b1b..00000000000 --- a/p2p/net/conn/conn_test.go +++ /dev/null @@ -1,136 +0,0 @@ -package conn - -import ( - "bytes" - "fmt" - "runtime" - "sync" - "testing" - "time" - - msgio "github.com/ipfs/go-ipfs/Godeps/_workspace/src/github.com/jbenet/go-msgio" - context "github.com/ipfs/go-ipfs/Godeps/_workspace/src/golang.org/x/net/context" - travis "github.com/ipfs/go-ipfs/util/testutil/ci/travis" -) - -func msgioWrap(c Conn) msgio.ReadWriter { - return msgio.NewReadWriter(c) -} - -func testOneSendRecv(t *testing.T, c1, c2 Conn) { - mc1 := msgioWrap(c1) - mc2 := msgioWrap(c2) - - log.Debugf("testOneSendRecv from %s to %s", c1.LocalPeer(), c2.LocalPeer()) - m1 := []byte("hello") - if err := mc1.WriteMsg(m1); err != nil { - t.Fatal(err) - } - m2, err := mc2.ReadMsg() - if err != nil { - t.Fatal(err) - } - if !bytes.Equal(m1, m2) { - t.Fatal("failed to send: %s %s", m1, m2) - } -} - -func testNotOneSendRecv(t *testing.T, c1, c2 Conn) { - mc1 := msgioWrap(c1) - mc2 := msgioWrap(c2) - - m1 := []byte("hello") - if err := mc1.WriteMsg(m1); err == nil { - t.Fatal("write should have failed", err) - } - _, err := mc2.ReadMsg() - if err == nil { - t.Fatal("read should have failed", err) - } -} - -func TestClose(t *testing.T) { - // t.Skip("Skipping in favor of another test") - - ctx, cancel := context.WithCancel(context.Background()) - defer cancel() - c1, c2, _, _ := setupSingleConn(t, ctx) - - testOneSendRecv(t, c1, c2) - testOneSendRecv(t, c2, c1) - - c1.Close() - testNotOneSendRecv(t, c1, c2) - - c2.Close() - testNotOneSendRecv(t, c2, c1) - testNotOneSendRecv(t, c1, c2) -} - -func TestCloseLeak(t *testing.T) { - // t.Skip("Skipping in favor of another test") - if testing.Short() { - t.SkipNow() - } - - if travis.IsRunning() { - t.Skip("this doesn't work well on travis") - } - - var wg sync.WaitGroup - - runPair := func(num int) { - ctx, cancel := context.WithCancel(context.Background()) - c1, c2, _, _ := setupSingleConn(t, ctx) - - mc1 := msgioWrap(c1) - mc2 := msgioWrap(c2) - - for i := 0; i < num; i++ { - b1 := []byte(fmt.Sprintf("beep%d", i)) - mc1.WriteMsg(b1) - b2, err := mc2.ReadMsg() - if err != nil { - panic(err) - } - if !bytes.Equal(b1, b2) { - panic(fmt.Errorf("bytes not equal: %s != %s", b1, b2)) - } - - b2 = []byte(fmt.Sprintf("boop%d", i)) - mc2.WriteMsg(b2) - b1, err = mc1.ReadMsg() - if err != nil { - panic(err) - } - if !bytes.Equal(b1, b2) { - panic(fmt.Errorf("bytes not equal: %s != %s", b1, b2)) - } - - <-time.After(time.Microsecond * 5) - } - - c1.Close() - c2.Close() - cancel() // close the listener - wg.Done() - } - - var cons = 5 - var msgs = 50 - log.Debugf("Running %d connections * %d msgs.\n", cons, msgs) - for i := 0; i < cons; i++ { - wg.Add(1) - go runPair(msgs) - } - - log.Debugf("Waiting...\n") - wg.Wait() - // done! - - <-time.After(time.Millisecond * 150) - if runtime.NumGoroutine() > 20 { - // panic("uncomment me to debug") - t.Fatal("leaking goroutines:", runtime.NumGoroutine()) - } -} diff --git a/p2p/net/conn/dial.go b/p2p/net/conn/dial.go deleted file mode 100644 index 76f4b35f660..00000000000 --- a/p2p/net/conn/dial.go +++ /dev/null @@ -1,198 +0,0 @@ -package conn - -import ( - "fmt" - "math/rand" - "strings" - - ma "github.com/ipfs/go-ipfs/Godeps/_workspace/src/github.com/jbenet/go-multiaddr" - manet "github.com/ipfs/go-ipfs/Godeps/_workspace/src/github.com/jbenet/go-multiaddr-net" - context "github.com/ipfs/go-ipfs/Godeps/_workspace/src/golang.org/x/net/context" - lgbl "github.com/ipfs/go-ipfs/util/eventlog/loggables" - - ci "github.com/ipfs/go-ipfs/p2p/crypto" - addrutil "github.com/ipfs/go-ipfs/p2p/net/swarm/addr" - transport "github.com/ipfs/go-ipfs/p2p/net/transport" - peer "github.com/ipfs/go-ipfs/p2p/peer" -) - -type WrapFunc func(transport.Conn) transport.Conn - -func NewDialer(p peer.ID, pk ci.PrivKey, wrap WrapFunc) *Dialer { - return &Dialer{ - LocalPeer: p, - PrivateKey: pk, - Wrapper: wrap, - } -} - -// String returns the string rep of d. -func (d *Dialer) String() string { - return fmt.Sprintf("", d.LocalPeer) -} - -// Dial connects to a peer over a particular address -// Ensures raddr is part of peer.Addresses() -// Example: d.DialAddr(ctx, peer.Addresses()[0], peer) -func (d *Dialer) Dial(ctx context.Context, raddr ma.Multiaddr, remote peer.ID) (Conn, error) { - logdial := lgbl.Dial("conn", d.LocalPeer, remote, nil, raddr) - logdial["encrypted"] = (d.PrivateKey != nil) // log wether this will be an encrypted dial or not. - defer log.EventBegin(ctx, "connDial", logdial).Done() - - var connOut Conn - var errOut error - done := make(chan struct{}) - - // do it async to ensure we respect don contexteone - go func() { - defer func() { - select { - case done <- struct{}{}: - case <-ctx.Done(): - } - }() - - maconn, err := d.rawConnDial(ctx, raddr, remote) - if err != nil { - errOut = err - return - } - - if d.Wrapper != nil { - maconn = d.Wrapper(maconn) - } - - c, err := newSingleConn(ctx, d.LocalPeer, remote, maconn) - if err != nil { - maconn.Close() - errOut = err - return - } - - if d.PrivateKey == nil || EncryptConnections == false { - log.Warning("dialer %s dialing INSECURELY %s at %s!", d, remote, raddr) - connOut = c - return - } - - c2, err := newSecureConn(ctx, d.PrivateKey, c) - if err != nil { - errOut = err - c.Close() - return - } - - connOut = c2 - }() - - select { - case <-ctx.Done(): - logdial["error"] = ctx.Err() - logdial["dial"] = "failure" - return nil, ctx.Err() - case <-done: - // whew, finished. - } - - if errOut != nil { - logdial["error"] = errOut - logdial["dial"] = "failure" - return nil, errOut - } - - logdial["dial"] = "success" - return connOut, nil -} - -func (d *Dialer) AddDialer(pd transport.Dialer) { - d.Dialers = append(d.Dialers, pd) -} - -// returns dialer that can dial the given address -func (d *Dialer) subDialerForAddr(raddr ma.Multiaddr) transport.Dialer { - for _, pd := range d.Dialers { - if pd.Matches(raddr) { - return pd - } - } - - return nil -} - -// rawConnDial dials the underlying net.Conn + manet.Conns -func (d *Dialer) rawConnDial(ctx context.Context, raddr ma.Multiaddr, remote peer.ID) (transport.Conn, error) { - if strings.HasPrefix(raddr.String(), "/ip4/0.0.0.0") { - log.Event(ctx, "connDialZeroAddr", lgbl.Dial("conn", d.LocalPeer, remote, nil, raddr)) - return nil, fmt.Errorf("Attempted to connect to zero address: %s", raddr) - } - - sd := d.subDialerForAddr(raddr) - if sd == nil { - return nil, fmt.Errorf("no dialer for %s", raddr) - } - - return sd.Dial(raddr) -} - -func pickLocalAddr(laddrs []ma.Multiaddr, raddr ma.Multiaddr) (laddr ma.Multiaddr) { - if len(laddrs) < 1 { - return nil - } - - // make sure that we ONLY use local addrs that match the remote addr. - laddrs = manet.AddrMatch(raddr, laddrs) - if len(laddrs) < 1 { - return nil - } - - // make sure that we ONLY use local addrs that CAN dial the remote addr. - // filter out all the local addrs that aren't capable - raddrIPLayer := ma.Split(raddr)[0] - raddrIsLoopback := manet.IsIPLoopback(raddrIPLayer) - raddrIsLinkLocal := manet.IsIP6LinkLocal(raddrIPLayer) - laddrs = addrutil.FilterAddrs(laddrs, func(a ma.Multiaddr) bool { - laddrIPLayer := ma.Split(a)[0] - laddrIsLoopback := manet.IsIPLoopback(laddrIPLayer) - laddrIsLinkLocal := manet.IsIP6LinkLocal(laddrIPLayer) - if laddrIsLoopback { // our loopback addrs can only dial loopbacks. - return raddrIsLoopback - } - if laddrIsLinkLocal { - return raddrIsLinkLocal // out linklocal addrs can only dial link locals. - } - return true - }) - - // TODO pick with a good heuristic - // we use a random one for now to prevent bad addresses from making nodes unreachable - // with a random selection, multiple tries may work. - return laddrs[rand.Intn(len(laddrs))] -} - -// MultiaddrProtocolsMatch returns whether two multiaddrs match in protocol stacks. -func MultiaddrProtocolsMatch(a, b ma.Multiaddr) bool { - ap := a.Protocols() - bp := b.Protocols() - - if len(ap) != len(bp) { - return false - } - - for i, api := range ap { - if api.Code != bp[i].Code { - return false - } - } - - return true -} - -// MultiaddrNetMatch returns the first Multiaddr found to match network. -func MultiaddrNetMatch(tgt ma.Multiaddr, srcs []ma.Multiaddr) ma.Multiaddr { - for _, a := range srcs { - if MultiaddrProtocolsMatch(tgt, a) { - return a - } - } - return nil -} diff --git a/p2p/net/conn/dial_test.go b/p2p/net/conn/dial_test.go deleted file mode 100644 index 164a8dbd7c6..00000000000 --- a/p2p/net/conn/dial_test.go +++ /dev/null @@ -1,321 +0,0 @@ -package conn - -import ( - "fmt" - "io" - "net" - "strings" - "testing" - "time" - - ic "github.com/ipfs/go-ipfs/p2p/crypto" - transport "github.com/ipfs/go-ipfs/p2p/net/transport" - peer "github.com/ipfs/go-ipfs/p2p/peer" - tu "github.com/ipfs/go-ipfs/util/testutil" - - ma "github.com/ipfs/go-ipfs/Godeps/_workspace/src/github.com/jbenet/go-multiaddr" - context "github.com/ipfs/go-ipfs/Godeps/_workspace/src/golang.org/x/net/context" -) - -func echoListen(ctx context.Context, listener Listener) { - for { - c, err := listener.Accept() - if err != nil { - - select { - case <-ctx.Done(): - return - default: - } - - if ne, ok := err.(net.Error); ok && ne.Temporary() { - <-time.After(time.Microsecond * 10) - continue - } - - log.Debugf("echoListen: listener appears to be closing") - return - } - - go echo(c.(Conn)) - } -} - -func echo(c Conn) { - io.Copy(c, c) -} - -func setupSecureConn(t *testing.T, ctx context.Context) (a, b Conn, p1, p2 tu.PeerNetParams) { - return setupConn(t, ctx, true) -} - -func setupSingleConn(t *testing.T, ctx context.Context) (a, b Conn, p1, p2 tu.PeerNetParams) { - return setupConn(t, ctx, false) -} - -func Listen(ctx context.Context, addr ma.Multiaddr, local peer.ID, sk ic.PrivKey) (Listener, error) { - list, err := transport.NewTCPTransport().Listen(addr) - if err != nil { - return nil, err - } - - return WrapTransportListener(ctx, list, local, sk) -} - -func dialer(t *testing.T, a ma.Multiaddr) transport.Dialer { - tpt := transport.NewTCPTransport() - tptd, err := tpt.Dialer(a) - if err != nil { - t.Fatal(err) - } - - return tptd -} - -func setupConn(t *testing.T, ctx context.Context, secure bool) (a, b Conn, p1, p2 tu.PeerNetParams) { - - p1 = tu.RandPeerNetParamsOrFatal(t) - p2 = tu.RandPeerNetParamsOrFatal(t) - - key1 := p1.PrivKey - key2 := p2.PrivKey - if !secure { - key1 = nil - key2 = nil - } - l1, err := Listen(ctx, p1.Addr, p1.ID, key1) - if err != nil { - t.Fatal(err) - } - p1.Addr = l1.Multiaddr() // Addr has been determined by kernel. - - d2 := &Dialer{ - LocalPeer: p2.ID, - PrivateKey: key2, - } - - d2.AddDialer(dialer(t, p2.Addr)) - - var c2 Conn - - done := make(chan error) - go func() { - defer close(done) - - var err error - c2, err = d2.Dial(ctx, p1.Addr, p1.ID) - if err != nil { - done <- err - return - } - - // if secure, need to read + write, as that's what triggers the handshake. - if secure { - if err := sayHello(c2); err != nil { - done <- err - } - } - }() - - c1, err := l1.Accept() - if err != nil { - t.Fatal("failed to accept", err) - } - - // if secure, need to read + write, as that's what triggers the handshake. - if secure { - if err := sayHello(c1); err != nil { - done <- err - } - } - - if err := <-done; err != nil { - t.Fatal(err) - } - - return c1.(Conn), c2, p1, p2 -} - -func sayHello(c net.Conn) error { - h := []byte("hello") - if _, err := c.Write(h); err != nil { - return err - } - if _, err := c.Read(h); err != nil { - return err - } - if string(h) != "hello" { - return fmt.Errorf("did not get hello") - } - return nil -} - -func testDialer(t *testing.T, secure bool) { - // t.Skip("Skipping in favor of another test") - - p1 := tu.RandPeerNetParamsOrFatal(t) - p2 := tu.RandPeerNetParamsOrFatal(t) - - key1 := p1.PrivKey - key2 := p2.PrivKey - if !secure { - key1 = nil - key2 = nil - t.Log("testing insecurely") - } else { - t.Log("testing securely") - } - - ctx, cancel := context.WithCancel(context.Background()) - l1, err := Listen(ctx, p1.Addr, p1.ID, key1) - if err != nil { - t.Fatal(err) - } - p1.Addr = l1.Multiaddr() // Addr has been determined by kernel. - - d2 := &Dialer{ - LocalPeer: p2.ID, - PrivateKey: key2, - } - d2.AddDialer(dialer(t, p2.Addr)) - - go echoListen(ctx, l1) - - c, err := d2.Dial(ctx, p1.Addr, p1.ID) - if err != nil { - t.Fatal("error dialing peer", err) - } - - // fmt.Println("sending") - mc := msgioWrap(c) - mc.WriteMsg([]byte("beep")) - mc.WriteMsg([]byte("boop")) - out, err := mc.ReadMsg() - if err != nil { - t.Fatal(err) - } - - // fmt.Println("recving", string(out)) - data := string(out) - if data != "beep" { - t.Error("unexpected conn output", data) - } - - out, err = mc.ReadMsg() - if err != nil { - t.Fatal(err) - } - - data = string(out) - if string(out) != "boop" { - t.Error("unexpected conn output", data) - } - - // fmt.Println("closing") - c.Close() - l1.Close() - cancel() -} - -func TestDialerInsecure(t *testing.T) { - // t.Skip("Skipping in favor of another test") - testDialer(t, false) -} - -func TestDialerSecure(t *testing.T) { - // t.Skip("Skipping in favor of another test") - testDialer(t, true) -} - -func testDialerCloseEarly(t *testing.T, secure bool) { - // t.Skip("Skipping in favor of another test") - - p1 := tu.RandPeerNetParamsOrFatal(t) - p2 := tu.RandPeerNetParamsOrFatal(t) - - key1 := p1.PrivKey - if !secure { - key1 = nil - t.Log("testing insecurely") - } else { - t.Log("testing securely") - } - - ctx, cancel := context.WithCancel(context.Background()) - l1, err := Listen(ctx, p1.Addr, p1.ID, key1) - if err != nil { - t.Fatal(err) - } - p1.Addr = l1.Multiaddr() // Addr has been determined by kernel. - - // lol nesting - d2 := &Dialer{ - LocalPeer: p2.ID, - // PrivateKey: key2, -- dont give it key. we'll just close the conn. - } - d2.AddDialer(dialer(t, p2.Addr)) - - errs := make(chan error, 100) - done := make(chan struct{}, 1) - gotclosed := make(chan struct{}, 1) - go func() { - defer func() { done <- struct{}{} }() - - c, err := l1.Accept() - if err != nil { - if strings.Contains(err.Error(), "closed") { - gotclosed <- struct{}{} - return - } - errs <- err - } - - if _, err := c.Write([]byte("hello")); err != nil { - gotclosed <- struct{}{} - return - } - - errs <- fmt.Errorf("wrote to conn") - }() - - c, err := d2.Dial(ctx, p1.Addr, p1.ID) - if err != nil { - t.Fatal(err) - } - c.Close() // close it early. - - readerrs := func() { - for { - select { - case e := <-errs: - t.Error(e) - default: - return - } - } - } - readerrs() - - l1.Close() - <-done - cancel() - readerrs() - close(errs) - - select { - case <-gotclosed: - default: - t.Error("did not get closed") - } -} - -// we dont do a handshake with singleConn, so cant "close early." -// func TestDialerCloseEarlyInsecure(t *testing.T) { -// // t.Skip("Skipping in favor of another test") -// testDialerCloseEarly(t, false) -// } - -func TestDialerCloseEarlySecure(t *testing.T) { - // t.Skip("Skipping in favor of another test") - testDialerCloseEarly(t, true) -} diff --git a/p2p/net/conn/interface.go b/p2p/net/conn/interface.go deleted file mode 100644 index b5fda20ac0e..00000000000 --- a/p2p/net/conn/interface.go +++ /dev/null @@ -1,102 +0,0 @@ -package conn - -import ( - "io" - "net" - "time" - - key "github.com/ipfs/go-ipfs/blocks/key" - ic "github.com/ipfs/go-ipfs/p2p/crypto" - filter "github.com/ipfs/go-ipfs/p2p/net/filter" - transport "github.com/ipfs/go-ipfs/p2p/net/transport" - peer "github.com/ipfs/go-ipfs/p2p/peer" - - ma "github.com/ipfs/go-ipfs/Godeps/_workspace/src/github.com/jbenet/go-multiaddr" -) - -// Map maps Keys (Peer.IDs) to Connections. -type Map map[key.Key]Conn - -type PeerConn interface { - io.Closer - - // LocalPeer (this side) ID, PrivateKey, and Address - LocalPeer() peer.ID - LocalPrivateKey() ic.PrivKey - LocalMultiaddr() ma.Multiaddr - - // RemotePeer ID, PublicKey, and Address - RemotePeer() peer.ID - RemotePublicKey() ic.PubKey - RemoteMultiaddr() ma.Multiaddr -} - -// Conn is a generic message-based Peer-to-Peer connection. -type Conn interface { - PeerConn - - // ID is an identifier unique to this connection. - ID() string - - // can't just say "net.Conn" cause we have duplicate methods. - LocalAddr() net.Addr - RemoteAddr() net.Addr - SetDeadline(t time.Time) error - SetReadDeadline(t time.Time) error - SetWriteDeadline(t time.Time) error - - io.Reader - io.Writer -} - -// Dialer is an object that can open connections. We could have a "convenience" -// Dial function as before, but it would have many arguments, as dialing is -// no longer simple (need a peerstore, a local peer, a context, a network, etc) -type Dialer struct { - // LocalPeer is the identity of the local Peer. - LocalPeer peer.ID - - // LocalAddrs is a set of local addresses to use. - //LocalAddrs []ma.Multiaddr - - // Dialers are the sub-dialers usable by this dialer - // selected in order based on the address being dialed - Dialers []transport.Dialer - - // PrivateKey used to initialize a secure connection. - // Warning: if PrivateKey is nil, connection will not be secured. - PrivateKey ic.PrivKey - - // Wrapper to wrap the raw connection (optional) - Wrapper WrapFunc -} - -// Listener is an object that can accept connections. It matches net.Listener -type Listener interface { - - // Accept waits for and returns the next connection to the listener. - Accept() (net.Conn, error) - - // Addr is the local address - Addr() net.Addr - - // Multiaddr is the local multiaddr address - Multiaddr() ma.Multiaddr - - // LocalPeer is the identity of the local Peer. - LocalPeer() peer.ID - - SetAddrFilters(*filter.Filters) - - // Close closes the listener. - // Any blocked Accept operations will be unblocked and return errors. - Close() error -} - -// EncryptConnections is a global parameter because it should either be -// enabled or _completely disabled_. I.e. a node should only be able to talk -// to proper (encrypted) networks if it is encrypting all its transports. -// Running a node with disabled transport encryption is useful to debug the -// protocols, achieve implementation interop, or for private networks which -// -- for whatever reason -- _must_ run unencrypted. -var EncryptConnections = true diff --git a/p2p/net/conn/listen.go b/p2p/net/conn/listen.go deleted file mode 100644 index eeb5662a03b..00000000000 --- a/p2p/net/conn/listen.go +++ /dev/null @@ -1,170 +0,0 @@ -package conn - -import ( - "fmt" - "io" - "net" - - ma "github.com/ipfs/go-ipfs/Godeps/_workspace/src/github.com/jbenet/go-multiaddr" - tec "github.com/ipfs/go-ipfs/Godeps/_workspace/src/github.com/jbenet/go-temp-err-catcher" - "github.com/ipfs/go-ipfs/Godeps/_workspace/src/github.com/jbenet/goprocess" - goprocessctx "github.com/ipfs/go-ipfs/Godeps/_workspace/src/github.com/jbenet/goprocess/context" - context "github.com/ipfs/go-ipfs/Godeps/_workspace/src/golang.org/x/net/context" - - ic "github.com/ipfs/go-ipfs/p2p/crypto" - filter "github.com/ipfs/go-ipfs/p2p/net/filter" - transport "github.com/ipfs/go-ipfs/p2p/net/transport" - peer "github.com/ipfs/go-ipfs/p2p/peer" -) - -// ConnWrapper is any function that wraps a raw multiaddr connection -type ConnWrapper func(transport.Conn) transport.Conn - -// listener is an object that can accept connections. It implements Listener -type listener struct { - transport.Listener - - local peer.ID // LocalPeer is the identity of the local Peer - privk ic.PrivKey // private key to use to initialize secure conns - - filters *filter.Filters - - wrapper ConnWrapper - - proc goprocess.Process -} - -func (l *listener) teardown() error { - defer log.Debugf("listener closed: %s %s", l.local, l.Multiaddr()) - return l.Listener.Close() -} - -func (l *listener) Close() error { - log.Debugf("listener closing: %s %s", l.local, l.Multiaddr()) - return l.proc.Close() -} - -func (l *listener) String() string { - return fmt.Sprintf("", l.local, l.Multiaddr()) -} - -func (l *listener) SetAddrFilters(fs *filter.Filters) { - l.filters = fs -} - -// Accept waits for and returns the next connection to the listener. -// Note that unfortunately this -func (l *listener) Accept() (net.Conn, error) { - - // listeners dont have contexts. given changes dont make sense here anymore - // note that the parent of listener will Close, which will interrupt all io. - // Contexts and io don't mix. - ctx := context.Background() - - var catcher tec.TempErrCatcher - - catcher.IsTemp = func(e error) bool { - // ignore connection breakages up to this point. but log them - if e == io.EOF { - log.Debugf("listener ignoring conn with EOF: %s", e) - return true - } - - te, ok := e.(tec.Temporary) - if ok { - log.Debugf("listener ignoring conn with temporary err: %s", e) - return te.Temporary() - } - return false - } - - for { - maconn, err := l.Listener.Accept() - if err != nil { - if catcher.IsTemporary(err) { - continue - } - return nil, err - } - - log.Debugf("listener %s got connection: %s <---> %s", l, maconn.LocalMultiaddr(), maconn.RemoteMultiaddr()) - - if l.filters != nil && l.filters.AddrBlocked(maconn.RemoteMultiaddr()) { - log.Debugf("blocked connection from %s", maconn.RemoteMultiaddr()) - maconn.Close() - continue - } - // If we have a wrapper func, wrap this conn - if l.wrapper != nil { - maconn = l.wrapper(maconn) - } - - c, err := newSingleConn(ctx, l.local, "", maconn) - if err != nil { - if catcher.IsTemporary(err) { - continue - } - return nil, err - } - - if l.privk == nil || EncryptConnections == false { - log.Warning("listener %s listening INSECURELY!", l) - return c, nil - } - sc, err := newSecureConn(ctx, l.privk, c) - if err != nil { - log.Infof("ignoring conn we failed to secure: %s %s", err, c) - continue - } - return sc, nil - } -} - -func (l *listener) Addr() net.Addr { - return l.Listener.Addr() -} - -// Multiaddr is the identity of the local Peer. -// If there is an error converting from net.Addr to ma.Multiaddr, -// the return value will be nil. -func (l *listener) Multiaddr() ma.Multiaddr { - return l.Listener.Multiaddr() -} - -// LocalPeer is the identity of the local Peer. -func (l *listener) LocalPeer() peer.ID { - return l.local -} - -func (l *listener) Loggable() map[string]interface{} { - return map[string]interface{}{ - "listener": map[string]interface{}{ - "peer": l.LocalPeer(), - "address": l.Multiaddr(), - "secure": (l.privk != nil), - }, - } -} - -func WrapTransportListener(ctx context.Context, ml transport.Listener, local peer.ID, sk ic.PrivKey) (Listener, error) { - l := &listener{ - Listener: ml, - local: local, - privk: sk, - } - l.proc = goprocessctx.WithContextAndTeardown(ctx, l.teardown) - - log.Debugf("Conn Listener on %s", l.Multiaddr()) - log.Event(ctx, "swarmListen", l) - return l, nil -} - -type ListenerConnWrapper interface { - SetConnWrapper(ConnWrapper) -} - -// SetConnWrapper assigns a maconn ConnWrapper to wrap all incoming -// connections with. MUST be set _before_ calling `Accept()` -func (l *listener) SetConnWrapper(cw ConnWrapper) { - l.wrapper = cw -} diff --git a/p2p/net/conn/secure_conn.go b/p2p/net/conn/secure_conn.go deleted file mode 100644 index 4e786c4b271..00000000000 --- a/p2p/net/conn/secure_conn.go +++ /dev/null @@ -1,125 +0,0 @@ -package conn - -import ( - "errors" - "net" - "time" - - ma "github.com/ipfs/go-ipfs/Godeps/_workspace/src/github.com/jbenet/go-multiaddr" - context "github.com/ipfs/go-ipfs/Godeps/_workspace/src/golang.org/x/net/context" - - ic "github.com/ipfs/go-ipfs/p2p/crypto" - secio "github.com/ipfs/go-ipfs/p2p/crypto/secio" - peer "github.com/ipfs/go-ipfs/p2p/peer" -) - -// secureConn wraps another Conn object with an encrypted channel. -type secureConn struct { - insecure Conn // the wrapped conn - secure secio.Session // secure Session -} - -// newConn constructs a new connection -func newSecureConn(ctx context.Context, sk ic.PrivKey, insecure Conn) (Conn, error) { - - if insecure == nil { - return nil, errors.New("insecure is nil") - } - if insecure.LocalPeer() == "" { - return nil, errors.New("insecure.LocalPeer() is nil") - } - if sk == nil { - return nil, errors.New("private key is nil") - } - - // NewSession performs the secure handshake, which takes multiple RTT - sessgen := secio.SessionGenerator{LocalID: insecure.LocalPeer(), PrivateKey: sk} - secure, err := sessgen.NewSession(ctx, insecure) - if err != nil { - return nil, err - } - - conn := &secureConn{ - insecure: insecure, - secure: secure, - } - return conn, nil -} - -func (c *secureConn) Close() error { - return c.secure.Close() -} - -// ID is an identifier unique to this connection. -func (c *secureConn) ID() string { - return ID(c) -} - -func (c *secureConn) String() string { - return String(c, "secureConn") -} - -func (c *secureConn) LocalAddr() net.Addr { - return c.insecure.LocalAddr() -} - -func (c *secureConn) RemoteAddr() net.Addr { - return c.insecure.RemoteAddr() -} - -func (c *secureConn) SetDeadline(t time.Time) error { - return c.insecure.SetDeadline(t) -} - -func (c *secureConn) SetReadDeadline(t time.Time) error { - return c.insecure.SetReadDeadline(t) -} - -func (c *secureConn) SetWriteDeadline(t time.Time) error { - return c.insecure.SetWriteDeadline(t) -} - -// LocalMultiaddr is the Multiaddr on this side -func (c *secureConn) LocalMultiaddr() ma.Multiaddr { - return c.insecure.LocalMultiaddr() -} - -// RemoteMultiaddr is the Multiaddr on the remote side -func (c *secureConn) RemoteMultiaddr() ma.Multiaddr { - return c.insecure.RemoteMultiaddr() -} - -// LocalPeer is the Peer on this side -func (c *secureConn) LocalPeer() peer.ID { - return c.secure.LocalPeer() -} - -// RemotePeer is the Peer on the remote side -func (c *secureConn) RemotePeer() peer.ID { - return c.secure.RemotePeer() -} - -// LocalPrivateKey is the public key of the peer on this side -func (c *secureConn) LocalPrivateKey() ic.PrivKey { - return c.secure.LocalPrivateKey() -} - -// RemotePubKey is the public key of the peer on the remote side -func (c *secureConn) RemotePublicKey() ic.PubKey { - return c.secure.RemotePublicKey() -} - -// Read reads data, net.Conn style -func (c *secureConn) Read(buf []byte) (int, error) { - return c.secure.ReadWriter().Read(buf) -} - -// Write writes data, net.Conn style -func (c *secureConn) Write(buf []byte) (int, error) { - return c.secure.ReadWriter().Write(buf) -} - -// ReleaseMsg releases a buffer -func (c *secureConn) ReleaseMsg(m []byte) { - c.secure.ReadWriter().ReleaseMsg(m) -} diff --git a/p2p/net/conn/secure_conn_test.go b/p2p/net/conn/secure_conn_test.go deleted file mode 100644 index 9f5a53794ee..00000000000 --- a/p2p/net/conn/secure_conn_test.go +++ /dev/null @@ -1,211 +0,0 @@ -package conn - -import ( - "bytes" - "runtime" - "sync" - "testing" - "time" - - ic "github.com/ipfs/go-ipfs/p2p/crypto" - travis "github.com/ipfs/go-ipfs/util/testutil/ci/travis" - - context "github.com/ipfs/go-ipfs/Godeps/_workspace/src/golang.org/x/net/context" -) - -func upgradeToSecureConn(t *testing.T, ctx context.Context, sk ic.PrivKey, c Conn) (Conn, error) { - if c, ok := c.(*secureConn); ok { - return c, nil - } - - // shouldn't happen, because dial + listen already return secure conns. - s, err := newSecureConn(ctx, sk, c) - if err != nil { - return nil, err - } - - // need to read + write, as that's what triggers the handshake. - h := []byte("hello") - if _, err := s.Write(h); err != nil { - return nil, err - } - if _, err := s.Read(h); err != nil { - return nil, err - } - return s, nil -} - -func secureHandshake(t *testing.T, ctx context.Context, sk ic.PrivKey, c Conn, done chan error) { - _, err := upgradeToSecureConn(t, ctx, sk, c) - done <- err -} - -func TestSecureSimple(t *testing.T) { - // t.Skip("Skipping in favor of another test") - - numMsgs := 100 - if testing.Short() { - numMsgs = 10 - } - - ctx := context.Background() - c1, c2, p1, p2 := setupSingleConn(t, ctx) - - done := make(chan error) - go secureHandshake(t, ctx, p1.PrivKey, c1, done) - go secureHandshake(t, ctx, p2.PrivKey, c2, done) - - for i := 0; i < 2; i++ { - if err := <-done; err != nil { - t.Fatal(err) - } - } - - for i := 0; i < numMsgs; i++ { - testOneSendRecv(t, c1, c2) - testOneSendRecv(t, c2, c1) - } - - c1.Close() - c2.Close() -} - -func TestSecureClose(t *testing.T) { - // t.Skip("Skipping in favor of another test") - - ctx := context.Background() - c1, c2, p1, p2 := setupSingleConn(t, ctx) - - done := make(chan error) - go secureHandshake(t, ctx, p1.PrivKey, c1, done) - go secureHandshake(t, ctx, p2.PrivKey, c2, done) - - for i := 0; i < 2; i++ { - if err := <-done; err != nil { - t.Fatal(err) - } - } - - testOneSendRecv(t, c1, c2) - - c1.Close() - testNotOneSendRecv(t, c1, c2) - - c2.Close() - testNotOneSendRecv(t, c1, c2) - testNotOneSendRecv(t, c2, c1) - -} - -func TestSecureCancelHandshake(t *testing.T) { - // t.Skip("Skipping in favor of another test") - - ctx, cancel := context.WithCancel(context.Background()) - c1, c2, p1, p2 := setupSingleConn(t, ctx) - - done := make(chan error) - go secureHandshake(t, ctx, p1.PrivKey, c1, done) - <-time.After(time.Millisecond) - cancel() // cancel ctx - go secureHandshake(t, ctx, p2.PrivKey, c2, done) - - for i := 0; i < 2; i++ { - if err := <-done; err == nil { - t.Error("cancel should've errored out") - } - } -} - -func TestSecureHandshakeFailsWithWrongKeys(t *testing.T) { - // t.Skip("Skipping in favor of another test") - - ctx, cancel := context.WithCancel(context.Background()) - defer cancel() - c1, c2, p1, p2 := setupSingleConn(t, ctx) - - done := make(chan error) - go secureHandshake(t, ctx, p2.PrivKey, c1, done) - go secureHandshake(t, ctx, p1.PrivKey, c2, done) - - for i := 0; i < 2; i++ { - if err := <-done; err == nil { - t.Fatal("wrong keys should've errored out.") - } - } -} - -func TestSecureCloseLeak(t *testing.T) { - // t.Skip("Skipping in favor of another test") - - if testing.Short() { - t.SkipNow() - } - if travis.IsRunning() { - t.Skip("this doesn't work well on travis") - } - - runPair := func(c1, c2 Conn, num int) { - mc1 := msgioWrap(c1) - mc2 := msgioWrap(c2) - - log.Debugf("runPair %d", num) - - for i := 0; i < num; i++ { - log.Debugf("runPair iteration %d", i) - b1 := []byte("beep") - mc1.WriteMsg(b1) - b2, err := mc2.ReadMsg() - if err != nil { - panic(err) - } - if !bytes.Equal(b1, b2) { - panic("bytes not equal") - } - - b2 = []byte("beep") - mc2.WriteMsg(b2) - b1, err = mc1.ReadMsg() - if err != nil { - panic(err) - } - if !bytes.Equal(b1, b2) { - panic("bytes not equal") - } - - <-time.After(time.Microsecond * 5) - } - } - - var cons = 5 - var msgs = 50 - log.Debugf("Running %d connections * %d msgs.\n", cons, msgs) - - var wg sync.WaitGroup - for i := 0; i < cons; i++ { - wg.Add(1) - - ctx, cancel := context.WithCancel(context.Background()) - c1, c2, _, _ := setupSecureConn(t, ctx) - go func(c1, c2 Conn) { - - defer func() { - c1.Close() - c2.Close() - cancel() - wg.Done() - }() - - runPair(c1, c2, msgs) - }(c1, c2) - } - - log.Debugf("Waiting...\n") - wg.Wait() - // done! - - <-time.After(time.Millisecond * 150) - if runtime.NumGoroutine() > 20 { - // panic("uncomment me to debug") - t.Fatal("leaking goroutines:", runtime.NumGoroutine()) - } -} diff --git a/p2p/net/filter/filter.go b/p2p/net/filter/filter.go deleted file mode 100644 index 20b62ce1227..00000000000 --- a/p2p/net/filter/filter.go +++ /dev/null @@ -1,62 +0,0 @@ -package filter - -import ( - "net" - "strings" - "sync" - - ma "github.com/ipfs/go-ipfs/Godeps/_workspace/src/github.com/jbenet/go-multiaddr" - manet "github.com/ipfs/go-ipfs/Godeps/_workspace/src/github.com/jbenet/go-multiaddr-net" -) - -type Filters struct { - mu sync.RWMutex - filters map[string]*net.IPNet -} - -func NewFilters() *Filters { - return &Filters{ - filters: make(map[string]*net.IPNet), - } -} - -func (fs *Filters) AddDialFilter(f *net.IPNet) { - fs.mu.Lock() - defer fs.mu.Unlock() - fs.filters[f.String()] = f -} - -func (f *Filters) AddrBlocked(a ma.Multiaddr) bool { - _, addr, err := manet.DialArgs(a) - if err != nil { - // if we cant parse it, its probably not blocked - return false - } - - ipstr := strings.Split(addr, ":")[0] - ip := net.ParseIP(ipstr) - f.mu.RLock() - defer f.mu.RUnlock() - for _, ft := range f.filters { - if ft.Contains(ip) { - return true - } - } - return false -} - -func (f *Filters) Filters() []*net.IPNet { - var out []*net.IPNet - f.mu.RLock() - defer f.mu.RUnlock() - for _, ff := range f.filters { - out = append(out, ff) - } - return out -} - -func (f *Filters) Remove(ff *net.IPNet) { - f.mu.Lock() - defer f.mu.Unlock() - delete(f.filters, ff.String()) -} diff --git a/p2p/net/interface.go b/p2p/net/interface.go deleted file mode 100644 index 14a94d76993..00000000000 --- a/p2p/net/interface.go +++ /dev/null @@ -1,155 +0,0 @@ -package net - -import ( - "io" - - conn "github.com/ipfs/go-ipfs/p2p/net/conn" - peer "github.com/ipfs/go-ipfs/p2p/peer" - - ma "github.com/ipfs/go-ipfs/Godeps/_workspace/src/github.com/jbenet/go-multiaddr" - "github.com/ipfs/go-ipfs/Godeps/_workspace/src/github.com/jbenet/goprocess" - context "github.com/ipfs/go-ipfs/Godeps/_workspace/src/golang.org/x/net/context" -) - -// MessageSizeMax is a soft (recommended) maximum for network messages. -// One can write more, as the interface is a stream. But it is useful -// to bunch it up into multiple read/writes when the whole message is -// a single, large serialized object. -const MessageSizeMax = 2 << 22 // 4MB - -// Stream represents a bidirectional channel between two agents in -// the IPFS network. "agent" is as granular as desired, potentially -// being a "request -> reply" pair, or whole protocols. -// Streams are backed by SPDY streams underneath the hood. -type Stream interface { - io.Reader - io.Writer - io.Closer - - // Conn returns the connection this stream is part of. - Conn() Conn -} - -// StreamHandler is the type of function used to listen for -// streams opened by the remote side. -type StreamHandler func(Stream) - -// Conn is a connection to a remote peer. It multiplexes streams. -// Usually there is no need to use a Conn directly, but it may -// be useful to get information about the peer on the other side: -// stream.Conn().RemotePeer() -type Conn interface { - conn.PeerConn - - // NewStream constructs a new Stream over this conn. - NewStream() (Stream, error) -} - -// ConnHandler is the type of function used to listen for -// connections opened by the remote side. -type ConnHandler func(Conn) - -// Network is the interface used to connect to the outside world. -// It dials and listens for connections. it uses a Swarm to pool -// connnections (see swarm pkg, and peerstream.Swarm). Connections -// are encrypted with a TLS-like protocol. -type Network interface { - Dialer - io.Closer - - // SetStreamHandler sets the handler for new streams opened by the - // remote side. This operation is threadsafe. - SetStreamHandler(StreamHandler) - - // SetConnHandler sets the handler for new connections opened by the - // remote side. This operation is threadsafe. - SetConnHandler(ConnHandler) - - // NewStream returns a new stream to given peer p. - // If there is no connection to p, attempts to create one. - NewStream(peer.ID) (Stream, error) - - // Listen tells the network to start listening on given multiaddrs. - Listen(...ma.Multiaddr) error - - // ListenAddresses returns a list of addresses at which this network listens. - ListenAddresses() []ma.Multiaddr - - // InterfaceListenAddresses returns a list of addresses at which this network - // listens. It expands "any interface" addresses (/ip4/0.0.0.0, /ip6/::) to - // use the known local interfaces. - InterfaceListenAddresses() ([]ma.Multiaddr, error) - - // Process returns the network's Process - Process() goprocess.Process -} - -// Dialer represents a service that can dial out to peers -// (this is usually just a Network, but other services may not need the whole -// stack, and thus it becomes easier to mock) -type Dialer interface { - - // Peerstore returns the internal peerstore - // This is useful to tell the dialer about a new address for a peer. - // Or use one of the public keys found out over the network. - Peerstore() peer.Peerstore - - // LocalPeer returns the local peer associated with this network - LocalPeer() peer.ID - - // DialPeer establishes a connection to a given peer - DialPeer(context.Context, peer.ID) (Conn, error) - - // ClosePeer closes the connection to a given peer - ClosePeer(peer.ID) error - - // Connectedness returns a state signaling connection capabilities - Connectedness(peer.ID) Connectedness - - // Peers returns the peers connected - Peers() []peer.ID - - // Conns returns the connections in this Netowrk - Conns() []Conn - - // ConnsToPeer returns the connections in this Netowrk for given peer. - ConnsToPeer(p peer.ID) []Conn - - // Notify/StopNotify register and unregister a notifiee for signals - Notify(Notifiee) - StopNotify(Notifiee) -} - -// Connectedness signals the capacity for a connection with a given node. -// It is used to signal to services and other peers whether a node is reachable. -type Connectedness int - -const ( - // NotConnected means no connection to peer, and no extra information (default) - NotConnected Connectedness = iota - - // Connected means has an open, live connection to peer - Connected - - // CanConnect means recently connected to peer, terminated gracefully - CanConnect - - // CannotConnect means recently attempted connecting but failed to connect. - // (should signal "made effort, failed") - CannotConnect -) - -// Notifiee is an interface for an object wishing to receive -// notifications from a Network. -type Notifiee interface { - Listen(Network, ma.Multiaddr) // called when network starts listening on an addr - ListenClose(Network, ma.Multiaddr) // called when network starts listening on an addr - Connected(Network, Conn) // called when a connection opened - Disconnected(Network, Conn) // called when a connection closed - OpenedStream(Network, Stream) // called when a stream opened - ClosedStream(Network, Stream) // called when a stream closed - - // TODO - // PeerConnected(Network, peer.ID) // called when a peer connected - // PeerDisconnected(Network, peer.ID) // called when a peer disconnected -} diff --git a/p2p/net/mock/interface.go b/p2p/net/mock/interface.go deleted file mode 100644 index 44f4d4c9051..00000000000 --- a/p2p/net/mock/interface.go +++ /dev/null @@ -1,103 +0,0 @@ -// Package mocknet provides a mock net.Network to test with. -// -// - a Mocknet has many inet.Networks -// - a Mocknet has many Links -// - a Link joins two inet.Networks -// - inet.Conns and inet.Streams are created by inet.Networks -package mocknet - -import ( - ic "github.com/ipfs/go-ipfs/p2p/crypto" - host "github.com/ipfs/go-ipfs/p2p/host" - inet "github.com/ipfs/go-ipfs/p2p/net" - peer "github.com/ipfs/go-ipfs/p2p/peer" - "io" - "time" - - ma "github.com/ipfs/go-ipfs/Godeps/_workspace/src/github.com/jbenet/go-multiaddr" -) - -type Mocknet interface { - - // GenPeer generates a peer and its inet.Network in the Mocknet - GenPeer() (host.Host, error) - - // AddPeer adds an existing peer. we need both a privkey and addr. - // ID is derived from PrivKey - AddPeer(ic.PrivKey, ma.Multiaddr) (host.Host, error) - AddPeerWithPeerstore(peer.ID, peer.Peerstore) (host.Host, error) - - // retrieve things (with randomized iteration order) - Peers() []peer.ID - Net(peer.ID) inet.Network - Nets() []inet.Network - Host(peer.ID) host.Host - Hosts() []host.Host - Links() LinkMap - LinksBetweenPeers(a, b peer.ID) []Link - LinksBetweenNets(a, b inet.Network) []Link - - // Links are the **ability to connect**. - // think of Links as the physical medium. - // For p1 and p2 to connect, a link must exist between them. - // (this makes it possible to test dial failures, and - // things like relaying traffic) - LinkPeers(peer.ID, peer.ID) (Link, error) - LinkNets(inet.Network, inet.Network) (Link, error) - Unlink(Link) error - UnlinkPeers(peer.ID, peer.ID) error - UnlinkNets(inet.Network, inet.Network) error - - // LinkDefaults are the default options that govern links - // if they do not have thier own option set. - SetLinkDefaults(LinkOptions) - LinkDefaults() LinkOptions - - // Connections are the usual. Connecting means Dialing. - // **to succeed, peers must be linked beforehand** - ConnectPeers(peer.ID, peer.ID) (inet.Conn, error) - ConnectNets(inet.Network, inet.Network) (inet.Conn, error) - DisconnectPeers(peer.ID, peer.ID) error - DisconnectNets(inet.Network, inet.Network) error - LinkAll() error - ConnectAllButSelf() error -} - -// LinkOptions are used to change aspects of the links. -// Sorry but they dont work yet :( -type LinkOptions struct { - Latency time.Duration - Bandwidth float64 // in bytes-per-second - // we can make these values distributions down the road. -} - -// Link represents the **possibility** of a connection between -// two peers. Think of it like physical network links. Without -// them, the peers can try and try but they won't be able to -// connect. This allows constructing topologies where specific -// nodes cannot talk to each other directly. :) -type Link interface { - Networks() []inet.Network - Peers() []peer.ID - - SetOptions(LinkOptions) - Options() LinkOptions - - // Metrics() Metrics -} - -// LinkMap is a 3D map to give us an easy way to track links. -// (wow, much map. so data structure. how compose. ahhh pointer) -type LinkMap map[string]map[string]map[Link]struct{} - -// Printer lets you inspect things :) -type Printer interface { - // MocknetLinks shows the entire Mocknet's link table :) - MocknetLinks(mn Mocknet) - NetworkConns(ni inet.Network) -} - -// PrinterTo returns a Printer ready to write to w. -func PrinterTo(w io.Writer) Printer { - return &printer{w} -} diff --git a/p2p/net/mock/mock.go b/p2p/net/mock/mock.go deleted file mode 100644 index 0e6c3f5dab6..00000000000 --- a/p2p/net/mock/mock.go +++ /dev/null @@ -1,57 +0,0 @@ -package mocknet - -import ( - logging "github.com/ipfs/go-ipfs/vendor/QmQg1J6vikuXF9oDvm4wpdeAUvvkVEKW1EYDw9HhTMnP2b/go-log" - - context "github.com/ipfs/go-ipfs/Godeps/_workspace/src/golang.org/x/net/context" -) - -var log = logging.Logger("mocknet") - -// WithNPeers constructs a Mocknet with N peers. -func WithNPeers(ctx context.Context, n int) (Mocknet, error) { - m := New(ctx) - for i := 0; i < n; i++ { - if _, err := m.GenPeer(); err != nil { - return nil, err - } - } - return m, nil -} - -// FullMeshLinked constructs a Mocknet with full mesh of Links. -// This means that all the peers **can** connect to each other -// (not that they already are connected. you can use m.ConnectAll()) -func FullMeshLinked(ctx context.Context, n int) (Mocknet, error) { - m, err := WithNPeers(ctx, n) - if err != nil { - return nil, err - } - - if err := m.LinkAll(); err != nil { - return nil, err - } - - return m, nil -} - -// FullMeshConnected constructs a Mocknet with full mesh of Connections. -// This means that all the peers have dialed and are ready to talk to -// each other. -func FullMeshConnected(ctx context.Context, n int) (Mocknet, error) { - m, err := FullMeshLinked(ctx, n) - if err != nil { - return nil, err - } - - nets := m.Nets() - for _, n1 := range nets { - for _, n2 := range nets { - if _, err := m.ConnectNets(n1, n2); err != nil { - return nil, err - } - } - } - - return m, nil -} diff --git a/p2p/net/mock/mock_conn.go b/p2p/net/mock/mock_conn.go deleted file mode 100644 index ae97c3e8344..00000000000 --- a/p2p/net/mock/mock_conn.go +++ /dev/null @@ -1,150 +0,0 @@ -package mocknet - -import ( - "container/list" - "sync" - - ic "github.com/ipfs/go-ipfs/p2p/crypto" - inet "github.com/ipfs/go-ipfs/p2p/net" - peer "github.com/ipfs/go-ipfs/p2p/peer" - - ma "github.com/ipfs/go-ipfs/Godeps/_workspace/src/github.com/jbenet/go-multiaddr" - process "github.com/ipfs/go-ipfs/Godeps/_workspace/src/github.com/jbenet/goprocess" -) - -// conn represents one side's perspective of a -// live connection between two peers. -// it goes over a particular link. -type conn struct { - local peer.ID - remote peer.ID - - localAddr ma.Multiaddr - remoteAddr ma.Multiaddr - - localPrivKey ic.PrivKey - remotePubKey ic.PubKey - - net *peernet - link *link - rconn *conn // counterpart - streams list.List - proc process.Process - - sync.RWMutex -} - -func newConn(ln, rn *peernet, l *link) *conn { - c := &conn{net: ln, link: l} - c.local = ln.peer - c.remote = rn.peer - - c.localAddr = ln.ps.Addrs(ln.peer)[0] - c.remoteAddr = rn.ps.Addrs(rn.peer)[0] - - c.localPrivKey = ln.ps.PrivKey(ln.peer) - c.remotePubKey = rn.ps.PubKey(rn.peer) - - c.proc = process.WithTeardown(c.teardown) - return c -} - -func (c *conn) Close() error { - return c.proc.Close() -} - -func (c *conn) teardown() error { - for _, s := range c.allStreams() { - s.Close() - } - c.net.removeConn(c) - c.net.notifyAll(func(n inet.Notifiee) { - n.Disconnected(c.net, c) - }) - return nil -} - -func (c *conn) addStream(s *stream) { - c.Lock() - s.conn = c - c.streams.PushBack(s) - c.Unlock() -} - -func (c *conn) removeStream(s *stream) { - c.Lock() - defer c.Unlock() - for e := c.streams.Front(); e != nil; e = e.Next() { - if s == e.Value { - c.streams.Remove(e) - return - } - } -} - -func (c *conn) allStreams() []inet.Stream { - c.RLock() - defer c.RUnlock() - - strs := make([]inet.Stream, 0, c.streams.Len()) - for e := c.streams.Front(); e != nil; e = e.Next() { - s := e.Value.(*stream) - strs = append(strs, s) - } - return strs -} - -func (c *conn) remoteOpenedStream(s *stream) { - c.addStream(s) - c.net.handleNewStream(s) - c.net.notifyAll(func(n inet.Notifiee) { - n.OpenedStream(c.net, s) - }) -} - -func (c *conn) openStream() *stream { - sl, sr := c.link.newStreamPair() - c.addStream(sl) - c.net.notifyAll(func(n inet.Notifiee) { - n.OpenedStream(c.net, sl) - }) - c.rconn.remoteOpenedStream(sr) - return sl -} - -func (c *conn) NewStream() (inet.Stream, error) { - log.Debugf("Conn.NewStreamWithProtocol: %s --> %s", c.local, c.remote) - - s := c.openStream() - return s, nil -} - -// LocalMultiaddr is the Multiaddr on this side -func (c *conn) LocalMultiaddr() ma.Multiaddr { - return c.localAddr -} - -// LocalPeer is the Peer on our side of the connection -func (c *conn) LocalPeer() peer.ID { - return c.local -} - -// LocalPrivateKey is the private key of the peer on our side. -func (c *conn) LocalPrivateKey() ic.PrivKey { - return c.localPrivKey -} - -// RemoteMultiaddr is the Multiaddr on the remote side -func (c *conn) RemoteMultiaddr() ma.Multiaddr { - return c.remoteAddr -} - -// RemotePeer is the Peer on the remote side -func (c *conn) RemotePeer() peer.ID { - return c.remote -} - -// RemotePublicKey is the private key of the peer on our side. -func (c *conn) RemotePublicKey() ic.PubKey { - return c.remotePubKey -} diff --git a/p2p/net/mock/mock_link.go b/p2p/net/mock/mock_link.go deleted file mode 100644 index 8ce43c441ca..00000000000 --- a/p2p/net/mock/mock_link.go +++ /dev/null @@ -1,93 +0,0 @@ -package mocknet - -import ( - // "fmt" - "io" - "sync" - "time" - - inet "github.com/ipfs/go-ipfs/p2p/net" - peer "github.com/ipfs/go-ipfs/p2p/peer" -) - -// link implements mocknet.Link -// and, for simplicity, inet.Conn -type link struct { - mock *mocknet - nets []*peernet - opts LinkOptions - ratelimiter *ratelimiter - // this could have addresses on both sides. - - sync.RWMutex -} - -func newLink(mn *mocknet, opts LinkOptions) *link { - l := &link{mock: mn, - opts: opts, - ratelimiter: NewRatelimiter(opts.Bandwidth)} - return l -} - -func (l *link) newConnPair(dialer *peernet) (*conn, *conn) { - l.RLock() - defer l.RUnlock() - - c1 := newConn(l.nets[0], l.nets[1], l) - c2 := newConn(l.nets[1], l.nets[0], l) - c1.rconn = c2 - c2.rconn = c1 - - if dialer == c1.net { - return c1, c2 - } - return c2, c1 -} - -func (l *link) newStreamPair() (*stream, *stream) { - r1, w1 := io.Pipe() - r2, w2 := io.Pipe() - - s1 := NewStream(w2, r1) - s2 := NewStream(w1, r2) - return s1, s2 -} - -func (l *link) Networks() []inet.Network { - l.RLock() - defer l.RUnlock() - - cp := make([]inet.Network, len(l.nets)) - for i, n := range l.nets { - cp[i] = n - } - return cp -} - -func (l *link) Peers() []peer.ID { - l.RLock() - defer l.RUnlock() - - cp := make([]peer.ID, len(l.nets)) - for i, n := range l.nets { - cp[i] = n.peer - } - return cp -} - -func (l *link) SetOptions(o LinkOptions) { - l.opts = o - l.ratelimiter.UpdateBandwidth(l.opts.Bandwidth) -} - -func (l *link) Options() LinkOptions { - return l.opts -} - -func (l *link) GetLatency() time.Duration { - return l.opts.Latency -} - -func (l *link) RateLimit(dataSize int) time.Duration { - return l.ratelimiter.Limit(dataSize) -} diff --git a/p2p/net/mock/mock_net.go b/p2p/net/mock/mock_net.go deleted file mode 100644 index 96c55bc2a74..00000000000 --- a/p2p/net/mock/mock_net.go +++ /dev/null @@ -1,371 +0,0 @@ -package mocknet - -import ( - "fmt" - "sort" - "sync" - - ic "github.com/ipfs/go-ipfs/p2p/crypto" - host "github.com/ipfs/go-ipfs/p2p/host" - bhost "github.com/ipfs/go-ipfs/p2p/host/basic" - inet "github.com/ipfs/go-ipfs/p2p/net" - peer "github.com/ipfs/go-ipfs/p2p/peer" - p2putil "github.com/ipfs/go-ipfs/p2p/test/util" - testutil "github.com/ipfs/go-ipfs/util/testutil" - - ma "github.com/ipfs/go-ipfs/Godeps/_workspace/src/github.com/jbenet/go-multiaddr" - "github.com/ipfs/go-ipfs/Godeps/_workspace/src/github.com/jbenet/goprocess" - goprocessctx "github.com/ipfs/go-ipfs/Godeps/_workspace/src/github.com/jbenet/goprocess/context" - context "github.com/ipfs/go-ipfs/Godeps/_workspace/src/golang.org/x/net/context" -) - -// mocknet implements mocknet.Mocknet -type mocknet struct { - nets map[peer.ID]*peernet - hosts map[peer.ID]*bhost.BasicHost - - // links make it possible to connect two peers. - // think of links as the physical medium. - // usually only one, but there could be multiple - // **links are shared between peers** - links map[peer.ID]map[peer.ID]map[*link]struct{} - - linkDefaults LinkOptions - - proc goprocess.Process // for Context closing - ctx context.Context - sync.Mutex -} - -func New(ctx context.Context) Mocknet { - return &mocknet{ - nets: map[peer.ID]*peernet{}, - hosts: map[peer.ID]*bhost.BasicHost{}, - links: map[peer.ID]map[peer.ID]map[*link]struct{}{}, - proc: goprocessctx.WithContext(ctx), - ctx: ctx, - } -} - -func (mn *mocknet) GenPeer() (host.Host, error) { - sk, err := p2putil.RandTestBogusPrivateKey() - if err != nil { - return nil, err - } - - a := testutil.RandLocalTCPAddress() - - h, err := mn.AddPeer(sk, a) - if err != nil { - return nil, err - } - - return h, nil -} - -func (mn *mocknet) AddPeer(k ic.PrivKey, a ma.Multiaddr) (host.Host, error) { - p, err := peer.IDFromPublicKey(k.GetPublic()) - if err != nil { - return nil, err - } - - ps := peer.NewPeerstore() - ps.AddAddr(p, a, peer.PermanentAddrTTL) - ps.AddPrivKey(p, k) - ps.AddPubKey(p, k.GetPublic()) - - return mn.AddPeerWithPeerstore(p, ps) -} - -func (mn *mocknet) AddPeerWithPeerstore(p peer.ID, ps peer.Peerstore) (host.Host, error) { - n, err := newPeernet(mn.ctx, mn, p, ps) - if err != nil { - return nil, err - } - - h := bhost.New(n) - - mn.proc.AddChild(n.proc) - - mn.Lock() - mn.nets[n.peer] = n - mn.hosts[n.peer] = h - mn.Unlock() - return h, nil -} - -func (mn *mocknet) Peers() []peer.ID { - mn.Lock() - defer mn.Unlock() - - cp := make([]peer.ID, 0, len(mn.nets)) - for _, n := range mn.nets { - cp = append(cp, n.peer) - } - sort.Sort(peer.IDSlice(cp)) - return cp -} - -func (mn *mocknet) Host(pid peer.ID) host.Host { - mn.Lock() - host := mn.hosts[pid] - mn.Unlock() - return host -} - -func (mn *mocknet) Net(pid peer.ID) inet.Network { - mn.Lock() - n := mn.nets[pid] - mn.Unlock() - return n -} - -func (mn *mocknet) Hosts() []host.Host { - mn.Lock() - defer mn.Unlock() - - cp := make([]host.Host, 0, len(mn.hosts)) - for _, h := range mn.hosts { - cp = append(cp, h) - } - - sort.Sort(hostSlice(cp)) - return cp -} - -func (mn *mocknet) Nets() []inet.Network { - mn.Lock() - defer mn.Unlock() - - cp := make([]inet.Network, 0, len(mn.nets)) - for _, n := range mn.nets { - cp = append(cp, n) - } - sort.Sort(netSlice(cp)) - return cp -} - -// Links returns a copy of the internal link state map. -// (wow, much map. so data structure. how compose. ahhh pointer) -func (mn *mocknet) Links() LinkMap { - mn.Lock() - defer mn.Unlock() - - links := map[string]map[string]map[Link]struct{}{} - for p1, lm := range mn.links { - sp1 := string(p1) - links[sp1] = map[string]map[Link]struct{}{} - for p2, ls := range lm { - sp2 := string(p2) - links[sp1][sp2] = map[Link]struct{}{} - for l := range ls { - links[sp1][sp2][l] = struct{}{} - } - } - } - return links -} - -func (mn *mocknet) LinkAll() error { - nets := mn.Nets() - for _, n1 := range nets { - for _, n2 := range nets { - if _, err := mn.LinkNets(n1, n2); err != nil { - return err - } - } - } - return nil -} - -func (mn *mocknet) LinkPeers(p1, p2 peer.ID) (Link, error) { - mn.Lock() - n1 := mn.nets[p1] - n2 := mn.nets[p2] - mn.Unlock() - - if n1 == nil { - return nil, fmt.Errorf("network for p1 not in mocknet") - } - - if n2 == nil { - return nil, fmt.Errorf("network for p2 not in mocknet") - } - - return mn.LinkNets(n1, n2) -} - -func (mn *mocknet) validate(n inet.Network) (*peernet, error) { - // WARNING: assumes locks acquired - - nr, ok := n.(*peernet) - if !ok { - return nil, fmt.Errorf("Network not supported (use mock package nets only)") - } - - if _, found := mn.nets[nr.peer]; !found { - return nil, fmt.Errorf("Network not on mocknet. is it from another mocknet?") - } - - return nr, nil -} - -func (mn *mocknet) LinkNets(n1, n2 inet.Network) (Link, error) { - mn.Lock() - n1r, err1 := mn.validate(n1) - n2r, err2 := mn.validate(n2) - ld := mn.linkDefaults - mn.Unlock() - - if err1 != nil { - return nil, err1 - } - if err2 != nil { - return nil, err2 - } - - l := newLink(mn, ld) - l.nets = append(l.nets, n1r, n2r) - mn.addLink(l) - return l, nil -} - -func (mn *mocknet) Unlink(l2 Link) error { - - l, ok := l2.(*link) - if !ok { - return fmt.Errorf("only links from mocknet are supported") - } - - mn.removeLink(l) - return nil -} - -func (mn *mocknet) UnlinkPeers(p1, p2 peer.ID) error { - ls := mn.LinksBetweenPeers(p1, p2) - if ls == nil { - return fmt.Errorf("no link between p1 and p2") - } - - for _, l := range ls { - if err := mn.Unlink(l); err != nil { - return err - } - } - return nil -} - -func (mn *mocknet) UnlinkNets(n1, n2 inet.Network) error { - return mn.UnlinkPeers(n1.LocalPeer(), n2.LocalPeer()) -} - -// get from the links map. and lazily contruct. -func (mn *mocknet) linksMapGet(p1, p2 peer.ID) map[*link]struct{} { - - l1, found := mn.links[p1] - if !found { - mn.links[p1] = map[peer.ID]map[*link]struct{}{} - l1 = mn.links[p1] // so we make sure it's there. - } - - l2, found := l1[p2] - if !found { - m := map[*link]struct{}{} - l1[p2] = m - l2 = l1[p2] - } - - return l2 -} - -func (mn *mocknet) addLink(l *link) { - mn.Lock() - defer mn.Unlock() - - n1, n2 := l.nets[0], l.nets[1] - mn.linksMapGet(n1.peer, n2.peer)[l] = struct{}{} - mn.linksMapGet(n2.peer, n1.peer)[l] = struct{}{} -} - -func (mn *mocknet) removeLink(l *link) { - mn.Lock() - defer mn.Unlock() - - n1, n2 := l.nets[0], l.nets[1] - delete(mn.linksMapGet(n1.peer, n2.peer), l) - delete(mn.linksMapGet(n2.peer, n1.peer), l) -} - -func (mn *mocknet) ConnectAllButSelf() error { - nets := mn.Nets() - for _, n1 := range nets { - for _, n2 := range nets { - if n1 == n2 { - continue - } - - if _, err := mn.ConnectNets(n1, n2); err != nil { - return err - } - } - } - return nil -} - -func (mn *mocknet) ConnectPeers(a, b peer.ID) (inet.Conn, error) { - return mn.Net(a).DialPeer(mn.ctx, b) -} - -func (mn *mocknet) ConnectNets(a, b inet.Network) (inet.Conn, error) { - return a.DialPeer(mn.ctx, b.LocalPeer()) -} - -func (mn *mocknet) DisconnectPeers(p1, p2 peer.ID) error { - return mn.Net(p1).ClosePeer(p2) -} - -func (mn *mocknet) DisconnectNets(n1, n2 inet.Network) error { - return n1.ClosePeer(n2.LocalPeer()) -} - -func (mn *mocknet) LinksBetweenPeers(p1, p2 peer.ID) []Link { - mn.Lock() - defer mn.Unlock() - - ls2 := mn.linksMapGet(p1, p2) - cp := make([]Link, 0, len(ls2)) - for l := range ls2 { - cp = append(cp, l) - } - return cp -} - -func (mn *mocknet) LinksBetweenNets(n1, n2 inet.Network) []Link { - return mn.LinksBetweenPeers(n1.LocalPeer(), n2.LocalPeer()) -} - -func (mn *mocknet) SetLinkDefaults(o LinkOptions) { - mn.Lock() - mn.linkDefaults = o - mn.Unlock() -} - -func (mn *mocknet) LinkDefaults() LinkOptions { - mn.Lock() - defer mn.Unlock() - return mn.linkDefaults -} - -// netSlice for sorting by peer -type netSlice []inet.Network - -func (es netSlice) Len() int { return len(es) } -func (es netSlice) Swap(i, j int) { es[i], es[j] = es[j], es[i] } -func (es netSlice) Less(i, j int) bool { return string(es[i].LocalPeer()) < string(es[j].LocalPeer()) } - -// hostSlice for sorting by peer -type hostSlice []host.Host - -func (es hostSlice) Len() int { return len(es) } -func (es hostSlice) Swap(i, j int) { es[i], es[j] = es[j], es[i] } -func (es hostSlice) Less(i, j int) bool { return string(es[i].ID()) < string(es[j].ID()) } diff --git a/p2p/net/mock/mock_notif_test.go b/p2p/net/mock/mock_notif_test.go deleted file mode 100644 index 611f36f5542..00000000000 --- a/p2p/net/mock/mock_notif_test.go +++ /dev/null @@ -1,224 +0,0 @@ -package mocknet - -import ( - "testing" - "time" - - ma "github.com/ipfs/go-ipfs/Godeps/_workspace/src/github.com/jbenet/go-multiaddr" - context "github.com/ipfs/go-ipfs/Godeps/_workspace/src/golang.org/x/net/context" - inet "github.com/ipfs/go-ipfs/p2p/net" - peer "github.com/ipfs/go-ipfs/p2p/peer" -) - -func TestNotifications(t *testing.T) { - - mn, err := FullMeshLinked(context.Background(), 5) - if err != nil { - t.Fatal(err) - } - - timeout := 10 * time.Second - - // signup notifs - nets := mn.Nets() - notifiees := make([]*netNotifiee, len(nets)) - for i, pn := range nets { - n := newNetNotifiee() - pn.Notify(n) - notifiees[i] = n - } - - // connect all but self - if err := mn.ConnectAllButSelf(); err != nil { - t.Fatal(err) - } - - // test everyone got the correct connection opened calls - for i, s := range nets { - n := notifiees[i] - notifs := make(map[peer.ID][]inet.Conn) - for j, s2 := range nets { - if i == j { - continue - } - - // this feels a little sketchy, but its probably okay - for len(s.ConnsToPeer(s2.LocalPeer())) != len(notifs[s2.LocalPeer()]) { - select { - case c := <-n.connected: - nfp := notifs[c.RemotePeer()] - notifs[c.RemotePeer()] = append(nfp, c) - case <-time.After(timeout): - t.Fatal("timeout") - } - } - } - - for p, cons := range notifs { - expect := s.ConnsToPeer(p) - if len(expect) != len(cons) { - t.Fatal("got different number of connections") - } - - for _, c := range cons { - var found bool - for _, c2 := range expect { - if c == c2 { - found = true - break - } - } - - if !found { - t.Fatal("connection not found!") - } - } - } - } - - complement := func(c inet.Conn) (inet.Network, *netNotifiee, *conn) { - for i, s := range nets { - for _, c2 := range s.Conns() { - if c2.(*conn).rconn == c { - return s, notifiees[i], c2.(*conn) - } - } - } - t.Fatal("complementary conn not found", c) - return nil, nil, nil - } - - testOCStream := func(n *netNotifiee, s inet.Stream) { - var s2 inet.Stream - select { - case s2 = <-n.openedStream: - t.Log("got notif for opened stream") - case <-time.After(timeout): - t.Fatal("timeout") - } - if s != nil && s != s2 { - t.Fatalf("got incorrect stream %p %p", s, s2) - } - - select { - case s2 = <-n.closedStream: - t.Log("got notif for closed stream") - case <-time.After(timeout): - t.Fatal("timeout") - } - if s != nil && s != s2 { - t.Fatalf("got incorrect stream %p %p", s, s2) - } - } - - for _, s := range nets { - s.SetStreamHandler(func(s inet.Stream) { - s.Close() - }) - } - - // there's one stream per conn that we need to drain.... - // unsure where these are coming from - for i := range nets { - n := notifiees[i] - for j := 0; j < len(nets)-1; j++ { - testOCStream(n, nil) - } - } - - streams := make(chan inet.Stream) - for _, s := range nets { - s.SetStreamHandler(func(s inet.Stream) { - streams <- s - s.Close() - }) - } - - // open a streams in each conn - for i, s := range nets { - conns := s.Conns() - for _, c := range conns { - _, n2, c2 := complement(c) - st1, err := c.NewStream() - if err != nil { - t.Error(err) - } else { - t.Logf("%s %s <--%p--> %s %s", c.LocalPeer(), c.LocalMultiaddr(), st1, c.RemotePeer(), c.RemoteMultiaddr()) - // st1.Write([]byte("hello")) - st1.Close() - st2 := <-streams - t.Logf("%s %s <--%p--> %s %s", c2.LocalPeer(), c2.LocalMultiaddr(), st2, c2.RemotePeer(), c2.RemoteMultiaddr()) - testOCStream(notifiees[i], st1) - testOCStream(n2, st2) - } - } - } - - // close conns - for i, s := range nets { - n := notifiees[i] - for _, c := range s.Conns() { - _, n2, c2 := complement(c) - c.(*conn).Close() - c2.Close() - - var c3, c4 inet.Conn - select { - case c3 = <-n.disconnected: - case <-time.After(timeout): - t.Fatal("timeout") - } - if c != c3 { - t.Fatal("got incorrect conn", c, c3) - } - - select { - case c4 = <-n2.disconnected: - case <-time.After(timeout): - t.Fatal("timeout") - } - if c2 != c4 { - t.Fatal("got incorrect conn", c, c2) - } - } - } -} - -type netNotifiee struct { - listen chan ma.Multiaddr - listenClose chan ma.Multiaddr - connected chan inet.Conn - disconnected chan inet.Conn - openedStream chan inet.Stream - closedStream chan inet.Stream -} - -func newNetNotifiee() *netNotifiee { - return &netNotifiee{ - listen: make(chan ma.Multiaddr), - listenClose: make(chan ma.Multiaddr), - connected: make(chan inet.Conn), - disconnected: make(chan inet.Conn), - openedStream: make(chan inet.Stream), - closedStream: make(chan inet.Stream), - } -} - -func (nn *netNotifiee) Listen(n inet.Network, a ma.Multiaddr) { - nn.listen <- a -} -func (nn *netNotifiee) ListenClose(n inet.Network, a ma.Multiaddr) { - nn.listenClose <- a -} -func (nn *netNotifiee) Connected(n inet.Network, v inet.Conn) { - nn.connected <- v -} -func (nn *netNotifiee) Disconnected(n inet.Network, v inet.Conn) { - nn.disconnected <- v -} -func (nn *netNotifiee) OpenedStream(n inet.Network, v inet.Stream) { - nn.openedStream <- v -} -func (nn *netNotifiee) ClosedStream(n inet.Network, v inet.Stream) { - nn.closedStream <- v -} diff --git a/p2p/net/mock/mock_peernet.go b/p2p/net/mock/mock_peernet.go deleted file mode 100644 index 6df096d120e..00000000000 --- a/p2p/net/mock/mock_peernet.go +++ /dev/null @@ -1,391 +0,0 @@ -package mocknet - -import ( - "fmt" - "math/rand" - "sync" - - inet "github.com/ipfs/go-ipfs/p2p/net" - peer "github.com/ipfs/go-ipfs/p2p/peer" - - ma "github.com/ipfs/go-ipfs/Godeps/_workspace/src/github.com/jbenet/go-multiaddr" - "github.com/ipfs/go-ipfs/Godeps/_workspace/src/github.com/jbenet/goprocess" - goprocessctx "github.com/ipfs/go-ipfs/Godeps/_workspace/src/github.com/jbenet/goprocess/context" - context "github.com/ipfs/go-ipfs/Godeps/_workspace/src/golang.org/x/net/context" -) - -// peernet implements inet.Network -type peernet struct { - mocknet *mocknet // parent - - peer peer.ID - ps peer.Peerstore - - // conns are actual live connections between peers. - // many conns could run over each link. - // **conns are NOT shared between peers** - connsByPeer map[peer.ID]map[*conn]struct{} - connsByLink map[*link]map[*conn]struct{} - - // implement inet.Network - streamHandler inet.StreamHandler - connHandler inet.ConnHandler - - notifmu sync.RWMutex - notifs map[inet.Notifiee]struct{} - - proc goprocess.Process - sync.RWMutex -} - -// newPeernet constructs a new peernet -func newPeernet(ctx context.Context, m *mocknet, p peer.ID, ps peer.Peerstore) (*peernet, error) { - - n := &peernet{ - mocknet: m, - peer: p, - ps: ps, - - connsByPeer: map[peer.ID]map[*conn]struct{}{}, - connsByLink: map[*link]map[*conn]struct{}{}, - - notifs: make(map[inet.Notifiee]struct{}), - } - - n.proc = goprocessctx.WithContextAndTeardown(ctx, n.teardown) - return n, nil -} - -func (pn *peernet) teardown() error { - - // close the connections - for _, c := range pn.allConns() { - c.Close() - } - return nil -} - -// allConns returns all the connections between this peer and others -func (pn *peernet) allConns() []*conn { - pn.RLock() - var cs []*conn - for _, csl := range pn.connsByPeer { - for c := range csl { - cs = append(cs, c) - } - } - pn.RUnlock() - return cs -} - -// Close calls the ContextCloser func -func (pn *peernet) Close() error { - return pn.proc.Close() -} - -func (pn *peernet) Peerstore() peer.Peerstore { - return pn.ps -} - -func (pn *peernet) String() string { - return fmt.Sprintf("", pn.peer, len(pn.allConns())) -} - -// handleNewStream is an internal function to trigger the client's handler -func (pn *peernet) handleNewStream(s inet.Stream) { - pn.RLock() - handler := pn.streamHandler - pn.RUnlock() - if handler != nil { - go handler(s) - } -} - -// handleNewConn is an internal function to trigger the client's handler -func (pn *peernet) handleNewConn(c inet.Conn) { - pn.RLock() - handler := pn.connHandler - pn.RUnlock() - if handler != nil { - go handler(c) - } -} - -// DialPeer attempts to establish a connection to a given peer. -// Respects the context. -func (pn *peernet) DialPeer(ctx context.Context, p peer.ID) (inet.Conn, error) { - return pn.connect(p) -} - -func (pn *peernet) connect(p peer.ID) (*conn, error) { - // first, check if we already have live connections - pn.RLock() - cs, found := pn.connsByPeer[p] - if found && len(cs) > 0 { - var chosen *conn - for c := range cs { // because cs is a map - chosen = c // select first - break - } - pn.RUnlock() - return chosen, nil - } - pn.RUnlock() - - log.Debugf("%s (newly) dialing %s", pn.peer, p) - - // ok, must create a new connection. we need a link - links := pn.mocknet.LinksBetweenPeers(pn.peer, p) - if len(links) < 1 { - return nil, fmt.Errorf("%s cannot connect to %s", pn.peer, p) - } - - // if many links found, how do we select? for now, randomly... - // this would be an interesting place to test logic that can measure - // links (network interfaces) and select properly - l := links[rand.Intn(len(links))] - - log.Debugf("%s dialing %s openingConn", pn.peer, p) - // create a new connection with link - c := pn.openConn(p, l.(*link)) - return c, nil -} - -func (pn *peernet) openConn(r peer.ID, l *link) *conn { - lc, rc := l.newConnPair(pn) - log.Debugf("%s opening connection to %s", pn.LocalPeer(), lc.RemotePeer()) - pn.addConn(lc) - pn.notifyAll(func(n inet.Notifiee) { - n.Connected(pn, lc) - }) - rc.net.remoteOpenedConn(rc) - return lc -} - -func (pn *peernet) remoteOpenedConn(c *conn) { - log.Debugf("%s accepting connection from %s", pn.LocalPeer(), c.RemotePeer()) - pn.addConn(c) - pn.handleNewConn(c) - pn.notifyAll(func(n inet.Notifiee) { - n.Connected(pn, c) - }) -} - -// addConn constructs and adds a connection -// to given remote peer over given link -func (pn *peernet) addConn(c *conn) { - pn.Lock() - defer pn.Unlock() - - cs, found := pn.connsByPeer[c.RemotePeer()] - if !found { - cs = map[*conn]struct{}{} - pn.connsByPeer[c.RemotePeer()] = cs - } - pn.connsByPeer[c.RemotePeer()][c] = struct{}{} - - cs, found = pn.connsByLink[c.link] - if !found { - cs = map[*conn]struct{}{} - pn.connsByLink[c.link] = cs - } - pn.connsByLink[c.link][c] = struct{}{} -} - -// removeConn removes a given conn -func (pn *peernet) removeConn(c *conn) { - pn.Lock() - defer pn.Unlock() - - cs, found := pn.connsByLink[c.link] - if !found || len(cs) < 1 { - panic(fmt.Sprintf("attempting to remove a conn that doesnt exist %p", c.link)) - } - delete(cs, c) - - cs, found = pn.connsByPeer[c.remote] - if !found { - panic(fmt.Sprintf("attempting to remove a conn that doesnt exist %p", c.remote)) - } - delete(cs, c) -} - -// Process returns the network's Process -func (pn *peernet) Process() goprocess.Process { - return pn.proc -} - -// LocalPeer the network's LocalPeer -func (pn *peernet) LocalPeer() peer.ID { - return pn.peer -} - -// Peers returns the connected peers -func (pn *peernet) Peers() []peer.ID { - pn.RLock() - defer pn.RUnlock() - - peers := make([]peer.ID, 0, len(pn.connsByPeer)) - for _, cs := range pn.connsByPeer { - for c := range cs { - peers = append(peers, c.remote) - break - } - } - return peers -} - -// Conns returns all the connections of this peer -func (pn *peernet) Conns() []inet.Conn { - pn.RLock() - defer pn.RUnlock() - - out := make([]inet.Conn, 0, len(pn.connsByPeer)) - for _, cs := range pn.connsByPeer { - for c := range cs { - out = append(out, c) - } - } - return out -} - -func (pn *peernet) ConnsToPeer(p peer.ID) []inet.Conn { - pn.RLock() - defer pn.RUnlock() - - cs, found := pn.connsByPeer[p] - if !found || len(cs) == 0 { - return nil - } - - var cs2 []inet.Conn - for c := range cs { - cs2 = append(cs2, c) - } - return cs2 -} - -// ClosePeer connections to peer -func (pn *peernet) ClosePeer(p peer.ID) error { - pn.RLock() - cs, found := pn.connsByPeer[p] - if !found { - pn.RUnlock() - return nil - } - - var conns []*conn - for c := range cs { - conns = append(conns, c) - } - pn.RUnlock() - for _, c := range conns { - c.Close() - } - return nil -} - -// BandwidthTotals returns the total amount of bandwidth transferred -func (pn *peernet) BandwidthTotals() (in uint64, out uint64) { - // need to implement this. probably best to do it in swarm this time. - // need a "metrics" object - return 0, 0 -} - -// Listen tells the network to start listening on given multiaddrs. -func (pn *peernet) Listen(addrs ...ma.Multiaddr) error { - pn.Peerstore().AddAddrs(pn.LocalPeer(), addrs, peer.PermanentAddrTTL) - return nil -} - -// ListenAddresses returns a list of addresses at which this network listens. -func (pn *peernet) ListenAddresses() []ma.Multiaddr { - return pn.Peerstore().Addrs(pn.LocalPeer()) -} - -// InterfaceListenAddresses returns a list of addresses at which this network -// listens. It expands "any interface" addresses (/ip4/0.0.0.0, /ip6/::) to -// use the known local interfaces. -func (pn *peernet) InterfaceListenAddresses() ([]ma.Multiaddr, error) { - return pn.ListenAddresses(), nil -} - -// Connectedness returns a state signaling connection capabilities -// For now only returns Connecter || NotConnected. Expand into more later. -func (pn *peernet) Connectedness(p peer.ID) inet.Connectedness { - pn.Lock() - defer pn.Unlock() - - cs, found := pn.connsByPeer[p] - if found && len(cs) > 0 { - return inet.Connected - } - return inet.NotConnected -} - -// NewStream returns a new stream to given peer p. -// If there is no connection to p, attempts to create one. -func (pn *peernet) NewStream(p peer.ID) (inet.Stream, error) { - pn.Lock() - cs, found := pn.connsByPeer[p] - if !found || len(cs) < 1 { - pn.Unlock() - return nil, fmt.Errorf("no connection to peer") - } - - // if many conns are found, how do we select? for now, randomly... - // this would be an interesting place to test logic that can measure - // links (network interfaces) and select properly - n := rand.Intn(len(cs)) - var c *conn - for c = range cs { - if n == 0 { - break - } - n-- - } - pn.Unlock() - - return c.NewStream() -} - -// SetStreamHandler sets the new stream handler on the Network. -// This operation is threadsafe. -func (pn *peernet) SetStreamHandler(h inet.StreamHandler) { - pn.Lock() - pn.streamHandler = h - pn.Unlock() -} - -// SetConnHandler sets the new conn handler on the Network. -// This operation is threadsafe. -func (pn *peernet) SetConnHandler(h inet.ConnHandler) { - pn.Lock() - pn.connHandler = h - pn.Unlock() -} - -// Notify signs up Notifiee to receive signals when events happen -func (pn *peernet) Notify(f inet.Notifiee) { - pn.notifmu.Lock() - pn.notifs[f] = struct{}{} - pn.notifmu.Unlock() -} - -// StopNotify unregisters Notifiee fromr receiving signals -func (pn *peernet) StopNotify(f inet.Notifiee) { - pn.notifmu.Lock() - delete(pn.notifs, f) - pn.notifmu.Unlock() -} - -// notifyAll runs the notification function on all Notifiees -func (pn *peernet) notifyAll(notification func(f inet.Notifiee)) { - pn.notifmu.RLock() - for n := range pn.notifs { - // make sure we dont block - // and they dont block each other. - go notification(n) - } - pn.notifmu.RUnlock() -} diff --git a/p2p/net/mock/mock_printer.go b/p2p/net/mock/mock_printer.go deleted file mode 100644 index 4a683a88612..00000000000 --- a/p2p/net/mock/mock_printer.go +++ /dev/null @@ -1,36 +0,0 @@ -package mocknet - -import ( - "fmt" - "io" - - inet "github.com/ipfs/go-ipfs/p2p/net" - peer "github.com/ipfs/go-ipfs/p2p/peer" -) - -// separate object so our interfaces are separate :) -type printer struct { - w io.Writer -} - -func (p *printer) MocknetLinks(mn Mocknet) { - links := mn.Links() - - fmt.Fprintf(p.w, "Mocknet link map:\n") - for p1, lm := range links { - fmt.Fprintf(p.w, "\t%s linked to:\n", peer.ID(p1)) - for p2, l := range lm { - fmt.Fprintf(p.w, "\t\t%s (%d links)\n", peer.ID(p2), len(l)) - } - } - fmt.Fprintf(p.w, "\n") -} - -func (p *printer) NetworkConns(ni inet.Network) { - - fmt.Fprintf(p.w, "%s connected to:\n", ni.LocalPeer()) - for _, c := range ni.Conns() { - fmt.Fprintf(p.w, "\t%s (addr: %s)\n", c.RemotePeer(), c.RemoteMultiaddr()) - } - fmt.Fprintf(p.w, "\n") -} diff --git a/p2p/net/mock/mock_stream.go b/p2p/net/mock/mock_stream.go deleted file mode 100644 index 56e3031efe8..00000000000 --- a/p2p/net/mock/mock_stream.go +++ /dev/null @@ -1,145 +0,0 @@ -package mocknet - -import ( - "bytes" - "io" - "time" - - process "github.com/ipfs/go-ipfs/Godeps/_workspace/src/github.com/jbenet/goprocess" - - inet "github.com/ipfs/go-ipfs/p2p/net" -) - -// stream implements inet.Stream -type stream struct { - io.Reader - io.Writer - conn *conn - toDeliver chan *transportObject - proc process.Process -} - -type transportObject struct { - msg []byte - arrivalTime time.Time -} - -func NewStream(w io.Writer, r io.Reader) *stream { - s := &stream{ - Reader: r, - Writer: w, - toDeliver: make(chan *transportObject), - } - - s.proc = process.WithTeardown(s.teardown) - s.proc.Go(s.transport) - return s -} - -// How to handle errors with writes? -func (s *stream) Write(p []byte) (n int, err error) { - l := s.conn.link - delay := l.GetLatency() + l.RateLimit(len(p)) - t := time.Now().Add(delay) - select { - case <-s.proc.Closing(): // bail out if we're closing. - return 0, io.ErrClosedPipe - case s.toDeliver <- &transportObject{msg: p, arrivalTime: t}: - } - return len(p), nil -} - -func (s *stream) Close() error { - return s.proc.Close() -} - -// teardown shuts down the stream. it is called by s.proc.Close() -// after all the children of this s.proc (i.e. transport's proc) -// are done. -func (s *stream) teardown() error { - // at this point, no streams are writing. - - s.conn.removeStream(s) - if r, ok := (s.Reader).(io.Closer); ok { - r.Close() - } - if w, ok := (s.Writer).(io.Closer); ok { - w.Close() - } - s.conn.net.notifyAll(func(n inet.Notifiee) { - n.ClosedStream(s.conn.net, s) - }) - return nil -} - -func (s *stream) Conn() inet.Conn { - return s.conn -} - -// transport will grab message arrival times, wait until that time, and -// then write the message out when it is scheduled to arrive -func (s *stream) transport(proc process.Process) { - bufsize := 256 - buf := new(bytes.Buffer) - ticker := time.NewTicker(time.Millisecond * 4) - - // writeBuf writes the contents of buf through to the s.Writer. - // done only when arrival time makes sense. - drainBuf := func() { - if buf.Len() > 0 { - _, err := s.Writer.Write(buf.Bytes()) - if err != nil { - return - } - buf.Reset() - } - } - - // deliverOrWait is a helper func that processes - // an incoming packet. it waits until the arrival time, - // and then writes things out. - deliverOrWait := func(o *transportObject) { - buffered := len(o.msg) + buf.Len() - - now := time.Now() - if now.Before(o.arrivalTime) { - if buffered < bufsize { - buf.Write(o.msg) - return - } - - // we do not buffer + return here, instead hanging the - // call (i.e. not accepting any more transportObjects) - // so that we apply back-pressure to the sender. - // this sleep should wake up same time as ticker. - time.Sleep(o.arrivalTime.Sub(now)) - } - - // ok, we waited our due time. now rite the buf + msg. - - // drainBuf first, before we write this message. - drainBuf() - - // write this message. - _, err := s.Writer.Write(o.msg) - if err != nil { - log.Error("mock_stream", err) - } - } - - for { - select { - case <-proc.Closing(): - return // bail out of here. - - case o, ok := <-s.toDeliver: - if !ok { - return - } - deliverOrWait(o) - - case <-ticker.C: // ok, due to write it out. - drainBuf() - } - } -} diff --git a/p2p/net/mock/mock_test.go b/p2p/net/mock/mock_test.go deleted file mode 100644 index 360886828e1..00000000000 --- a/p2p/net/mock/mock_test.go +++ /dev/null @@ -1,581 +0,0 @@ -package mocknet - -import ( - "bytes" - "io" - "math" - "math/rand" - "sync" - "testing" - "time" - - inet "github.com/ipfs/go-ipfs/p2p/net" - peer "github.com/ipfs/go-ipfs/p2p/peer" - protocol "github.com/ipfs/go-ipfs/p2p/protocol" - testutil "github.com/ipfs/go-ipfs/util/testutil" - - detectrace "github.com/ipfs/go-ipfs/Godeps/_workspace/src/github.com/jbenet/go-detect-race" - context "github.com/ipfs/go-ipfs/Godeps/_workspace/src/golang.org/x/net/context" -) - -func randPeer(t *testing.T) peer.ID { - p, err := testutil.RandPeerID() - if err != nil { - t.Fatal(err) - } - return p -} - -func TestNetworkSetup(t *testing.T) { - - ctx := context.Background() - sk1, _, err := testutil.RandTestKeyPair(512) - if err != nil { - t.Fatal(t) - } - sk2, _, err := testutil.RandTestKeyPair(512) - if err != nil { - t.Fatal(t) - } - sk3, _, err := testutil.RandTestKeyPair(512) - if err != nil { - t.Fatal(t) - } - mn := New(ctx) - // peers := []peer.ID{p1, p2, p3} - - // add peers to mock net - - a1 := testutil.RandLocalTCPAddress() - a2 := testutil.RandLocalTCPAddress() - a3 := testutil.RandLocalTCPAddress() - - h1, err := mn.AddPeer(sk1, a1) - if err != nil { - t.Fatal(err) - } - p1 := h1.ID() - - h2, err := mn.AddPeer(sk2, a2) - if err != nil { - t.Fatal(err) - } - p2 := h2.ID() - - h3, err := mn.AddPeer(sk3, a3) - if err != nil { - t.Fatal(err) - } - p3 := h3.ID() - - // check peers and net - if mn.Host(p1) != h1 { - t.Error("host for p1.ID != h1") - } - if mn.Host(p2) != h2 { - t.Error("host for p2.ID != h2") - } - if mn.Host(p3) != h3 { - t.Error("host for p3.ID != h3") - } - - n1 := h1.Network() - if mn.Net(p1) != n1 { - t.Error("net for p1.ID != n1") - } - n2 := h2.Network() - if mn.Net(p2) != n2 { - t.Error("net for p2.ID != n1") - } - n3 := h3.Network() - if mn.Net(p3) != n3 { - t.Error("net for p3.ID != n1") - } - - // link p1<-->p2, p1<-->p1, p2<-->p3, p3<-->p2 - - l12, err := mn.LinkPeers(p1, p2) - if err != nil { - t.Fatal(err) - } - if !(l12.Networks()[0] == n1 && l12.Networks()[1] == n2) && - !(l12.Networks()[0] == n2 && l12.Networks()[1] == n1) { - t.Error("l12 networks incorrect") - } - - l11, err := mn.LinkPeers(p1, p1) - if err != nil { - t.Fatal(err) - } - if !(l11.Networks()[0] == n1 && l11.Networks()[1] == n1) { - t.Error("l11 networks incorrect") - } - - l23, err := mn.LinkPeers(p2, p3) - if err != nil { - t.Fatal(err) - } - if !(l23.Networks()[0] == n2 && l23.Networks()[1] == n3) && - !(l23.Networks()[0] == n3 && l23.Networks()[1] == n2) { - t.Error("l23 networks incorrect") - } - - l32, err := mn.LinkPeers(p3, p2) - if err != nil { - t.Fatal(err) - } - if !(l32.Networks()[0] == n2 && l32.Networks()[1] == n3) && - !(l32.Networks()[0] == n3 && l32.Networks()[1] == n2) { - t.Error("l32 networks incorrect") - } - - // check things - - links12 := mn.LinksBetweenPeers(p1, p2) - if len(links12) != 1 { - t.Errorf("should be 1 link bt. p1 and p2 (found %d)", len(links12)) - } - if links12[0] != l12 { - t.Error("links 1-2 should be l12.") - } - - links11 := mn.LinksBetweenPeers(p1, p1) - if len(links11) != 1 { - t.Errorf("should be 1 link bt. p1 and p1 (found %d)", len(links11)) - } - if links11[0] != l11 { - t.Error("links 1-1 should be l11.") - } - - links23 := mn.LinksBetweenPeers(p2, p3) - if len(links23) != 2 { - t.Errorf("should be 2 link bt. p2 and p3 (found %d)", len(links23)) - } - if !((links23[0] == l23 && links23[1] == l32) || - (links23[0] == l32 && links23[1] == l23)) { - t.Error("links 2-3 should be l23 and l32.") - } - - // unlinking - - if err := mn.UnlinkPeers(p2, p1); err != nil { - t.Error(err) - } - - // check only one link affected: - - links12 = mn.LinksBetweenPeers(p1, p2) - if len(links12) != 0 { - t.Errorf("should be 0 now...", len(links12)) - } - - links11 = mn.LinksBetweenPeers(p1, p1) - if len(links11) != 1 { - t.Errorf("should be 1 link bt. p1 and p1 (found %d)", len(links11)) - } - if links11[0] != l11 { - t.Error("links 1-1 should be l11.") - } - - links23 = mn.LinksBetweenPeers(p2, p3) - if len(links23) != 2 { - t.Errorf("should be 2 link bt. p2 and p3 (found %d)", len(links23)) - } - if !((links23[0] == l23 && links23[1] == l32) || - (links23[0] == l32 && links23[1] == l23)) { - t.Error("links 2-3 should be l23 and l32.") - } - - // check connecting - - // first, no conns - if len(n2.Conns()) > 0 || len(n3.Conns()) > 0 { - t.Error("should have 0 conn. Got: (%d, %d)", len(n2.Conns()), len(n3.Conns())) - } - - // connect p2->p3 - if _, err := n2.DialPeer(ctx, p3); err != nil { - t.Error(err) - } - - if len(n2.Conns()) != 1 || len(n3.Conns()) != 1 { - t.Errorf("should have (1,1) conn. Got: (%d, %d)", len(n2.Conns()), len(n3.Conns())) - } - - // p := PrinterTo(os.Stdout) - // p.NetworkConns(n1) - // p.NetworkConns(n2) - // p.NetworkConns(n3) - - // can create a stream 2->3, 3->2, - if _, err := n2.NewStream(p3); err != nil { - t.Error(err) - } - if _, err := n3.NewStream(p2); err != nil { - t.Error(err) - } - - // but not 1->2 nor 2->2 (not linked), nor 1->1 (not connected) - if _, err := n1.NewStream(p2); err == nil { - t.Error("should not be able to connect") - } - if _, err := n2.NewStream(p2); err == nil { - t.Error("should not be able to connect") - } - if _, err := n1.NewStream(p1); err == nil { - t.Error("should not be able to connect") - } - - // connect p1->p1 (should work) - if _, err := n1.DialPeer(ctx, p1); err != nil { - t.Error("p1 should be able to dial self.", err) - } - - // and a stream too - if _, err := n1.NewStream(p1); err != nil { - t.Error(err) - } - - // connect p1->p2 - if _, err := n1.DialPeer(ctx, p2); err == nil { - t.Error("p1 should not be able to dial p2, not connected...") - } - - // connect p3->p1 - if _, err := n3.DialPeer(ctx, p1); err == nil { - t.Error("p3 should not be able to dial p1, not connected...") - } - - // relink p1->p2 - - l12, err = mn.LinkPeers(p1, p2) - if err != nil { - t.Fatal(err) - } - if !(l12.Networks()[0] == n1 && l12.Networks()[1] == n2) && - !(l12.Networks()[0] == n2 && l12.Networks()[1] == n1) { - t.Error("l12 networks incorrect") - } - - // should now be able to connect - - // connect p1->p2 - if _, err := n1.DialPeer(ctx, p2); err != nil { - t.Error(err) - } - - // and a stream should work now too :) - if _, err := n2.NewStream(p3); err != nil { - t.Error(err) - } - -} - -func TestStreams(t *testing.T) { - - mn, err := FullMeshConnected(context.Background(), 3) - if err != nil { - t.Fatal(err) - } - - handler := func(s inet.Stream) { - b := make([]byte, 4) - if _, err := io.ReadFull(s, b); err != nil { - panic(err) - } - if !bytes.Equal(b, []byte("beep")) { - panic("bytes mismatch") - } - if _, err := s.Write([]byte("boop")); err != nil { - panic(err) - } - s.Close() - } - - hosts := mn.Hosts() - for _, h := range mn.Hosts() { - h.SetStreamHandler(protocol.TestingID, handler) - } - - s, err := hosts[0].NewStream(protocol.TestingID, hosts[1].ID()) - if err != nil { - t.Fatal(err) - } - - if _, err := s.Write([]byte("beep")); err != nil { - panic(err) - } - b := make([]byte, 4) - if _, err := io.ReadFull(s, b); err != nil { - panic(err) - } - if !bytes.Equal(b, []byte("boop")) { - panic("bytes mismatch 2") - } - -} - -func makePinger(st string, n int) func(inet.Stream) { - return func(s inet.Stream) { - go func() { - defer s.Close() - - for i := 0; i < n; i++ { - b := make([]byte, 4+len(st)) - if _, err := s.Write([]byte("ping" + st)); err != nil { - panic(err) - } - if _, err := io.ReadFull(s, b); err != nil { - panic(err) - } - if !bytes.Equal(b, []byte("pong"+st)) { - panic("bytes mismatch") - } - } - }() - } -} - -func makePonger(st string) func(inet.Stream) { - return func(s inet.Stream) { - go func() { - defer s.Close() - - for { - b := make([]byte, 4+len(st)) - if _, err := io.ReadFull(s, b); err != nil { - if err == io.EOF { - return - } - panic(err) - } - if !bytes.Equal(b, []byte("ping"+st)) { - panic("bytes mismatch") - } - if _, err := s.Write([]byte("pong" + st)); err != nil { - panic(err) - } - } - }() - } -} - -func TestStreamsStress(t *testing.T) { - nnodes := 100 - if detectrace.WithRace() { - nnodes = 50 - } - - mn, err := FullMeshConnected(context.Background(), nnodes) - if err != nil { - t.Fatal(err) - } - - hosts := mn.Hosts() - for _, h := range hosts { - ponger := makePonger(string(protocol.TestingID)) - h.SetStreamHandler(protocol.TestingID, ponger) - } - - var wg sync.WaitGroup - for i := 0; i < 1000; i++ { - wg.Add(1) - go func(i int) { - defer wg.Done() - from := rand.Intn(len(hosts)) - to := rand.Intn(len(hosts)) - s, err := hosts[from].NewStream(protocol.TestingID, hosts[to].ID()) - if err != nil { - log.Debugf("%d (%s) %d (%s)", from, hosts[from], to, hosts[to]) - panic(err) - } - - log.Infof("%d start pinging", i) - makePinger("pingpong", rand.Intn(100))(s) - log.Infof("%d done pinging", i) - }(i) - } - - wg.Wait() -} - -func TestAdding(t *testing.T) { - - mn := New(context.Background()) - - peers := []peer.ID{} - for i := 0; i < 3; i++ { - sk, _, err := testutil.RandTestKeyPair(512) - if err != nil { - t.Fatal(err) - } - - a := testutil.RandLocalTCPAddress() - h, err := mn.AddPeer(sk, a) - if err != nil { - t.Fatal(err) - } - - peers = append(peers, h.ID()) - } - - p1 := peers[0] - p2 := peers[1] - - // link them - for _, p1 := range peers { - for _, p2 := range peers { - if _, err := mn.LinkPeers(p1, p2); err != nil { - t.Error(err) - } - } - } - - // set the new stream handler on p2 - h2 := mn.Host(p2) - if h2 == nil { - t.Fatalf("no host for %s", p2) - } - h2.SetStreamHandler(protocol.TestingID, func(s inet.Stream) { - defer s.Close() - - b := make([]byte, 4) - if _, err := io.ReadFull(s, b); err != nil { - panic(err) - } - if string(b) != "beep" { - panic("did not beep!") - } - - if _, err := s.Write([]byte("boop")); err != nil { - panic(err) - } - }) - - // connect p1 to p2 - if _, err := mn.ConnectPeers(p1, p2); err != nil { - t.Fatal(err) - } - - // talk to p2 - h1 := mn.Host(p1) - if h1 == nil { - t.Fatalf("no network for %s", p1) - } - - s, err := h1.NewStream(protocol.TestingID, p2) - if err != nil { - t.Fatal(err) - } - - if _, err := s.Write([]byte("beep")); err != nil { - t.Error(err) - } - b := make([]byte, 4) - if _, err := io.ReadFull(s, b); err != nil { - t.Error(err) - } - if !bytes.Equal(b, []byte("boop")) { - t.Error("bytes mismatch 2") - } - -} - -func TestRateLimiting(t *testing.T) { - rl := NewRatelimiter(10) - - if !within(rl.Limit(10), time.Duration(float32(time.Second)), time.Millisecond/10) { - t.Fail() - } - if !within(rl.Limit(10), time.Duration(float32(time.Second*2)), time.Millisecond) { - t.Fail() - } - if !within(rl.Limit(10), time.Duration(float32(time.Second*3)), time.Millisecond) { - t.Fail() - } - - if within(rl.Limit(10), time.Duration(float32(time.Second*3)), time.Millisecond) { - t.Fail() - } - - rl.UpdateBandwidth(50) - if !within(rl.Limit(75), time.Duration(float32(time.Second)*1.5), time.Millisecond/10) { - t.Fail() - } - - if within(rl.Limit(75), time.Duration(float32(time.Second)*1.5), time.Millisecond/10) { - t.Fail() - } - - rl.UpdateBandwidth(100) - if !within(rl.Limit(1), time.Duration(time.Millisecond*10), time.Millisecond/10) { - t.Fail() - } - - if within(rl.Limit(1), time.Duration(time.Millisecond*10), time.Millisecond/10) { - t.Fail() - } -} - -func within(t1 time.Duration, t2 time.Duration, tolerance time.Duration) bool { - return math.Abs(float64(t1)-float64(t2)) < float64(tolerance) -} - -func TestLimitedStreams(t *testing.T) { - mn, err := FullMeshConnected(context.Background(), 2) - if err != nil { - t.Fatal(err) - } - - var wg sync.WaitGroup - messages := 4 - messageSize := 500 - handler := func(s inet.Stream) { - b := make([]byte, messageSize) - for i := 0; i < messages; i++ { - if _, err := io.ReadFull(s, b); err != nil { - log.Fatal(err) - } - if !bytes.Equal(b[:4], []byte("ping")) { - log.Fatal("bytes mismatch") - } - wg.Done() - } - s.Close() - } - - hosts := mn.Hosts() - for _, h := range mn.Hosts() { - h.SetStreamHandler(protocol.TestingID, handler) - } - - peers := mn.Peers() - links := mn.LinksBetweenPeers(peers[0], peers[1]) - // 1000 byte per second bandwidth - bps := float64(1000) - opts := links[0].Options() - opts.Bandwidth = bps - for _, link := range links { - link.SetOptions(opts) - } - - s, err := hosts[0].NewStream(protocol.TestingID, hosts[1].ID()) - if err != nil { - t.Fatal(err) - } - - filler := make([]byte, messageSize-4) - data := append([]byte("ping"), filler...) - before := time.Now() - for i := 0; i < messages; i++ { - wg.Add(1) - if _, err := s.Write(data); err != nil { - panic(err) - } - } - - wg.Wait() - if !within(time.Since(before), time.Duration(time.Second*2), time.Second/3) { - t.Fatal("Expected 2ish seconds but got ", time.Since(before)) - } -} diff --git a/p2p/net/mock/ratelimiter.go b/p2p/net/mock/ratelimiter.go deleted file mode 100644 index 0b21c9a4d92..00000000000 --- a/p2p/net/mock/ratelimiter.go +++ /dev/null @@ -1,75 +0,0 @@ -package mocknet - -import ( - "sync" - "time" -) - -// A ratelimiter is used by a link to determine how long to wait before sending -// data given a bandwidth cap. -type ratelimiter struct { - lock sync.Mutex - bandwidth float64 // bytes per nanosecond - allowance float64 // in bytes - maxAllowance float64 // in bytes - lastUpdate time.Time // when allowance was updated last - count int // number of times rate limiting was applied - duration time.Duration // total delay introduced due to rate limiting -} - -// Creates a new ratelimiter with bandwidth (in bytes/sec) -func NewRatelimiter(bandwidth float64) *ratelimiter { - // convert bandwidth to bytes per nanosecond - b := bandwidth / float64(time.Second) - return &ratelimiter{ - bandwidth: b, - allowance: 0, - maxAllowance: bandwidth, - lastUpdate: time.Now(), - } -} - -// Changes bandwidth of a ratelimiter and resets its allowance -func (r *ratelimiter) UpdateBandwidth(bandwidth float64) { - r.lock.Lock() - defer r.lock.Unlock() - // Convert bandwidth from bytes/second to bytes/nanosecond - b := bandwidth / float64(time.Second) - r.bandwidth = b - // Reset allowance - r.allowance = 0 - r.maxAllowance = bandwidth - r.lastUpdate = time.Now() -} - -// Returns how long to wait before sending data with length 'dataSize' bytes -func (r *ratelimiter) Limit(dataSize int) time.Duration { - r.lock.Lock() - defer r.lock.Unlock() - // update time - var duration time.Duration = time.Duration(0) - if r.bandwidth == 0 { - return duration - } - current := time.Now() - elapsedTime := current.Sub(r.lastUpdate) - r.lastUpdate = current - - allowance := r.allowance + float64(elapsedTime)*r.bandwidth - // allowance can't exceed bandwidth - if allowance > r.maxAllowance { - allowance = r.maxAllowance - } - - allowance -= float64(dataSize) - if allowance < 0 { - // sleep until allowance is back to 0 - duration = time.Duration(-allowance / r.bandwidth) - // rate limiting was applied, record stats - r.count++ - r.duration += duration - } - - r.allowance = allowance - return duration -} diff --git a/p2p/net/swarm/addr/addr.go b/p2p/net/swarm/addr/addr.go deleted file mode 100644 index 0f8593d0743..00000000000 --- a/p2p/net/swarm/addr/addr.go +++ /dev/null @@ -1,275 +0,0 @@ -package addrutil - -import ( - "fmt" - - logging "github.com/ipfs/go-ipfs/vendor/QmQg1J6vikuXF9oDvm4wpdeAUvvkVEKW1EYDw9HhTMnP2b/go-log" - - ma "github.com/ipfs/go-ipfs/Godeps/_workspace/src/github.com/jbenet/go-multiaddr" - manet "github.com/ipfs/go-ipfs/Godeps/_workspace/src/github.com/jbenet/go-multiaddr-net" - context "github.com/ipfs/go-ipfs/Godeps/_workspace/src/golang.org/x/net/context" -) - -var log = logging.Logger("p2p/net/swarm/addr") - -// SupportedTransportStrings is the list of supported transports for the swarm. -// These are strings of encapsulated multiaddr protocols. E.g.: -// /ip4/tcp -var SupportedTransportStrings = []string{ - "/ip4/tcp", - "/ip6/tcp", - "/ip4/udp/utp", - "/ip6/udp/utp", - // "/ip4/udp/udt", disabled because the lib doesnt work on arm - // "/ip6/udp/udt", disabled because the lib doesnt work on arm -} - -// SupportedTransportProtocols is the list of supported transports for the swarm. -// These are []ma.Protocol lists. Populated at runtime from SupportedTransportStrings -var SupportedTransportProtocols = [][]ma.Protocol{} - -func init() { - // initialize SupportedTransportProtocols - transports := make([][]ma.Protocol, len(SupportedTransportStrings)) - for _, s := range SupportedTransportStrings { - t, err := ma.ProtocolsWithString(s) - if err != nil { - panic(err) // important to fix this in the codebase - } - transports = append(transports, t) - } - SupportedTransportProtocols = transports -} - -// FilterAddrs is a filter that removes certain addresses, according to filter. -// if filter returns true, the address is kept. -func FilterAddrs(a []ma.Multiaddr, filter func(ma.Multiaddr) bool) []ma.Multiaddr { - b := make([]ma.Multiaddr, 0, len(a)) - for _, addr := range a { - if filter(addr) { - b = append(b, addr) - } - } - return b -} - -// FilterUsableAddrs removes certain addresses -// from a list. the addresses removed are those known NOT -// to work with our network. Namely, addresses with UTP. -func FilterUsableAddrs(a []ma.Multiaddr) []ma.Multiaddr { - return FilterAddrs(a, func(m ma.Multiaddr) bool { - return AddrUsable(m, false) - }) -} - -// AddrOverNonLocalIP returns whether the addr uses a non-local ip link -func AddrOverNonLocalIP(a ma.Multiaddr) bool { - split := ma.Split(a) - if len(split) < 1 { - return false - } - if manet.IsIP6LinkLocal(split[0]) { - return false - } - return true -} - -// AddrUsable returns whether our network can use this addr. -// We only use the transports in SupportedTransportStrings, -// and we do not link local addresses. Loopback is ok -// as we need to be able to connect to multiple ipfs nodes -// in the same machine. -func AddrUsable(a ma.Multiaddr, partial bool) bool { - if a == nil { - return false - } - - if !AddrOverNonLocalIP(a) { - return false - } - - // test the address protocol list is in SupportedTransportProtocols - matches := func(supported, test []ma.Protocol) bool { - if len(test) > len(supported) { - return false - } - - // when partial, it's ok if test < supported. - if !partial && len(supported) != len(test) { - return false - } - - for i := range test { - if supported[i].Code != test[i].Code { - return false - } - } - return true - } - - transport := a.Protocols() - for _, supported := range SupportedTransportProtocols { - if matches(supported, transport) { - return true - } - } - - return false -} - -// ResolveUnspecifiedAddress expands an unspecified ip addresses (/ip4/0.0.0.0, /ip6/::) to -// use the known local interfaces. If ifaceAddr is nil, we request interface addresses -// from the network stack. (this is so you can provide a cached value if resolving many addrs) -func ResolveUnspecifiedAddress(resolve ma.Multiaddr, ifaceAddrs []ma.Multiaddr) ([]ma.Multiaddr, error) { - // split address into its components - split := ma.Split(resolve) - - // if first component (ip) is not unspecified, use it as is. - if !manet.IsIPUnspecified(split[0]) { - return []ma.Multiaddr{resolve}, nil - } - - out := make([]ma.Multiaddr, 0, len(ifaceAddrs)) - for _, ia := range ifaceAddrs { - // must match the first protocol to be resolve. - if ia.Protocols()[0].Code != resolve.Protocols()[0].Code { - continue - } - - split[0] = ia - joined := ma.Join(split...) - out = append(out, joined) - log.Debug("adding resolved addr:", resolve, joined, out) - } - if len(out) < 1 { - return nil, fmt.Errorf("failed to resolve: %s", resolve) - } - return out, nil -} - -// ResolveUnspecifiedAddresses expands unspecified ip addresses (/ip4/0.0.0.0, /ip6/::) to -// use the known local interfaces. -func ResolveUnspecifiedAddresses(unspecAddrs, ifaceAddrs []ma.Multiaddr) ([]ma.Multiaddr, error) { - - // todo optimize: only fetch these if we have a "any" addr. - if len(ifaceAddrs) < 1 { - var err error - ifaceAddrs, err = InterfaceAddresses() - if err != nil { - return nil, err - } - // log.Debug("InterfaceAddresses:", ifaceAddrs) - } - - var outputAddrs []ma.Multiaddr - for _, a := range unspecAddrs { - // unspecified? - resolved, err := ResolveUnspecifiedAddress(a, ifaceAddrs) - if err != nil { - continue // optimistic. if we cant resolve anything, we'll know at the bottom. - } - // log.Debug("resolved:", a, resolved) - outputAddrs = append(outputAddrs, resolved...) - } - - if len(outputAddrs) < 1 { - return nil, fmt.Errorf("failed to specify addrs: %s", unspecAddrs) - } - - log.Event(context.TODO(), "interfaceListenAddresses", func() logging.Loggable { - var addrs []string - for _, addr := range outputAddrs { - addrs = append(addrs, addr.String()) - } - return logging.Metadata{"addresses": addrs} - }()) - - log.Debug("ResolveUnspecifiedAddresses:", unspecAddrs, ifaceAddrs, outputAddrs) - return outputAddrs, nil -} - -// InterfaceAddresses returns a list of addresses associated with local machine -// Note: we do not return link local addresses. IP loopback is ok, because we -// may be connecting to other nodes in the same machine. -func InterfaceAddresses() ([]ma.Multiaddr, error) { - maddrs, err := manet.InterfaceMultiaddrs() - if err != nil { - return nil, err - } - log.Debug("InterfaceAddresses: from manet:", maddrs) - - var out []ma.Multiaddr - for _, a := range maddrs { - if !AddrUsable(a, true) { // partial - // log.Debug("InterfaceAddresses: skipping unusable:", a) - continue - } - - out = append(out, a) - } - - log.Debug("InterfaceAddresses: usable:", out) - return out, nil -} - -// AddrInList returns whether or not an address is part of a list. -// this is useful to check if NAT is happening (or other bugs?) -func AddrInList(addr ma.Multiaddr, list []ma.Multiaddr) bool { - for _, addr2 := range list { - if addr.Equal(addr2) { - return true - } - } - return false -} - -// AddrIsShareableOnWAN returns whether the given address should be shareable on the -// wide area network (wide internet). -func AddrIsShareableOnWAN(addr ma.Multiaddr) bool { - s := ma.Split(addr) - if len(s) < 1 { - return false - } - a := s[0] - if manet.IsIPLoopback(a) || manet.IsIP6LinkLocal(a) || manet.IsIPUnspecified(a) { - return false - } - return manet.IsThinWaist(a) -} - -// WANShareableAddrs filters addresses based on whether they're shareable on WAN -func WANShareableAddrs(inp []ma.Multiaddr) []ma.Multiaddr { - return FilterAddrs(inp, AddrIsShareableOnWAN) -} - -// Subtract filters out all addrs in b from a -func Subtract(a, b []ma.Multiaddr) []ma.Multiaddr { - return FilterAddrs(a, func(m ma.Multiaddr) bool { - for _, bb := range b { - if m.Equal(bb) { - return false - } - } - return true - }) -} - -// CheckNATWarning checks if our observed addresses differ. if so, -// informs the user that certain things might not work yet -func CheckNATWarning(observed, expected ma.Multiaddr, listen []ma.Multiaddr) { - if observed.Equal(expected) { - return - } - - if !AddrInList(observed, listen) { // probably a nat - log.Warningf(natWarning, observed, listen) - } -} - -const natWarning = `Remote peer observed our address to be: %s -The local addresses are: %s -Thus, connection is going through NAT, and other connections may fail. - -IPFS NAT traversal is still under development. Please bug us on github or irc to fix this. -Baby steps: http://jbenet.static.s3.amazonaws.com/271dfcf/baby-steps.gif -` diff --git a/p2p/net/swarm/addr/addr_test.go b/p2p/net/swarm/addr/addr_test.go deleted file mode 100644 index 91b89067061..00000000000 --- a/p2p/net/swarm/addr/addr_test.go +++ /dev/null @@ -1,226 +0,0 @@ -package addrutil - -import ( - "testing" - - ma "github.com/ipfs/go-ipfs/Godeps/_workspace/src/github.com/jbenet/go-multiaddr" - manet "github.com/ipfs/go-ipfs/Godeps/_workspace/src/github.com/jbenet/go-multiaddr-net" -) - -func newMultiaddr(t *testing.T, s string) ma.Multiaddr { - maddr, err := ma.NewMultiaddr(s) - if err != nil { - t.Fatal(err) - } - return maddr -} - -func TestFilterAddrs(t *testing.T) { - - bad := []ma.Multiaddr{ - newMultiaddr(t, "/ip4/1.2.3.4/udp/1234"), // unreliable - newMultiaddr(t, "/ip4/1.2.3.4/udp/1234/sctp/1234"), // not in manet - newMultiaddr(t, "/ip4/1.2.3.4/udp/1234/udt"), // udt is broken on arm - newMultiaddr(t, "/ip6/fe80::1/tcp/1234"), // link local - newMultiaddr(t, "/ip6/fe80::100/tcp/1234"), // link local - } - - good := []ma.Multiaddr{ - newMultiaddr(t, "/ip4/127.0.0.1/tcp/1234"), - newMultiaddr(t, "/ip6/::1/tcp/1234"), - newMultiaddr(t, "/ip4/1.2.3.4/udp/1234/utp"), - } - - goodAndBad := append(good, bad...) - - // test filters - - for _, a := range bad { - if AddrUsable(a, false) { - t.Errorf("addr %s should be unusable", a) - } - } - - for _, a := range good { - if !AddrUsable(a, false) { - t.Errorf("addr %s should be usable", a) - } - } - - subtestAddrsEqual(t, FilterUsableAddrs(bad), []ma.Multiaddr{}) - subtestAddrsEqual(t, FilterUsableAddrs(good), good) - subtestAddrsEqual(t, FilterUsableAddrs(goodAndBad), good) -} - -func subtestAddrsEqual(t *testing.T, a, b []ma.Multiaddr) { - if len(a) != len(b) { - t.Error(t) - } - - in := func(addr ma.Multiaddr, l []ma.Multiaddr) bool { - for _, addr2 := range l { - if addr.Equal(addr2) { - return true - } - } - return false - } - - for _, aa := range a { - if !in(aa, b) { - t.Errorf("%s not in %s", aa, b) - } - } -} - -func TestInterfaceAddrs(t *testing.T) { - addrs, err := InterfaceAddresses() - if err != nil { - t.Fatal(err) - } - - if len(addrs) < 1 { - t.Error("no addresses") - } - - for _, a := range addrs { - if manet.IsIP6LinkLocal(a) { - t.Error("should not return ip link local addresses", a) - } - } - - if len(addrs) < 1 { - t.Error("no good interface addrs") - } -} - -func TestResolvingAddrs(t *testing.T) { - - unspec := []ma.Multiaddr{ - newMultiaddr(t, "/ip4/0.0.0.0/tcp/1234"), - newMultiaddr(t, "/ip4/1.2.3.4/tcp/1234"), - newMultiaddr(t, "/ip6/::/tcp/1234"), - newMultiaddr(t, "/ip6/::100/tcp/1234"), - } - - iface := []ma.Multiaddr{ - newMultiaddr(t, "/ip4/127.0.0.1"), - newMultiaddr(t, "/ip4/10.20.30.40"), - newMultiaddr(t, "/ip6/::1"), - newMultiaddr(t, "/ip6/::f"), - } - - spec := []ma.Multiaddr{ - newMultiaddr(t, "/ip4/127.0.0.1/tcp/1234"), - newMultiaddr(t, "/ip4/10.20.30.40/tcp/1234"), - newMultiaddr(t, "/ip4/1.2.3.4/tcp/1234"), - newMultiaddr(t, "/ip6/::1/tcp/1234"), - newMultiaddr(t, "/ip6/::f/tcp/1234"), - newMultiaddr(t, "/ip6/::100/tcp/1234"), - } - - actual, err := ResolveUnspecifiedAddresses(unspec, iface) - if err != nil { - t.Fatal(err) - } - - for i, a := range actual { - if !a.Equal(spec[i]) { - t.Error(a, " != ", spec[i]) - } - } - - ip4u := []ma.Multiaddr{newMultiaddr(t, "/ip4/0.0.0.0")} - ip4i := []ma.Multiaddr{newMultiaddr(t, "/ip4/1.2.3.4")} - - ip6u := []ma.Multiaddr{newMultiaddr(t, "/ip6/::")} - ip6i := []ma.Multiaddr{newMultiaddr(t, "/ip6/::1")} - - if _, err := ResolveUnspecifiedAddress(ip4u[0], ip6i); err == nil { - t.Fatal("should have failed") - } - if _, err := ResolveUnspecifiedAddress(ip6u[0], ip4i); err == nil { - t.Fatal("should have failed") - } - - if _, err := ResolveUnspecifiedAddresses(ip6u, ip4i); err == nil { - t.Fatal("should have failed") - } - if _, err := ResolveUnspecifiedAddresses(ip4u, ip6i); err == nil { - t.Fatal("should have failed") - } - -} - -func TestWANShareable(t *testing.T) { - - wanok := []ma.Multiaddr{ - newMultiaddr(t, "/ip4/1.2.3.4/tcp/1234"), - newMultiaddr(t, "/ip6/abcd::1/tcp/1234"), - } - - wanbad := []ma.Multiaddr{ - newMultiaddr(t, "/ip4/127.0.0.1/tcp/1234"), - newMultiaddr(t, "/ip4/0.0.0.0/tcp/1234"), - newMultiaddr(t, "/ip6/::1/tcp/1234"), - newMultiaddr(t, "/ip6/::/tcp/1234"), - newMultiaddr(t, "/ip6/fe80::1/tcp/1234"), - newMultiaddr(t, "/ip6/fe80::/tcp/1234"), - } - - for _, a := range wanok { - if !AddrIsShareableOnWAN(a) { - t.Error("should be true", a) - } - } - - for _, a := range wanbad { - if AddrIsShareableOnWAN(a) { - t.Error("should be false", a) - } - } - - wanok2 := WANShareableAddrs(wanok) - if len(wanok) != len(wanok2) { - t.Error("should be the same") - } - - wanbad2 := WANShareableAddrs(wanbad) - if len(wanbad2) != 0 { - t.Error("should be zero") - } -} - -func TestSubtract(t *testing.T) { - - a := []ma.Multiaddr{ - newMultiaddr(t, "/ip4/127.0.0.1/tcp/1234"), - newMultiaddr(t, "/ip4/0.0.0.0/tcp/1234"), - newMultiaddr(t, "/ip6/::1/tcp/1234"), - newMultiaddr(t, "/ip6/::/tcp/1234"), - newMultiaddr(t, "/ip6/fe80::1/tcp/1234"), - newMultiaddr(t, "/ip6/fe80::/tcp/1234"), - } - - b := []ma.Multiaddr{ - newMultiaddr(t, "/ip4/127.0.0.1/tcp/1234"), - newMultiaddr(t, "/ip6/::1/tcp/1234"), - newMultiaddr(t, "/ip6/fe80::1/tcp/1234"), - } - - c1 := []ma.Multiaddr{ - newMultiaddr(t, "/ip4/0.0.0.0/tcp/1234"), - newMultiaddr(t, "/ip6/::/tcp/1234"), - newMultiaddr(t, "/ip6/fe80::/tcp/1234"), - } - - c2 := Subtract(a, b) - if len(c1) != len(c2) { - t.Error("should be the same") - } - for i, ca := range c1 { - if !c2[i].Equal(ca) { - t.Error("should be the same", ca, c2[i]) - } - } -} diff --git a/p2p/net/swarm/dial_test.go b/p2p/net/swarm/dial_test.go deleted file mode 100644 index b4faf91156f..00000000000 --- a/p2p/net/swarm/dial_test.go +++ /dev/null @@ -1,476 +0,0 @@ -package swarm - -import ( - "net" - "sort" - "sync" - "testing" - "time" - - addrutil "github.com/ipfs/go-ipfs/p2p/net/swarm/addr" - peer "github.com/ipfs/go-ipfs/p2p/peer" - - testutil "github.com/ipfs/go-ipfs/util/testutil" - ci "github.com/ipfs/go-ipfs/util/testutil/ci" - - ma "github.com/ipfs/go-ipfs/Godeps/_workspace/src/github.com/jbenet/go-multiaddr" - manet "github.com/ipfs/go-ipfs/Godeps/_workspace/src/github.com/jbenet/go-multiaddr-net" - context "github.com/ipfs/go-ipfs/Godeps/_workspace/src/golang.org/x/net/context" -) - -func acceptAndHang(l net.Listener) { - conns := make([]net.Conn, 0, 10) - for { - c, err := l.Accept() - if err != nil { - break - } - if c != nil { - conns = append(conns, c) - } - } - for _, c := range conns { - c.Close() - } -} - -func TestSimultDials(t *testing.T) { - // t.Skip("skipping for another test") - t.Parallel() - - ctx := context.Background() - swarms := makeSwarms(ctx, t, 2) - - // connect everyone - { - var wg sync.WaitGroup - connect := func(s *Swarm, dst peer.ID, addr ma.Multiaddr) { - // copy for other peer - log.Debugf("TestSimultOpen: connecting: %s --> %s (%s)", s.local, dst, addr) - s.peers.AddAddr(dst, addr, peer.TempAddrTTL) - if _, err := s.Dial(ctx, dst); err != nil { - t.Fatal("error swarm dialing to peer", err) - } - wg.Done() - } - - ifaceAddrs0, err := swarms[0].InterfaceListenAddresses() - if err != nil { - t.Fatal(err) - } - ifaceAddrs1, err := swarms[1].InterfaceListenAddresses() - if err != nil { - t.Fatal(err) - } - - log.Info("Connecting swarms simultaneously.") - for i := 0; i < 10; i++ { // connect 10x for each. - wg.Add(2) - go connect(swarms[0], swarms[1].local, ifaceAddrs1[0]) - go connect(swarms[1], swarms[0].local, ifaceAddrs0[0]) - } - wg.Wait() - } - - // should still just have 1, at most 2 connections :) - c01l := len(swarms[0].ConnectionsToPeer(swarms[1].local)) - if c01l > 2 { - t.Error("0->1 has", c01l) - } - c10l := len(swarms[1].ConnectionsToPeer(swarms[0].local)) - if c10l > 2 { - t.Error("1->0 has", c10l) - } - - for _, s := range swarms { - s.Close() - } -} - -func newSilentPeer(t *testing.T) (peer.ID, ma.Multiaddr, net.Listener) { - dst := testutil.RandPeerIDFatal(t) - lst, err := net.Listen("tcp4", "0.0.0.0:0") - if err != nil { - t.Fatal(err) - } - addr, err := manet.FromNetAddr(lst.Addr()) - if err != nil { - t.Fatal(err) - } - addrs := []ma.Multiaddr{addr} - addrs, err = addrutil.ResolveUnspecifiedAddresses(addrs, nil) - if err != nil { - t.Fatal(err) - } - t.Log("new silent peer:", dst, addrs[0]) - return dst, addrs[0], lst -} - -func TestDialWait(t *testing.T) { - // t.Skip("skipping for another test") - t.Parallel() - - ctx := context.Background() - swarms := makeSwarms(ctx, t, 1) - s1 := swarms[0] - defer s1.Close() - - s1.dialT = time.Millisecond * 300 // lower timeout for tests. - if ci.IsRunning() { - s1.dialT = time.Second - } - - // dial to a non-existent peer. - s2p, s2addr, s2l := newSilentPeer(t) - go acceptAndHang(s2l) - defer s2l.Close() - s1.peers.AddAddr(s2p, s2addr, peer.PermanentAddrTTL) - - before := time.Now() - if c, err := s1.Dial(ctx, s2p); err == nil { - defer c.Close() - t.Fatal("error swarm dialing to unknown peer worked...", err) - } else { - t.Log("correctly got error:", err) - } - duration := time.Now().Sub(before) - - dt := s1.dialT - if duration < dt*dialAttempts { - t.Error("< DialTimeout * dialAttempts not being respected", duration, dt*dialAttempts) - } - if duration > 2*dt*dialAttempts { - t.Error("> 2*DialTimeout * dialAttempts not being respected", duration, 2*dt*dialAttempts) - } - - if !s1.backf.Backoff(s2p) { - t.Error("s2 should now be on backoff") - } -} - -func TestDialBackoff(t *testing.T) { - // t.Skip("skipping for another test") - if ci.IsRunning() { - t.Skip("travis will never have fun with this test") - } - - t.Parallel() - - ctx := context.Background() - swarms := makeSwarms(ctx, t, 2) - s1 := swarms[0] - s2 := swarms[1] - defer s1.Close() - defer s2.Close() - - s1.dialT = time.Second // lower timeout for tests. - s2.dialT = time.Second // lower timeout for tests. - - s2addrs, err := s2.InterfaceListenAddresses() - if err != nil { - t.Fatal(err) - } - s1.peers.AddAddrs(s2.local, s2addrs, peer.PermanentAddrTTL) - - // dial to a non-existent peer. - s3p, s3addr, s3l := newSilentPeer(t) - go acceptAndHang(s3l) - defer s3l.Close() - s1.peers.AddAddr(s3p, s3addr, peer.PermanentAddrTTL) - - // in this test we will: - // 1) dial 10x to each node. - // 2) all dials should hang - // 3) s1->s2 should succeed. - // 4) s1->s3 should not (and should place s3 on backoff) - // 5) disconnect entirely - // 6) dial 10x to each node again - // 7) s3 dials should all return immediately (except 1) - // 8) s2 dials should all hang, and succeed - // 9) last s3 dial ends, unsuccessful - - dialOnlineNode := func(dst peer.ID, times int) <-chan bool { - ch := make(chan bool) - for i := 0; i < times; i++ { - go func() { - if _, err := s1.Dial(ctx, dst); err != nil { - t.Error("error dialing", dst, err) - ch <- false - } else { - ch <- true - } - }() - } - return ch - } - - dialOfflineNode := func(dst peer.ID, times int) <-chan bool { - ch := make(chan bool) - for i := 0; i < times; i++ { - go func() { - if c, err := s1.Dial(ctx, dst); err != nil { - ch <- false - } else { - t.Error("succeeded in dialing", dst) - ch <- true - c.Close() - } - }() - } - return ch - } - - { - // 1) dial 10x to each node. - N := 10 - s2done := dialOnlineNode(s2.local, N) - s3done := dialOfflineNode(s3p, N) - - // when all dials should be done by: - dialTimeout1x := time.After(s1.dialT) - // dialTimeout1Ax := time.After(s1.dialT * 2) // dialAttempts) - dialTimeout10Ax := time.After(s1.dialT * 2 * 10) // dialAttempts * 10) - - // 2) all dials should hang - select { - case <-s2done: - t.Error("s2 should not happen immediately") - case <-s3done: - t.Error("s3 should not happen yet") - case <-time.After(time.Millisecond): - // s2 may finish very quickly, so let's get out. - } - - // 3) s1->s2 should succeed. - for i := 0; i < N; i++ { - select { - case r := <-s2done: - if !r { - t.Error("s2 should not fail") - } - case <-s3done: - t.Error("s3 should not happen yet") - case <-dialTimeout1x: - t.Error("s2 took too long") - } - } - - select { - case <-s2done: - t.Error("s2 should have no more") - case <-s3done: - t.Error("s3 should not happen yet") - case <-dialTimeout1x: // let it pass - } - - // 4) s1->s3 should not (and should place s3 on backoff) - // N-1 should finish before dialTimeout1x * 2 - for i := 0; i < N; i++ { - select { - case <-s2done: - t.Error("s2 should have no more") - case r := <-s3done: - if r { - t.Error("s3 should not succeed") - } - case <-(dialTimeout1x): - if i < (N - 1) { - t.Fatal("s3 took too long") - } - t.Log("dialTimeout1x * 1.3 hit for last peer") - case <-dialTimeout10Ax: - t.Fatal("s3 took too long") - } - } - - // check backoff state - if s1.backf.Backoff(s2.local) { - t.Error("s2 should not be on backoff") - } - if !s1.backf.Backoff(s3p) { - t.Error("s3 should be on backoff") - } - - // 5) disconnect entirely - - for _, c := range s1.Connections() { - c.Close() - } - for i := 0; i < 100 && len(s1.Connections()) > 0; i++ { - <-time.After(time.Millisecond) - } - if len(s1.Connections()) > 0 { - t.Fatal("s1 conns must exit") - } - } - - { - // 6) dial 10x to each node again - N := 10 - s2done := dialOnlineNode(s2.local, N) - s3done := dialOfflineNode(s3p, N) - - // when all dials should be done by: - dialTimeout1x := time.After(s1.dialT) - // dialTimeout1Ax := time.After(s1.dialT * 2) // dialAttempts) - dialTimeout10Ax := time.After(s1.dialT * 2 * 10) // dialAttempts * 10) - - // 7) s3 dials should all return immediately (except 1) - for i := 0; i < N-1; i++ { - select { - case <-s2done: - t.Error("s2 should not succeed yet") - case r := <-s3done: - if r { - t.Error("s3 should not succeed") - } - case <-dialTimeout1x: - t.Fatal("s3 took too long") - } - } - - // 8) s2 dials should all hang, and succeed - for i := 0; i < N; i++ { - select { - case r := <-s2done: - if !r { - t.Error("s2 should succeed") - } - // case <-s3done: - case <-(dialTimeout1x): - t.Fatal("s3 took too long") - } - } - - // 9) the last s3 should return, failed. - select { - case <-s2done: - t.Error("s2 should have no more") - case r := <-s3done: - if r { - t.Error("s3 should not succeed") - } - case <-dialTimeout10Ax: - t.Fatal("s3 took too long") - } - - // check backoff state (the same) - if s1.backf.Backoff(s2.local) { - t.Error("s2 should not be on backoff") - } - if !s1.backf.Backoff(s3p) { - t.Error("s3 should be on backoff") - } - - } -} - -func TestDialBackoffClears(t *testing.T) { - // t.Skip("skipping for another test") - t.Parallel() - - ctx := context.Background() - swarms := makeSwarms(ctx, t, 2) - s1 := swarms[0] - s2 := swarms[1] - defer s1.Close() - defer s2.Close() - s1.dialT = time.Millisecond * 300 // lower timeout for tests. - s2.dialT = time.Millisecond * 300 // lower timeout for tests. - if ci.IsRunning() { - s1.dialT = 2 * time.Second - s2.dialT = 2 * time.Second - } - - // use another address first, that accept and hang on conns - _, s2bad, s2l := newSilentPeer(t) - go acceptAndHang(s2l) - defer s2l.Close() - - // phase 1 -- dial to non-operational addresses - s1.peers.AddAddr(s2.local, s2bad, peer.PermanentAddrTTL) - - before := time.Now() - if c, err := s1.Dial(ctx, s2.local); err == nil { - t.Fatal("dialing to broken addr worked...", err) - defer c.Close() - } else { - t.Log("correctly got error:", err) - } - duration := time.Now().Sub(before) - - dt := s1.dialT - if duration < dt*dialAttempts { - t.Error("< DialTimeout * dialAttempts not being respected", duration, dt*dialAttempts) - } - if duration > 2*dt*dialAttempts { - t.Error("> 2*DialTimeout * dialAttempts not being respected", duration, 2*dt*dialAttempts) - } - - if !s1.backf.Backoff(s2.local) { - t.Error("s2 should now be on backoff") - } else { - t.Log("correctly added to backoff") - } - - // phase 2 -- add the working address. dial should succeed. - ifaceAddrs1, err := swarms[1].InterfaceListenAddresses() - if err != nil { - t.Fatal(err) - } - s1.peers.AddAddrs(s2.local, ifaceAddrs1, peer.PermanentAddrTTL) - - if _, err := s1.Dial(ctx, s2.local); err == nil { - t.Fatal("should have failed to dial backed off peer") - } - - time.Sleep(baseBackoffTime) - - if c, err := s1.Dial(ctx, s2.local); err != nil { - t.Fatal(err) - } else { - c.Close() - t.Log("correctly connected") - } - - if s1.backf.Backoff(s2.local) { - t.Error("s2 should no longer be on backoff") - } else { - t.Log("correctly cleared backoff") - } -} - -func mkAddr(t *testing.T, s string) ma.Multiaddr { - a, err := ma.NewMultiaddr(s) - if err != nil { - t.Fatal(err) - } - - return a -} - -func TestAddressSorting(t *testing.T) { - u1 := mkAddr(t, "/ip4/152.12.23.53/udp/1234/utp") - u2l := mkAddr(t, "/ip4/127.0.0.1/udp/1234/utp") - local := mkAddr(t, "/ip4/127.0.0.1/tcp/1234") - norm := mkAddr(t, "/ip4/6.5.4.3/tcp/1234") - - l := AddrList{local, u1, u2l, norm} - sort.Sort(l) - - if !l[0].Equal(u2l) { - t.Fatal("expected utp local addr to be sorted first: ", l[0]) - } - - if !l[1].Equal(u1) { - t.Fatal("expected utp addr to be sorted second") - } - - if !l[2].Equal(local) { - t.Fatal("expected tcp localhost addr thid") - } - - if !l[3].Equal(norm) { - t.Fatal("expected normal addr last") - } -} diff --git a/p2p/net/swarm/peers_test.go b/p2p/net/swarm/peers_test.go deleted file mode 100644 index 2f8b07ef0bb..00000000000 --- a/p2p/net/swarm/peers_test.go +++ /dev/null @@ -1,72 +0,0 @@ -package swarm - -import ( - "testing" - - peer "github.com/ipfs/go-ipfs/p2p/peer" - - ma "github.com/ipfs/go-ipfs/Godeps/_workspace/src/github.com/jbenet/go-multiaddr" - context "github.com/ipfs/go-ipfs/Godeps/_workspace/src/golang.org/x/net/context" -) - -func TestPeers(t *testing.T) { - // t.Skip("skipping for another test") - - ctx := context.Background() - swarms := makeSwarms(ctx, t, 2) - s1 := swarms[0] - s2 := swarms[1] - - connect := func(s *Swarm, dst peer.ID, addr ma.Multiaddr) { - // TODO: make a DialAddr func. - s.peers.AddAddr(dst, addr, peer.PermanentAddrTTL) - // t.Logf("connections from %s", s.LocalPeer()) - // for _, c := range s.ConnectionsToPeer(dst) { - // t.Logf("connection from %s to %s: %v", s.LocalPeer(), dst, c) - // } - // t.Logf("") - if _, err := s.Dial(ctx, dst); err != nil { - t.Fatal("error swarm dialing to peer", err) - } - // t.Log(s.swarm.Dump()) - } - - s1GotConn := make(chan struct{}, 0) - s2GotConn := make(chan struct{}, 0) - s1.SetConnHandler(func(c *Conn) { - s1GotConn <- struct{}{} - }) - s2.SetConnHandler(func(c *Conn) { - s2GotConn <- struct{}{} - }) - - connect(s1, s2.LocalPeer(), s2.ListenAddresses()[0]) - <-s2GotConn // have to wait here so the other side catches up. - connect(s2, s1.LocalPeer(), s1.ListenAddresses()[0]) - - for i := 0; i < 100; i++ { - connect(s1, s2.LocalPeer(), s2.ListenAddresses()[0]) - connect(s2, s1.LocalPeer(), s1.ListenAddresses()[0]) - } - - for _, s := range swarms { - log.Infof("%s swarm routing table: %s", s.local, s.Peers()) - } - - test := func(s *Swarm) { - expect := 1 - actual := len(s.Peers()) - if actual != expect { - t.Errorf("%s has %d peers, not %d: %v", s.LocalPeer(), actual, expect, s.Peers()) - t.Log(s.swarm.Dump()) - } - actual = len(s.Connections()) - if actual != expect { - t.Errorf("%s has %d conns, not %d: %v", s.LocalPeer(), actual, expect, s.Connections()) - t.Log(s.swarm.Dump()) - } - } - - test(s1) - test(s2) -} diff --git a/p2p/net/swarm/simul_test.go b/p2p/net/swarm/simul_test.go deleted file mode 100644 index 6a5547dc6bb..00000000000 --- a/p2p/net/swarm/simul_test.go +++ /dev/null @@ -1,77 +0,0 @@ -package swarm - -import ( - "runtime" - "sync" - "testing" - "time" - - peer "github.com/ipfs/go-ipfs/p2p/peer" - ci "github.com/ipfs/go-ipfs/util/testutil/ci" - - ma "github.com/ipfs/go-ipfs/Godeps/_workspace/src/github.com/jbenet/go-multiaddr" - context "github.com/ipfs/go-ipfs/Godeps/_workspace/src/golang.org/x/net/context" -) - -func TestSimultOpen(t *testing.T) { - // t.Skip("skipping for another test") - t.Parallel() - - ctx := context.Background() - swarms := makeSwarms(ctx, t, 2) - - // connect everyone - { - var wg sync.WaitGroup - connect := func(s *Swarm, dst peer.ID, addr ma.Multiaddr) { - // copy for other peer - log.Debugf("TestSimultOpen: connecting: %s --> %s (%s)", s.local, dst, addr) - s.peers.AddAddr(dst, addr, peer.PermanentAddrTTL) - if _, err := s.Dial(ctx, dst); err != nil { - t.Fatal("error swarm dialing to peer", err) - } - wg.Done() - } - - log.Info("Connecting swarms simultaneously.") - wg.Add(2) - go connect(swarms[0], swarms[1].local, swarms[1].ListenAddresses()[0]) - go connect(swarms[1], swarms[0].local, swarms[0].ListenAddresses()[0]) - wg.Wait() - } - - for _, s := range swarms { - s.Close() - } -} - -func TestSimultOpenMany(t *testing.T) { - // t.Skip("very very slow") - - addrs := 20 - rounds := 10 - if ci.IsRunning() || runtime.GOOS == "darwin" { - // osx has a limit of 256 file descriptors - addrs = 10 - rounds = 5 - } - SubtestSwarm(t, addrs, rounds) -} - -func TestSimultOpenFewStress(t *testing.T) { - if testing.Short() { - t.SkipNow() - } - // t.Skip("skipping for another test") - t.Parallel() - - msgs := 40 - swarms := 2 - rounds := 10 - // rounds := 100 - - for i := 0; i < rounds; i++ { - SubtestSwarm(t, swarms, msgs) - <-time.After(10 * time.Millisecond) - } -} diff --git a/p2p/net/swarm/swarm.go b/p2p/net/swarm/swarm.go deleted file mode 100644 index f12ca1a5380..00000000000 --- a/p2p/net/swarm/swarm.go +++ /dev/null @@ -1,344 +0,0 @@ -// package swarm implements a connection muxer with a pair of channels -// to synchronize all network communication. -package swarm - -import ( - "fmt" - "sync" - "time" - - metrics "github.com/ipfs/go-ipfs/metrics" - mconn "github.com/ipfs/go-ipfs/metrics/conn" - inet "github.com/ipfs/go-ipfs/p2p/net" - conn "github.com/ipfs/go-ipfs/p2p/net/conn" - filter "github.com/ipfs/go-ipfs/p2p/net/filter" - addrutil "github.com/ipfs/go-ipfs/p2p/net/swarm/addr" - transport "github.com/ipfs/go-ipfs/p2p/net/transport" - peer "github.com/ipfs/go-ipfs/p2p/peer" - logging "github.com/ipfs/go-ipfs/vendor/QmQg1J6vikuXF9oDvm4wpdeAUvvkVEKW1EYDw9HhTMnP2b/go-log" - - ma "github.com/ipfs/go-ipfs/Godeps/_workspace/src/github.com/jbenet/go-multiaddr" - ps "github.com/ipfs/go-ipfs/Godeps/_workspace/src/github.com/jbenet/go-peerstream" - pst "github.com/ipfs/go-ipfs/Godeps/_workspace/src/github.com/jbenet/go-stream-muxer" - psmss "github.com/ipfs/go-ipfs/Godeps/_workspace/src/github.com/jbenet/go-stream-muxer/multistream" - "github.com/ipfs/go-ipfs/Godeps/_workspace/src/github.com/jbenet/goprocess" - goprocessctx "github.com/ipfs/go-ipfs/Godeps/_workspace/src/github.com/jbenet/goprocess/context" - prom "github.com/ipfs/go-ipfs/Godeps/_workspace/src/github.com/prometheus/client_golang/prometheus" - mafilter "github.com/ipfs/go-ipfs/Godeps/_workspace/src/github.com/whyrusleeping/multiaddr-filter" - context "github.com/ipfs/go-ipfs/Godeps/_workspace/src/golang.org/x/net/context" -) - -var log = logging.Logger("swarm2") - -var PSTransport pst.Transport - -var peersTotal = prom.NewGaugeVec(prom.GaugeOpts{ - Namespace: "ipfs", - Subsystem: "p2p", - Name: "peers_total", - Help: "Number of connected peers", -}, []string{"peer_id"}) - -func init() { - PSTransport = psmss.NewTransport() -} - -// Swarm is a connection muxer, allowing connections to other peers to -// be opened and closed, while still using the same Chan for all -// communication. The Chan sends/receives Messages, which note the -// destination or source Peer. -// -// Uses peerstream.Swarm -type Swarm struct { - swarm *ps.Swarm - local peer.ID - peers peer.Peerstore - connh ConnHandler - - dsync dialsync - backf dialbackoff - dialT time.Duration // mainly for tests - - dialer *conn.Dialer - - notifmu sync.RWMutex - notifs map[inet.Notifiee]ps.Notifiee - - transports []transport.Transport - - // filters for addresses that shouldnt be dialed - Filters *filter.Filters - - // file descriptor rate limited - fdRateLimit chan struct{} - - proc goprocess.Process - ctx context.Context - bwc metrics.Reporter -} - -// NewSwarm constructs a Swarm, with a Chan. -func NewSwarm(ctx context.Context, listenAddrs []ma.Multiaddr, - local peer.ID, peers peer.Peerstore, bwc metrics.Reporter) (*Swarm, error) { - - listenAddrs, err := filterAddrs(listenAddrs) - if err != nil { - return nil, err - } - - wrap := func(c transport.Conn) transport.Conn { - return mconn.WrapConn(bwc, c) - } - - s := &Swarm{ - swarm: ps.NewSwarm(PSTransport), - local: local, - peers: peers, - ctx: ctx, - dialT: DialTimeout, - notifs: make(map[inet.Notifiee]ps.Notifiee), - transports: []transport.Transport{ - transport.NewTCPTransport(), - transport.NewUtpTransport(), - }, - bwc: bwc, - fdRateLimit: make(chan struct{}, concurrentFdDials), - Filters: filter.NewFilters(), - dialer: conn.NewDialer(local, peers.PrivKey(local), wrap), - } - - // configure Swarm - s.proc = goprocessctx.WithContextAndTeardown(ctx, s.teardown) - s.SetConnHandler(nil) // make sure to setup our own conn handler. - - // setup swarm metrics - prom.MustRegisterOrGet(peersTotal) - s.Notify((*metricsNotifiee)(s)) - - err = s.setupInterfaces(listenAddrs) - if err != nil { - return nil, err - } - - return s, nil -} - -func (s *Swarm) teardown() error { - return s.swarm.Close() -} - -func (s *Swarm) AddAddrFilter(f string) error { - m, err := mafilter.NewMask(f) - if err != nil { - return err - } - - s.Filters.AddDialFilter(m) - return nil -} -func filterAddrs(listenAddrs []ma.Multiaddr) ([]ma.Multiaddr, error) { - if len(listenAddrs) > 0 { - filtered := addrutil.FilterUsableAddrs(listenAddrs) - if len(filtered) < 1 { - return nil, fmt.Errorf("swarm cannot use any addr in: %s", listenAddrs) - } - listenAddrs = filtered - } - return listenAddrs, nil -} - -func (s *Swarm) Listen(addrs ...ma.Multiaddr) error { - addrs, err := filterAddrs(addrs) - if err != nil { - return err - } - - return s.setupInterfaces(addrs) -} - -// Process returns the Process of the swarm -func (s *Swarm) Process() goprocess.Process { - return s.proc -} - -// Context returns the context of the swarm -func (s *Swarm) Context() context.Context { - return s.ctx -} - -// Close stops the Swarm. -func (s *Swarm) Close() error { - return s.proc.Close() -} - -// StreamSwarm returns the underlying peerstream.Swarm -func (s *Swarm) StreamSwarm() *ps.Swarm { - return s.swarm -} - -// SetConnHandler assigns the handler for new connections. -// See peerstream. You will rarely use this. See SetStreamHandler -func (s *Swarm) SetConnHandler(handler ConnHandler) { - - // handler is nil if user wants to clear the old handler. - if handler == nil { - s.swarm.SetConnHandler(func(psconn *ps.Conn) { - s.connHandler(psconn) - }) - return - } - - s.swarm.SetConnHandler(func(psconn *ps.Conn) { - // sc is nil if closed in our handler. - if sc := s.connHandler(psconn); sc != nil { - // call the user's handler. in a goroutine for sync safety. - go handler(sc) - } - }) -} - -// SetStreamHandler assigns the handler for new streams. -// See peerstream. -func (s *Swarm) SetStreamHandler(handler inet.StreamHandler) { - s.swarm.SetStreamHandler(func(s *ps.Stream) { - handler(wrapStream(s)) - }) -} - -// NewStreamWithPeer creates a new stream on any available connection to p -func (s *Swarm) NewStreamWithPeer(p peer.ID) (*Stream, error) { - // if we have no connections, try connecting. - if len(s.ConnectionsToPeer(p)) == 0 { - log.Debug("Swarm: NewStreamWithPeer no connections. Attempting to connect...") - if _, err := s.Dial(s.Context(), p); err != nil { - return nil, err - } - } - log.Debug("Swarm: NewStreamWithPeer...") - - st, err := s.swarm.NewStreamWithGroup(p) - return wrapStream(st), err -} - -// StreamsWithPeer returns all the live Streams to p -func (s *Swarm) StreamsWithPeer(p peer.ID) []*Stream { - return wrapStreams(ps.StreamsWithGroup(p, s.swarm.Streams())) -} - -// ConnectionsToPeer returns all the live connections to p -func (s *Swarm) ConnectionsToPeer(p peer.ID) []*Conn { - return wrapConns(ps.ConnsWithGroup(p, s.swarm.Conns())) -} - -// Connections returns a slice of all connections. -func (s *Swarm) Connections() []*Conn { - return wrapConns(s.swarm.Conns()) -} - -// CloseConnection removes a given peer from swarm + closes the connection -func (s *Swarm) CloseConnection(p peer.ID) error { - conns := s.swarm.ConnsWithGroup(p) // boom. - for _, c := range conns { - c.Close() - } - return nil -} - -// Peers returns a copy of the set of peers swarm is connected to. -func (s *Swarm) Peers() []peer.ID { - conns := s.Connections() - - seen := make(map[peer.ID]struct{}) - peers := make([]peer.ID, 0, len(conns)) - for _, c := range conns { - p := c.RemotePeer() - if _, found := seen[p]; found { - continue - } - - seen[p] = struct{}{} - peers = append(peers, p) - } - return peers -} - -// LocalPeer returns the local peer swarm is associated to. -func (s *Swarm) LocalPeer() peer.ID { - return s.local -} - -// notifyAll sends a signal to all Notifiees -func (s *Swarm) notifyAll(notify func(inet.Notifiee)) { - s.notifmu.RLock() - for f := range s.notifs { - go notify(f) - } - s.notifmu.RUnlock() -} - -// Notify signs up Notifiee to receive signals when events happen -func (s *Swarm) Notify(f inet.Notifiee) { - // wrap with our notifiee, to translate function calls - n := &ps2netNotifee{net: (*Network)(s), not: f} - - s.notifmu.Lock() - s.notifs[f] = n - s.notifmu.Unlock() - - // register for notifications in the peer swarm. - s.swarm.Notify(n) -} - -// StopNotify unregisters Notifiee fromr receiving signals -func (s *Swarm) StopNotify(f inet.Notifiee) { - s.notifmu.Lock() - n, found := s.notifs[f] - if found { - delete(s.notifs, f) - } - s.notifmu.Unlock() - - if found { - s.swarm.StopNotify(n) - } -} - -type ps2netNotifee struct { - net *Network - not inet.Notifiee -} - -func (n *ps2netNotifee) Connected(c *ps.Conn) { - n.not.Connected(n.net, inet.Conn((*Conn)(c))) -} - -func (n *ps2netNotifee) Disconnected(c *ps.Conn) { - n.not.Disconnected(n.net, inet.Conn((*Conn)(c))) -} - -func (n *ps2netNotifee) OpenedStream(s *ps.Stream) { - n.not.OpenedStream(n.net, inet.Stream((*Stream)(s))) -} - -func (n *ps2netNotifee) ClosedStream(s *ps.Stream) { - n.not.ClosedStream(n.net, inet.Stream((*Stream)(s))) -} - -type metricsNotifiee Swarm - -func (nn *metricsNotifiee) Connected(n inet.Network, v inet.Conn) { - peersTotalGauge(n.LocalPeer()).Set(float64(len(n.Conns()))) -} - -func (nn *metricsNotifiee) Disconnected(n inet.Network, v inet.Conn) { - peersTotalGauge(n.LocalPeer()).Set(float64(len(n.Conns()))) -} - -func (nn *metricsNotifiee) OpenedStream(n inet.Network, v inet.Stream) {} -func (nn *metricsNotifiee) ClosedStream(n inet.Network, v inet.Stream) {} -func (nn *metricsNotifiee) Listen(n inet.Network, a ma.Multiaddr) {} -func (nn *metricsNotifiee) ListenClose(n inet.Network, a ma.Multiaddr) {} - -func peersTotalGauge(id peer.ID) prom.Gauge { - return peersTotal.With(prom.Labels{"peer_id": id.Pretty()}) -} diff --git a/p2p/net/swarm/swarm_addr.go b/p2p/net/swarm/swarm_addr.go deleted file mode 100644 index 8f9360d9d07..00000000000 --- a/p2p/net/swarm/swarm_addr.go +++ /dev/null @@ -1,39 +0,0 @@ -package swarm - -import ( - conn "github.com/ipfs/go-ipfs/p2p/net/conn" - addrutil "github.com/ipfs/go-ipfs/p2p/net/swarm/addr" - - ma "github.com/ipfs/go-ipfs/Godeps/_workspace/src/github.com/jbenet/go-multiaddr" -) - -// ListenAddresses returns a list of addresses at which this swarm listens. -func (s *Swarm) ListenAddresses() []ma.Multiaddr { - listeners := s.swarm.Listeners() - addrs := make([]ma.Multiaddr, 0, len(listeners)) - for _, l := range listeners { - if l2, ok := l.NetListener().(conn.Listener); ok { - addrs = append(addrs, l2.Multiaddr()) - } - } - return addrs -} - -// InterfaceListenAddresses returns a list of addresses at which this swarm -// listens. It expands "any interface" addresses (/ip4/0.0.0.0, /ip6/::) to -// use the known local interfaces. -func (s *Swarm) InterfaceListenAddresses() ([]ma.Multiaddr, error) { - return addrutil.ResolveUnspecifiedAddresses(s.ListenAddresses(), nil) -} - -// checkNATWarning checks if our observed addresses differ. if so, -// informs the user that certain things might not work yet -func checkNATWarning(s *Swarm, observed ma.Multiaddr, expected ma.Multiaddr) { - listen, err := s.InterfaceListenAddresses() - if err != nil { - log.Debugf("Error retrieving swarm.InterfaceListenAddresses: %s", err) - return - } - - addrutil.CheckNATWarning(observed, expected, listen) -} diff --git a/p2p/net/swarm/swarm_addr_test.go b/p2p/net/swarm/swarm_addr_test.go deleted file mode 100644 index 95b6e66e072..00000000000 --- a/p2p/net/swarm/swarm_addr_test.go +++ /dev/null @@ -1,123 +0,0 @@ -package swarm - -import ( - "testing" - - metrics "github.com/ipfs/go-ipfs/metrics" - addrutil "github.com/ipfs/go-ipfs/p2p/net/swarm/addr" - peer "github.com/ipfs/go-ipfs/p2p/peer" - testutil "github.com/ipfs/go-ipfs/util/testutil" - - ma "github.com/ipfs/go-ipfs/Godeps/_workspace/src/github.com/jbenet/go-multiaddr" - context "github.com/ipfs/go-ipfs/Godeps/_workspace/src/golang.org/x/net/context" -) - -func TestFilterAddrs(t *testing.T) { - - m := func(s string) ma.Multiaddr { - maddr, err := ma.NewMultiaddr(s) - if err != nil { - t.Fatal(err) - } - return maddr - } - - bad := []ma.Multiaddr{ - m("/ip4/1.2.3.4/udp/1234"), // unreliable - m("/ip4/1.2.3.4/udp/1234/sctp/1234"), // not in manet - m("/ip4/1.2.3.4/udp/1234/udt"), // udt is broken on arm - m("/ip6/fe80::1/tcp/0"), // link local - m("/ip6/fe80::100/tcp/1234"), // link local - } - - good := []ma.Multiaddr{ - m("/ip4/127.0.0.1/tcp/0"), - m("/ip6/::1/tcp/0"), - m("/ip4/1.2.3.4/udp/1234/utp"), - } - - goodAndBad := append(good, bad...) - - // test filters - - for _, a := range bad { - if addrutil.AddrUsable(a, false) { - t.Errorf("addr %s should be unusable", a) - } - } - - for _, a := range good { - if !addrutil.AddrUsable(a, false) { - t.Errorf("addr %s should be usable", a) - } - } - - subtestAddrsEqual(t, addrutil.FilterUsableAddrs(bad), []ma.Multiaddr{}) - subtestAddrsEqual(t, addrutil.FilterUsableAddrs(good), good) - subtestAddrsEqual(t, addrutil.FilterUsableAddrs(goodAndBad), good) - - // now test it with swarm - - id, err := testutil.RandPeerID() - if err != nil { - t.Fatal(err) - } - - ps := peer.NewPeerstore() - ctx := context.Background() - - if _, err := NewNetwork(ctx, bad, id, ps, metrics.NewBandwidthCounter()); err == nil { - t.Fatal("should have failed to create swarm") - } - - if _, err := NewNetwork(ctx, goodAndBad, id, ps, metrics.NewBandwidthCounter()); err != nil { - t.Fatal("should have succeeded in creating swarm", err) - } -} - -func subtestAddrsEqual(t *testing.T, a, b []ma.Multiaddr) { - if len(a) != len(b) { - t.Error(t) - } - - in := func(addr ma.Multiaddr, l []ma.Multiaddr) bool { - for _, addr2 := range l { - if addr.Equal(addr2) { - return true - } - } - return false - } - - for _, aa := range a { - if !in(aa, b) { - t.Errorf("%s not in %s", aa, b) - } - } -} - -func TestDialBadAddrs(t *testing.T) { - - m := func(s string) ma.Multiaddr { - maddr, err := ma.NewMultiaddr(s) - if err != nil { - t.Fatal(err) - } - return maddr - } - - ctx := context.Background() - s := makeSwarms(ctx, t, 1)[0] - - test := func(a ma.Multiaddr) { - p := testutil.RandPeerIDFatal(t) - s.peers.AddAddr(p, a, peer.PermanentAddrTTL) - if _, err := s.Dial(ctx, p); err == nil { - t.Error("swarm should not dial: %s", m) - } - } - - test(m("/ip6/fe80::1")) // link local - test(m("/ip6/fe80::100")) // link local - test(m("/ip4/127.0.0.1/udp/1234/utp")) // utp -} diff --git a/p2p/net/swarm/swarm_conn.go b/p2p/net/swarm/swarm_conn.go deleted file mode 100644 index 126ace627a5..00000000000 --- a/p2p/net/swarm/swarm_conn.go +++ /dev/null @@ -1,141 +0,0 @@ -package swarm - -import ( - "fmt" - - ic "github.com/ipfs/go-ipfs/p2p/crypto" - inet "github.com/ipfs/go-ipfs/p2p/net" - conn "github.com/ipfs/go-ipfs/p2p/net/conn" - peer "github.com/ipfs/go-ipfs/p2p/peer" - - ma "github.com/ipfs/go-ipfs/Godeps/_workspace/src/github.com/jbenet/go-multiaddr" - ps "github.com/ipfs/go-ipfs/Godeps/_workspace/src/github.com/jbenet/go-peerstream" - context "github.com/ipfs/go-ipfs/Godeps/_workspace/src/golang.org/x/net/context" -) - -// a Conn is a simple wrapper around a ps.Conn that also exposes -// some of the methods from the underlying conn.Conn. -// There's **five** "layers" to each connection: -// * 0. the net.Conn - underlying net.Conn (TCP/UDP/UTP/etc) -// * 1. the manet.Conn - provides multiaddr friendly Conn -// * 2. the conn.Conn - provides Peer friendly Conn (inc Secure channel) -// * 3. the peerstream.Conn - provides peerstream / spdysptream happiness -// * 4. the Conn - abstracts everyting out, exposing only key parts of underlying layers -// (I know, this is kinda crazy. it's more historical than a good design. though the -// layers do build up pieces of functionality. and they're all just io.RW :) ) -type Conn ps.Conn - -// ConnHandler is called when new conns are opened from remote peers. -// See peerstream.ConnHandler -type ConnHandler func(*Conn) - -func (c *Conn) StreamConn() *ps.Conn { - return (*ps.Conn)(c) -} - -func (c *Conn) RawConn() conn.Conn { - // righly panic if these things aren't true. it is an expected - // invariant that these Conns are all of the typewe expect: - // ps.Conn wrapping a conn.Conn - // if we get something else it is programmer error. - return (*ps.Conn)(c).NetConn().(conn.Conn) -} - -func (c *Conn) String() string { - return fmt.Sprintf("", c.RawConn()) -} - -// LocalMultiaddr is the Multiaddr on this side -func (c *Conn) LocalMultiaddr() ma.Multiaddr { - return c.RawConn().LocalMultiaddr() -} - -// LocalPeer is the Peer on our side of the connection -func (c *Conn) LocalPeer() peer.ID { - return c.RawConn().LocalPeer() -} - -// RemoteMultiaddr is the Multiaddr on the remote side -func (c *Conn) RemoteMultiaddr() ma.Multiaddr { - return c.RawConn().RemoteMultiaddr() -} - -// RemotePeer is the Peer on the remote side -func (c *Conn) RemotePeer() peer.ID { - return c.RawConn().RemotePeer() -} - -// LocalPrivateKey is the public key of the peer on this side -func (c *Conn) LocalPrivateKey() ic.PrivKey { - return c.RawConn().LocalPrivateKey() -} - -// RemotePublicKey is the public key of the peer on the remote side -func (c *Conn) RemotePublicKey() ic.PubKey { - return c.RawConn().RemotePublicKey() -} - -// NewSwarmStream returns a new Stream from this connection -func (c *Conn) NewSwarmStream() (*Stream, error) { - s, err := c.StreamConn().NewStream() - return wrapStream(s), err -} - -// NewStream returns a new Stream from this connection -func (c *Conn) NewStream() (inet.Stream, error) { - s, err := c.NewSwarmStream() - return inet.Stream(s), err -} - -func (c *Conn) Close() error { - return c.StreamConn().Close() -} - -func wrapConn(psc *ps.Conn) (*Conn, error) { - // grab the underlying connection. - if _, ok := psc.NetConn().(conn.Conn); !ok { - // this should never happen. if we see it ocurring it means that we added - // a Listener to the ps.Swarm that is NOT one of our net/conn.Listener. - return nil, fmt.Errorf("swarm connHandler: invalid conn (not a conn.Conn): %s", psc) - } - return (*Conn)(psc), nil -} - -// wrapConns returns a *Conn for all these ps.Conns -func wrapConns(conns1 []*ps.Conn) []*Conn { - conns2 := make([]*Conn, len(conns1)) - for i, c1 := range conns1 { - if c2, err := wrapConn(c1); err == nil { - conns2[i] = c2 - } - } - return conns2 -} - -// newConnSetup does the swarm's "setup" for a connection. returns the underlying -// conn.Conn this method is used by both swarm.Dial and ps.Swarm connHandler -func (s *Swarm) newConnSetup(ctx context.Context, psConn *ps.Conn) (*Conn, error) { - - // wrap with a Conn - sc, err := wrapConn(psConn) - if err != nil { - return nil, err - } - - // if we have a public key, make sure we add it to our peerstore! - // This is an important detail. Otherwise we must fetch the public - // key from the DHT or some other system. - if pk := sc.RemotePublicKey(); pk != nil { - s.peers.AddPubKey(sc.RemotePeer(), pk) - } - - // ok great! we can use it. add it to our group. - - // set the RemotePeer as a group on the conn. this lets us group - // connections in the StreamSwarm by peer, and get a streams from - // any available connection in the group (better multiconn): - // swarm.StreamSwarm().NewStreamWithGroup(remotePeer) - psConn.AddGroup(sc.RemotePeer()) - - return sc, nil -} diff --git a/p2p/net/swarm/swarm_dial.go b/p2p/net/swarm/swarm_dial.go deleted file mode 100644 index 6d4e0344e18..00000000000 --- a/p2p/net/swarm/swarm_dial.go +++ /dev/null @@ -1,586 +0,0 @@ -package swarm - -import ( - "bytes" - "errors" - "fmt" - "sort" - "sync" - "time" - - "github.com/ipfs/go-ipfs/Godeps/_workspace/src/github.com/jbenet/go-multiaddr-net" - conn "github.com/ipfs/go-ipfs/p2p/net/conn" - addrutil "github.com/ipfs/go-ipfs/p2p/net/swarm/addr" - peer "github.com/ipfs/go-ipfs/p2p/peer" - lgbl "github.com/ipfs/go-ipfs/util/eventlog/loggables" - - ma "github.com/ipfs/go-ipfs/Godeps/_workspace/src/github.com/jbenet/go-multiaddr" - context "github.com/ipfs/go-ipfs/Godeps/_workspace/src/golang.org/x/net/context" -) - -// Diagram of dial sync: -// -// many callers of Dial() synched w. dials many addrs results to callers -// ----------------------\ dialsync use earliest /-------------- -// -----------------------\ |----------\ /---------------- -// ------------------------>------------<------- >---------<----------------- -// -----------------------| \----x \---------------- -// ----------------------| \-----x \--------------- -// any may fail if no addr at end -// retry dialAttempt x - -var ( - ErrDialBackoff = errors.New("dial backoff") - ErrDialFailed = errors.New("dial attempt failed") - ErrDialToSelf = errors.New("dial to self attempted") -) - -// dialAttempts governs how many times a goroutine will try to dial a given peer. -// Note: this is down to one, as we have _too many dials_ atm. To add back in, -// add loop back in Dial(.) -const dialAttempts = 1 - -// number of concurrent outbound dials over transports that consume file descriptors -const concurrentFdDials = 160 - -// DialTimeout is the amount of time each dial attempt has. We can think about making -// this larger down the road, or putting more granular timeouts (i.e. within each -// subcomponent of Dial) -var DialTimeout time.Duration = time.Second * 10 - -// dialsync is a small object that helps manage ongoing dials. -// this way, if we receive many simultaneous dial requests, one -// can do its thing, while the rest wait. -// -// this interface is so would-be dialers can just: -// -// for { -// c := findConnectionToPeer(peer) -// if c != nil { -// return c -// } -// -// // ok, no connections. should we dial? -// if ok, wait := dialsync.Lock(peer); !ok { -// <-wait // can optionally wait -// continue -// } -// defer dialsync.Unlock(peer) -// -// c := actuallyDial(peer) -// return c -// } -// -type dialsync struct { - // ongoing is a map of tickets for the current peers being dialed. - // this way, we dont kick off N dials simultaneously. - ongoing map[peer.ID]chan struct{} - lock sync.Mutex -} - -// Lock governs the beginning of a dial attempt. -// If there are no ongoing dials, it returns true, and the client is now -// scheduled to dial. Every other goroutine that calls startDial -- with -//the same dst -- will block until client is done. The client MUST call -// ds.Unlock(p) when it is done, to unblock the other callers. -// The client is not reponsible for achieving a successful dial, only for -// reporting the end of the attempt (calling ds.Unlock(p)). -// -// see the example below `dialsync` -func (ds *dialsync) Lock(dst peer.ID) (bool, chan struct{}) { - ds.lock.Lock() - if ds.ongoing == nil { // init if not ready - ds.ongoing = make(map[peer.ID]chan struct{}) - } - wait, found := ds.ongoing[dst] - if !found { - ds.ongoing[dst] = make(chan struct{}) - } - ds.lock.Unlock() - - if found { - return false, wait - } - - // ok! you're signed up to dial! - return true, nil -} - -// Unlock releases waiters to a dial attempt. see Lock. -// if Unlock(p) is called without calling Lock(p) first, Unlock panics. -func (ds *dialsync) Unlock(dst peer.ID) { - ds.lock.Lock() - wait, found := ds.ongoing[dst] - if !found { - panic("called dialDone with no ongoing dials to peer: " + dst.Pretty()) - } - - delete(ds.ongoing, dst) // remove ongoing dial - close(wait) // release everyone else - ds.lock.Unlock() -} - -// dialbackoff is a struct used to avoid over-dialing the same, dead peers. -// Whenever we totally time out on a peer (all three attempts), we add them -// to dialbackoff. Then, whenevers goroutines would _wait_ (dialsync), they -// check dialbackoff. If it's there, they don't wait and exit promptly with -// an error. (the single goroutine that is actually dialing continues to -// dial). If a dial is successful, the peer is removed from backoff. -// Example: -// -// for { -// if ok, wait := dialsync.Lock(p); !ok { -// if backoff.Backoff(p) { -// return errDialFailed -// } -// <-wait -// continue -// } -// defer dialsync.Unlock(p) -// c, err := actuallyDial(p) -// if err != nil { -// dialbackoff.AddBackoff(p) -// continue -// } -// dialbackoff.Clear(p) -// } -// - -type dialbackoff struct { - entries map[peer.ID]*backoffPeer - lock sync.RWMutex -} - -type backoffPeer struct { - tries int - until time.Time -} - -func (db *dialbackoff) init() { - if db.entries == nil { - db.entries = make(map[peer.ID]*backoffPeer) - } -} - -// Backoff returns whether the client should backoff from dialing -// peer p -func (db *dialbackoff) Backoff(p peer.ID) (backoff bool) { - db.lock.Lock() - defer db.lock.Unlock() - db.init() - bp, found := db.entries[p] - if found && time.Now().Before(bp.until) { - return true - } - - return false -} - -const baseBackoffTime = time.Second * 5 -const maxBackoffTime = time.Minute * 5 - -// AddBackoff lets other nodes know that we've entered backoff with -// peer p, so dialers should not wait unnecessarily. We still will -// attempt to dial with one goroutine, in case we get through. -func (db *dialbackoff) AddBackoff(p peer.ID) { - db.lock.Lock() - defer db.lock.Unlock() - db.init() - bp, ok := db.entries[p] - if !ok { - db.entries[p] = &backoffPeer{ - tries: 1, - until: time.Now().Add(baseBackoffTime), - } - return - } - - expTimeAdd := time.Second * time.Duration(bp.tries*bp.tries) - if expTimeAdd > maxBackoffTime { - expTimeAdd = maxBackoffTime - } - bp.until = time.Now().Add(baseBackoffTime + expTimeAdd) - bp.tries++ -} - -// Clear removes a backoff record. Clients should call this after a -// successful Dial. -func (db *dialbackoff) Clear(p peer.ID) { - db.lock.Lock() - defer db.lock.Unlock() - db.init() - delete(db.entries, p) -} - -// Dial connects to a peer. -// -// The idea is that the client of Swarm does not need to know what network -// the connection will happen over. Swarm can use whichever it choses. -// This allows us to use various transport protocols, do NAT traversal/relay, -// etc. to achive connection. -func (s *Swarm) Dial(ctx context.Context, p peer.ID) (*Conn, error) { - var logdial = lgbl.Dial("swarm", s.LocalPeer(), p, nil, nil) - if p == s.local { - log.Event(ctx, "swarmDialSelf", logdial) - return nil, ErrDialToSelf - } - - return s.gatedDialAttempt(ctx, p) -} - -func (s *Swarm) bestConnectionToPeer(p peer.ID) *Conn { - cs := s.ConnectionsToPeer(p) - for _, conn := range cs { - if conn != nil { // dump out the first one we find. (TODO pick better) - return conn - } - } - return nil -} - -// gatedDialAttempt is an attempt to dial a node. It is gated by the swarm's -// dial synchronization systems: dialsync and dialbackoff. -func (s *Swarm) gatedDialAttempt(ctx context.Context, p peer.ID) (*Conn, error) { - var logdial = lgbl.Dial("swarm", s.LocalPeer(), p, nil, nil) - defer log.EventBegin(ctx, "swarmDialAttemptSync", logdial).Done() - - // check if we already have an open connection first - conn := s.bestConnectionToPeer(p) - if conn != nil { - return conn, nil - } - - // check if there's an ongoing dial to this peer - if ok, wait := s.dsync.Lock(p); ok { - defer s.dsync.Unlock(p) - - // if this peer has been backed off, lets get out of here - if s.backf.Backoff(p) { - log.Event(ctx, "swarmDialBackoff", logdial) - return nil, ErrDialBackoff - } - - // ok, we have been charged to dial! let's do it. - // if it succeeds, dial will add the conn to the swarm itself. - defer log.EventBegin(ctx, "swarmDialAttemptStart", logdial).Done() - ctxT, cancel := context.WithTimeout(ctx, s.dialT) - conn, err := s.dial(ctxT, p) - cancel() - log.Debugf("dial end %s", conn) - if err != nil { - log.Event(ctx, "swarmDialBackoffAdd", logdial) - s.backf.AddBackoff(p) // let others know to backoff - - // ok, we failed. try again. (if loop is done, our error is output) - return nil, fmt.Errorf("dial attempt failed: %s", err) - } - log.Event(ctx, "swarmDialBackoffClear", logdial) - s.backf.Clear(p) // okay, no longer need to backoff - return conn, nil - - } else { - // we did not dial. we must wait for someone else to dial. - - // check whether we should backoff first... - if s.backf.Backoff(p) { - log.Event(ctx, "swarmDialBackoff", logdial) - return nil, ErrDialBackoff - } - - defer log.EventBegin(ctx, "swarmDialWait", logdial).Done() - select { - case <-wait: // wait for that other dial to finish. - - // see if it worked, OR we got an incoming dial in the meantime... - conn := s.bestConnectionToPeer(p) - if conn != nil { - return conn, nil - } - return nil, ErrDialFailed - case <-ctx.Done(): // or we may have to bail... - return nil, ctx.Err() - } - } -} - -// dial is the actual swarm's dial logic, gated by Dial. -func (s *Swarm) dial(ctx context.Context, p peer.ID) (*Conn, error) { - var logdial = lgbl.Dial("swarm", s.LocalPeer(), p, nil, nil) - if p == s.local { - log.Event(ctx, "swarmDialDoDialSelf", logdial) - return nil, ErrDialToSelf - } - defer log.EventBegin(ctx, "swarmDialDo", logdial).Done() - logdial["dial"] = "failure" // start off with failure. set to "success" at the end. - - sk := s.peers.PrivKey(s.local) - logdial["encrypted"] = (sk != nil) // log wether this will be an encrypted dial or not. - if sk == nil { - // fine for sk to be nil, just log. - log.Debug("Dial not given PrivateKey, so WILL NOT SECURE conn.") - } - - // get remote peer addrs - remoteAddrs := s.peers.Addrs(p) - // make sure we can use the addresses. - remoteAddrs = addrutil.FilterUsableAddrs(remoteAddrs) - // drop out any addrs that would just dial ourselves. use ListenAddresses - // as that is a more authoritative view than localAddrs. - ila, _ := s.InterfaceListenAddresses() - remoteAddrs = addrutil.Subtract(remoteAddrs, ila) - remoteAddrs = addrutil.Subtract(remoteAddrs, s.peers.Addrs(s.local)) - - log.Debugf("%s swarm dialing %s -- local:%s remote:%s", s.local, p, s.ListenAddresses(), remoteAddrs) - if len(remoteAddrs) == 0 { - err := errors.New("peer has no addresses") - logdial["error"] = err - return nil, err - } - - remoteAddrs = s.filterAddrs(remoteAddrs) - if len(remoteAddrs) == 0 { - err := errors.New("all adresses for peer have been filtered out") - logdial["error"] = err - return nil, err - } - - // try to get a connection to any addr - connC, err := s.dialAddrs(ctx, p, remoteAddrs) - if err != nil { - logdial["error"] = err - return nil, err - } - logdial["netconn"] = lgbl.NetConn(connC) - - // ok try to setup the new connection. - defer log.EventBegin(ctx, "swarmDialDoSetup", logdial, lgbl.NetConn(connC)).Done() - swarmC, err := dialConnSetup(ctx, s, connC) - if err != nil { - logdial["error"] = err - connC.Close() // close the connection. didn't work out :( - return nil, err - } - - logdial["dial"] = "success" - return swarmC, nil -} - -func (s *Swarm) dialAddrs(ctx context.Context, p peer.ID, remoteAddrs []ma.Multiaddr) (conn.Conn, error) { - - // sort addresses so preferred addresses are dialed sooner - sort.Sort(AddrList(remoteAddrs)) - - // try to connect to one of the peer's known addresses. - // we dial concurrently to each of the addresses, which: - // * makes the process faster overall - // * attempts to get the fastest connection available. - // * mitigates the waste of trying bad addresses - log.Debugf("%s swarm dialing %s %s", s.local, p, remoteAddrs) - - ctx, cancel := context.WithCancel(ctx) - defer cancel() // cancel work when we exit func - - conns := make(chan conn.Conn) - errs := make(chan error, len(remoteAddrs)) - - // dialSingleAddr is used in the rate-limited async thing below. - dialSingleAddr := func(addr ma.Multiaddr) { - // rebind chans in scope so we can nil them out easily - connsout := conns - errsout := errs - - connC, err := s.dialAddr(ctx, p, addr) - if err != nil { - connsout = nil - } else if connC == nil { - // NOTE: this really should never happen - log.Errorf("failed to dial %s %s and got no error!", p, addr) - err = fmt.Errorf("failed to dial %s %s", p, addr) - connsout = nil - } else { - errsout = nil - } - - // check parent still wants our results - select { - case <-ctx.Done(): - if connC != nil { - connC.Close() - } - case errsout <- err: - case connsout <- connC: - } - } - - // this whole thing is in a goroutine so we can use foundConn - // to end early. - go func() { - limiter := make(chan struct{}, 8) - for _, addr := range remoteAddrs { - // returns whatever ratelimiting is acceptable for workerAddr. - // may not rate limit at all. - rl := s.addrDialRateLimit(addr) - select { - case <-ctx.Done(): // our context was cancelled - return - case rl <- struct{}{}: - // take the token, move on - } - - select { - case <-ctx.Done(): // our context was cancelled - return - case limiter <- struct{}{}: - // take the token, move on - } - - go func(rlc <-chan struct{}, a ma.Multiaddr) { - dialSingleAddr(a) - <-limiter - <-rlc - }(rl, addr) - } - }() - - // wair for the results. - exitErr := fmt.Errorf("failed to dial %s", p) - for range remoteAddrs { - select { - case exitErr = <-errs: // - log.Debug("dial error: ", exitErr) - case connC := <-conns: - // take the first + return asap - return connC, nil - case <-ctx.Done(): - // break out and return error - break - } - } - return nil, exitErr -} - -func (s *Swarm) dialAddr(ctx context.Context, p peer.ID, addr ma.Multiaddr) (conn.Conn, error) { - log.Debugf("%s swarm dialing %s %s", s.local, p, addr) - - connC, err := s.dialer.Dial(ctx, addr, p) - if err != nil { - return nil, fmt.Errorf("%s --> %s dial attempt failed: %s", s.local, p, err) - } - - // if the connection is not to whom we thought it would be... - remotep := connC.RemotePeer() - if remotep != p { - connC.Close() - return nil, fmt.Errorf("misdial to %s through %s (got %s)", p, addr, remotep) - } - - // if the connection is to ourselves... - // this can happen TONS when Loopback addrs are advertized. - // (this should be caught by two checks above, but let's just make sure.) - if remotep == s.local { - connC.Close() - return nil, fmt.Errorf("misdial to %s through %s (got self)", p, addr) - } - - // success! we got one! - return connC, nil -} - -func (s *Swarm) filterAddrs(addrs []ma.Multiaddr) []ma.Multiaddr { - var out []ma.Multiaddr - for _, a := range addrs { - if !s.Filters.AddrBlocked(a) { - out = append(out, a) - } - } - return out -} - -// dialConnSetup is the setup logic for a connection from the dial side. it -// needs to add the Conn to the StreamSwarm, then run newConnSetup -func dialConnSetup(ctx context.Context, s *Swarm, connC conn.Conn) (*Conn, error) { - - psC, err := s.swarm.AddConn(connC) - if err != nil { - // connC is closed by caller if we fail. - return nil, fmt.Errorf("failed to add conn to ps.Swarm: %s", err) - } - - // ok try to setup the new connection. (newConnSetup will add to group) - swarmC, err := s.newConnSetup(ctx, psC) - if err != nil { - psC.Close() // we need to make sure psC is Closed. - return nil, err - } - - return swarmC, err -} - -// addrDialRateLimit returns a ratelimiting channel for dialing transport -// addrs like a. for example, tcp is fd-ratelimited. utp is not ratelimited. -func (s *Swarm) addrDialRateLimit(a ma.Multiaddr) chan struct{} { - if isFDCostlyTransport(a) { - return s.fdRateLimit - } - - // do not rate limit it at all - return make(chan struct{}, 1) -} - -func isFDCostlyTransport(a ma.Multiaddr) bool { - return isTCPMultiaddr(a) -} - -func isTCPMultiaddr(a ma.Multiaddr) bool { - p := a.Protocols() - return len(p) == 2 && (p[0].Name == "ip4" || p[0].Name == "ip6") && p[1].Name == "tcp" -} - -type AddrList []ma.Multiaddr - -func (al AddrList) Len() int { - return len(al) -} - -func (al AddrList) Swap(i, j int) { - al[i], al[j] = al[j], al[i] -} - -func (al AddrList) Less(i, j int) bool { - a := al[i] - b := al[j] - - // dial localhost addresses next, they should fail immediately - lba := manet.IsIPLoopback(a) - lbb := manet.IsIPLoopback(b) - if lba { - if !lbb { - return true - } - } - - // dial utp and similar 'non-fd-consuming' addresses first - fda := isFDCostlyTransport(a) - fdb := isFDCostlyTransport(b) - if !fda { - if fdb { - return true - } - - // if neither consume fd's, assume equal ordering - return false - } - - // if 'b' doesnt take a file descriptor - if !fdb { - return false - } - - // if 'b' is loopback and both take file descriptors - if lbb { - return false - } - - // for the rest, just sort by bytes - return bytes.Compare(a.Bytes(), b.Bytes()) > 0 -} diff --git a/p2p/net/swarm/swarm_listen.go b/p2p/net/swarm/swarm_listen.go deleted file mode 100644 index c19faccb274..00000000000 --- a/p2p/net/swarm/swarm_listen.go +++ /dev/null @@ -1,164 +0,0 @@ -package swarm - -import ( - "fmt" - - mconn "github.com/ipfs/go-ipfs/metrics/conn" - inet "github.com/ipfs/go-ipfs/p2p/net" - conn "github.com/ipfs/go-ipfs/p2p/net/conn" - transport "github.com/ipfs/go-ipfs/p2p/net/transport" - lgbl "github.com/ipfs/go-ipfs/util/eventlog/loggables" - - ma "github.com/ipfs/go-ipfs/Godeps/_workspace/src/github.com/jbenet/go-multiaddr" - ps "github.com/ipfs/go-ipfs/Godeps/_workspace/src/github.com/jbenet/go-peerstream" - context "github.com/ipfs/go-ipfs/Godeps/_workspace/src/golang.org/x/net/context" -) - -// Open listeners and reuse-dialers for the given addresses -func (s *Swarm) setupInterfaces(addrs []ma.Multiaddr) error { - errs := make([]error, len(addrs)) - var succeeded int - for i, a := range addrs { - tpt := s.transportForAddr(a) - if tpt == nil { - errs[i] = fmt.Errorf("no transport for address: %s", a) - continue - } - - d, err := tpt.Dialer(a, transport.TimeoutOpt(DialTimeout), transport.ReusePorts) - if err != nil { - errs[i] = err - continue - } - - s.dialer.AddDialer(d) - - list, err := tpt.Listen(a) - if err != nil { - errs[i] = err - continue - } - - err = s.addListener(list) - if err != nil { - errs[i] = err - continue - } - succeeded++ - } - - for i, e := range errs { - if e != nil { - log.Warning("listen on %s failed: %s", addrs[i], errs[i]) - } - } - if succeeded == 0 && len(addrs) > 0 { - return fmt.Errorf("failed to listen on any addresses: %s", errs) - } - - return nil -} - -func (s *Swarm) transportForAddr(a ma.Multiaddr) transport.Transport { - for _, t := range s.transports { - if t.Matches(a) { - return t - } - } - - return nil -} - -func (s *Swarm) addListener(tptlist transport.Listener) error { - - sk := s.peers.PrivKey(s.local) - if sk == nil { - // may be fine for sk to be nil, just log a warning. - log.Warning("Listener not given PrivateKey, so WILL NOT SECURE conns.") - } - - list, err := conn.WrapTransportListener(s.Context(), tptlist, s.local, sk) - if err != nil { - return err - } - - list.SetAddrFilters(s.Filters) - - if cw, ok := list.(conn.ListenerConnWrapper); ok { - cw.SetConnWrapper(func(c transport.Conn) transport.Conn { - return mconn.WrapConn(s.bwc, c) - }) - } - - return s.addConnListener(list) -} - -func (s *Swarm) addConnListener(list conn.Listener) error { - // AddListener to the peerstream Listener. this will begin accepting connections - // and streams! - sl, err := s.swarm.AddListener(list) - if err != nil { - return err - } - log.Debugf("Swarm Listeners at %s", s.ListenAddresses()) - - maddr := list.Multiaddr() - - // signal to our notifiees on successful conn. - s.notifyAll(func(n inet.Notifiee) { - n.Listen((*Network)(s), maddr) - }) - - // go consume peerstream's listen accept errors. note, these ARE errors. - // they may be killing the listener, and if we get _any_ we should be - // fixing this in our conn.Listener (to ignore them or handle them - // differently.) - go func(ctx context.Context, sl *ps.Listener) { - - // signal to our notifiees closing - defer s.notifyAll(func(n inet.Notifiee) { - n.ListenClose((*Network)(s), maddr) - }) - - for { - select { - case err, more := <-sl.AcceptErrors(): - if !more { - return - } - log.Errorf("swarm listener accept error: %s", err) - case <-ctx.Done(): - return - } - } - }(s.Context(), sl) - - return nil -} - -// connHandler is called by the StreamSwarm whenever a new connection is added -// here we configure it slightly. Note that this is sequential, so if anything -// will take a while do it in a goroutine. -// See https://godoc.org/github.com/jbenet/go-peerstream for more information -func (s *Swarm) connHandler(c *ps.Conn) *Conn { - ctx := context.Background() - // this context is for running the handshake, which -- when receiveing connections - // -- we have no bound on beyond what the transport protocol bounds it at. - // note that setup + the handshake are bounded by underlying io. - // (i.e. if TCP or UDP disconnects (or the swarm closes), we're done. - // Q: why not have a shorter handshake? think about an HTTP server on really slow conns. - // as long as the conn is live (TCP says its online), it tries its best. we follow suit.) - - sc, err := s.newConnSetup(ctx, c) - if err != nil { - log.Debug(err) - log.Event(ctx, "newConnHandlerDisconnect", lgbl.NetConn(c.NetConn()), lgbl.Error(err)) - c.Close() // boom. close it. - return nil - } - - // if a peer dials us, remove from dial backoff. - s.backf.Clear(sc.RemotePeer()) - - return sc -} diff --git a/p2p/net/swarm/swarm_net.go b/p2p/net/swarm/swarm_net.go deleted file mode 100644 index da9b52251e2..00000000000 --- a/p2p/net/swarm/swarm_net.go +++ /dev/null @@ -1,172 +0,0 @@ -package swarm - -import ( - "fmt" - - peer "github.com/ipfs/go-ipfs/p2p/peer" - - metrics "github.com/ipfs/go-ipfs/metrics" - inet "github.com/ipfs/go-ipfs/p2p/net" - - ma "github.com/ipfs/go-ipfs/Godeps/_workspace/src/github.com/jbenet/go-multiaddr" - "github.com/ipfs/go-ipfs/Godeps/_workspace/src/github.com/jbenet/goprocess" - context "github.com/ipfs/go-ipfs/Godeps/_workspace/src/golang.org/x/net/context" -) - -// Network implements the inet.Network interface. -// It is simply a swarm, with a few different functions -// to implement inet.Network. -type Network Swarm - -// NewNetwork constructs a new network and starts listening on given addresses. -func NewNetwork(ctx context.Context, listen []ma.Multiaddr, local peer.ID, - peers peer.Peerstore, bwc metrics.Reporter) (*Network, error) { - - s, err := NewSwarm(ctx, listen, local, peers, bwc) - if err != nil { - return nil, err - } - - return (*Network)(s), nil -} - -// DialPeer attempts to establish a connection to a given peer. -// Respects the context. -func (n *Network) DialPeer(ctx context.Context, p peer.ID) (inet.Conn, error) { - log.Debugf("[%s] network dialing peer [%s]", n.local, p) - sc, err := n.Swarm().Dial(ctx, p) - if err != nil { - return nil, err - } - - log.Debugf("network for %s finished dialing %s", n.local, p) - return inet.Conn(sc), nil -} - -// Process returns the network's Process -func (n *Network) Process() goprocess.Process { - return n.proc -} - -// Swarm returns the network's peerstream.Swarm -func (n *Network) Swarm() *Swarm { - return (*Swarm)(n) -} - -// LocalPeer the network's LocalPeer -func (n *Network) LocalPeer() peer.ID { - return n.Swarm().LocalPeer() -} - -// Peers returns the known peer IDs from the Peerstore -func (n *Network) Peers() []peer.ID { - return n.Swarm().Peers() -} - -// Peers returns the Peerstore, which tracks known peers -func (n *Network) Peerstore() peer.Peerstore { - return n.Swarm().peers -} - -// Conns returns the connected peers -func (n *Network) Conns() []inet.Conn { - conns1 := n.Swarm().Connections() - out := make([]inet.Conn, len(conns1)) - for i, c := range conns1 { - out[i] = inet.Conn(c) - } - return out -} - -// ConnsToPeer returns the connections in this Netowrk for given peer. -func (n *Network) ConnsToPeer(p peer.ID) []inet.Conn { - conns1 := n.Swarm().ConnectionsToPeer(p) - out := make([]inet.Conn, len(conns1)) - for i, c := range conns1 { - out[i] = inet.Conn(c) - } - return out -} - -// ClosePeer connection to peer -func (n *Network) ClosePeer(p peer.ID) error { - return n.Swarm().CloseConnection(p) -} - -// close is the real teardown function -func (n *Network) close() error { - return n.Swarm().Close() -} - -// Close calls the ContextCloser func -func (n *Network) Close() error { - return n.Swarm().proc.Close() -} - -// Listen tells the network to start listening on given multiaddrs. -func (n *Network) Listen(addrs ...ma.Multiaddr) error { - return n.Swarm().Listen(addrs...) -} - -// ListenAddresses returns a list of addresses at which this network listens. -func (n *Network) ListenAddresses() []ma.Multiaddr { - return n.Swarm().ListenAddresses() -} - -// InterfaceListenAddresses returns a list of addresses at which this network -// listens. It expands "any interface" addresses (/ip4/0.0.0.0, /ip6/::) to -// use the known local interfaces. -func (n *Network) InterfaceListenAddresses() ([]ma.Multiaddr, error) { - return n.Swarm().InterfaceListenAddresses() -} - -// Connectedness returns a state signaling connection capabilities -// For now only returns Connected || NotConnected. Expand into more later. -func (n *Network) Connectedness(p peer.ID) inet.Connectedness { - c := n.Swarm().ConnectionsToPeer(p) - if c != nil && len(c) > 0 { - return inet.Connected - } - return inet.NotConnected -} - -// NewStream returns a new stream to given peer p. -// If there is no connection to p, attempts to create one. -func (n *Network) NewStream(p peer.ID) (inet.Stream, error) { - log.Debugf("[%s] network opening stream to peer [%s]", n.local, p) - s, err := n.Swarm().NewStreamWithPeer(p) - if err != nil { - return nil, err - } - - return inet.Stream(s), nil -} - -// SetHandler sets the protocol handler on the Network's Muxer. -// This operation is threadsafe. -func (n *Network) SetStreamHandler(h inet.StreamHandler) { - n.Swarm().SetStreamHandler(h) -} - -// SetConnHandler sets the conn handler on the Network. -// This operation is threadsafe. -func (n *Network) SetConnHandler(h inet.ConnHandler) { - n.Swarm().SetConnHandler(func(c *Conn) { - h(inet.Conn(c)) - }) -} - -// String returns a string representation of Network. -func (n *Network) String() string { - return fmt.Sprintf("", n.LocalPeer()) -} - -// Notify signs up Notifiee to receive signals when events happen -func (n *Network) Notify(f inet.Notifiee) { - n.Swarm().Notify(f) -} - -// StopNotify unregisters Notifiee fromr receiving signals -func (n *Network) StopNotify(f inet.Notifiee) { - n.Swarm().StopNotify(f) -} diff --git a/p2p/net/swarm/swarm_net_test.go b/p2p/net/swarm/swarm_net_test.go deleted file mode 100644 index b5f5c569967..00000000000 --- a/p2p/net/swarm/swarm_net_test.go +++ /dev/null @@ -1,77 +0,0 @@ -package swarm_test - -import ( - "fmt" - "testing" - "time" - - context "github.com/ipfs/go-ipfs/Godeps/_workspace/src/golang.org/x/net/context" - inet "github.com/ipfs/go-ipfs/p2p/net" - testutil "github.com/ipfs/go-ipfs/p2p/test/util" -) - -// TestConnectednessCorrect starts a few networks, connects a few -// and tests Connectedness value is correct. -func TestConnectednessCorrect(t *testing.T) { - - ctx := context.Background() - - nets := make([]inet.Network, 4) - for i := 0; i < 4; i++ { - nets[i] = testutil.GenSwarmNetwork(t, ctx) - } - - // connect 0-1, 0-2, 0-3, 1-2, 2-3 - - dial := func(a, b inet.Network) { - testutil.DivulgeAddresses(b, a) - if _, err := a.DialPeer(ctx, b.LocalPeer()); err != nil { - t.Fatalf("Failed to dial: %s", err) - } - } - - dial(nets[0], nets[1]) - dial(nets[0], nets[3]) - dial(nets[1], nets[2]) - dial(nets[3], nets[2]) - - // there's something wrong with dial, i think. it's not finishing - // completely. there must be some async stuff. - <-time.After(100 * time.Millisecond) - - // test those connected show up correctly - - // test connected - expectConnectedness(t, nets[0], nets[1], inet.Connected) - expectConnectedness(t, nets[0], nets[3], inet.Connected) - expectConnectedness(t, nets[1], nets[2], inet.Connected) - expectConnectedness(t, nets[3], nets[2], inet.Connected) - - // test not connected - expectConnectedness(t, nets[0], nets[2], inet.NotConnected) - expectConnectedness(t, nets[1], nets[3], inet.NotConnected) - - for _, n := range nets { - n.Close() - } -} - -func expectConnectedness(t *testing.T, a, b inet.Network, expected inet.Connectedness) { - es := "%s is connected to %s, but Connectedness incorrect. %s %s" - if a.Connectedness(b.LocalPeer()) != expected { - t.Errorf(es, a, b, printConns(a), printConns(b)) - } - - // test symmetric case - if b.Connectedness(a.LocalPeer()) != expected { - t.Errorf(es, b, a, printConns(b), printConns(a)) - } -} - -func printConns(n inet.Network) string { - s := fmt.Sprintf("Connections in %s:\n", n) - for _, c := range n.Conns() { - s = s + fmt.Sprintf("- %s\n", c) - } - return s -} diff --git a/p2p/net/swarm/swarm_notif_test.go b/p2p/net/swarm/swarm_notif_test.go deleted file mode 100644 index 9b0e3a9babb..00000000000 --- a/p2p/net/swarm/swarm_notif_test.go +++ /dev/null @@ -1,210 +0,0 @@ -package swarm - -import ( - "testing" - "time" - - ma "github.com/ipfs/go-ipfs/Godeps/_workspace/src/github.com/jbenet/go-multiaddr" - context "github.com/ipfs/go-ipfs/Godeps/_workspace/src/golang.org/x/net/context" - - inet "github.com/ipfs/go-ipfs/p2p/net" - peer "github.com/ipfs/go-ipfs/p2p/peer" -) - -func TestNotifications(t *testing.T) { - ctx := context.Background() - swarms := makeSwarms(ctx, t, 5) - defer func() { - for _, s := range swarms { - s.Close() - } - }() - - timeout := 5 * time.Second - - // signup notifs - notifiees := make([]*netNotifiee, len(swarms)) - for i, swarm := range swarms { - n := newNetNotifiee() - swarm.Notify(n) - notifiees[i] = n - } - - connectSwarms(t, ctx, swarms) - - <-time.After(time.Millisecond) - // should've gotten 5 by now. - - // test everyone got the correct connection opened calls - for i, s := range swarms { - n := notifiees[i] - notifs := make(map[peer.ID][]inet.Conn) - for j, s2 := range swarms { - if i == j { - continue - } - - // this feels a little sketchy, but its probably okay - for len(s.ConnectionsToPeer(s2.LocalPeer())) != len(notifs[s2.LocalPeer()]) { - select { - case c := <-n.connected: - nfp := notifs[c.RemotePeer()] - notifs[c.RemotePeer()] = append(nfp, c) - case <-time.After(timeout): - t.Fatal("timeout") - } - } - } - - for p, cons := range notifs { - expect := s.ConnectionsToPeer(p) - if len(expect) != len(cons) { - t.Fatal("got different number of connections") - } - - for _, c := range cons { - var found bool - for _, c2 := range expect { - if c == c2 { - found = true - break - } - } - - if !found { - t.Fatal("connection not found!") - } - } - } - } - - complement := func(c inet.Conn) (*Swarm, *netNotifiee, *Conn) { - for i, s := range swarms { - for _, c2 := range s.Connections() { - if c.LocalMultiaddr().Equal(c2.RemoteMultiaddr()) && - c2.LocalMultiaddr().Equal(c.RemoteMultiaddr()) { - return s, notifiees[i], c2 - } - } - } - t.Fatal("complementary conn not found", c) - return nil, nil, nil - } - - testOCStream := func(n *netNotifiee, s inet.Stream) { - var s2 inet.Stream - select { - case s2 = <-n.openedStream: - t.Log("got notif for opened stream") - case <-time.After(timeout): - t.Fatal("timeout") - } - if s != s2 { - t.Fatal("got incorrect stream", s.Conn(), s2.Conn()) - } - - select { - case s2 = <-n.closedStream: - t.Log("got notif for closed stream") - case <-time.After(timeout): - t.Fatal("timeout") - } - if s != s2 { - t.Fatal("got incorrect stream", s.Conn(), s2.Conn()) - } - } - - streams := make(chan inet.Stream) - for _, s := range swarms { - s.SetStreamHandler(func(s inet.Stream) { - streams <- s - s.Close() - }) - } - - // open a streams in each conn - for i, s := range swarms { - for _, c := range s.Connections() { - _, n2, _ := complement(c) - - st1, err := c.NewStream() - if err != nil { - t.Error(err) - } else { - st1.Write([]byte("hello")) - st1.Close() - testOCStream(notifiees[i], st1) - st2 := <-streams - testOCStream(n2, st2) - } - } - } - - // close conns - for i, s := range swarms { - n := notifiees[i] - for _, c := range s.Connections() { - _, n2, c2 := complement(c) - c.Close() - c2.Close() - - var c3, c4 inet.Conn - select { - case c3 = <-n.disconnected: - case <-time.After(timeout): - t.Fatal("timeout") - } - if c != c3 { - t.Fatal("got incorrect conn", c, c3) - } - - select { - case c4 = <-n2.disconnected: - case <-time.After(timeout): - t.Fatal("timeout") - } - if c2 != c4 { - t.Fatal("got incorrect conn", c, c2) - } - } - } -} - -type netNotifiee struct { - listen chan ma.Multiaddr - listenClose chan ma.Multiaddr - connected chan inet.Conn - disconnected chan inet.Conn - openedStream chan inet.Stream - closedStream chan inet.Stream -} - -func newNetNotifiee() *netNotifiee { - return &netNotifiee{ - listen: make(chan ma.Multiaddr), - listenClose: make(chan ma.Multiaddr), - connected: make(chan inet.Conn), - disconnected: make(chan inet.Conn), - openedStream: make(chan inet.Stream), - closedStream: make(chan inet.Stream), - } -} - -func (nn *netNotifiee) Listen(n inet.Network, a ma.Multiaddr) { - nn.listen <- a -} -func (nn *netNotifiee) ListenClose(n inet.Network, a ma.Multiaddr) { - nn.listenClose <- a -} -func (nn *netNotifiee) Connected(n inet.Network, v inet.Conn) { - nn.connected <- v -} -func (nn *netNotifiee) Disconnected(n inet.Network, v inet.Conn) { - nn.disconnected <- v -} -func (nn *netNotifiee) OpenedStream(n inet.Network, v inet.Stream) { - nn.openedStream <- v -} -func (nn *netNotifiee) ClosedStream(n inet.Network, v inet.Stream) { - nn.closedStream <- v -} diff --git a/p2p/net/swarm/swarm_stream.go b/p2p/net/swarm/swarm_stream.go deleted file mode 100644 index 66dd6353b71..00000000000 --- a/p2p/net/swarm/swarm_stream.go +++ /dev/null @@ -1,54 +0,0 @@ -package swarm - -import ( - inet "github.com/ipfs/go-ipfs/p2p/net" - - ps "github.com/ipfs/go-ipfs/Godeps/_workspace/src/github.com/jbenet/go-peerstream" -) - -// a Stream is a wrapper around a ps.Stream that exposes a way to get -// our Conn and Swarm (instead of just the ps.Conn and ps.Swarm) -type Stream ps.Stream - -// Stream returns the underlying peerstream.Stream -func (s *Stream) Stream() *ps.Stream { - return (*ps.Stream)(s) -} - -// Conn returns the Conn associated with this Stream, as an inet.Conn -func (s *Stream) Conn() inet.Conn { - return s.SwarmConn() -} - -// SwarmConn returns the Conn associated with this Stream, as a *Conn -func (s *Stream) SwarmConn() *Conn { - return (*Conn)(s.Stream().Conn()) -} - -// Read reads bytes from a stream. -func (s *Stream) Read(p []byte) (n int, err error) { - return s.Stream().Read(p) -} - -// Write writes bytes to a stream, flushing for each call. -func (s *Stream) Write(p []byte) (n int, err error) { - return s.Stream().Write(p) -} - -// Close closes the stream, indicating this side is finished -// with the stream. -func (s *Stream) Close() error { - return s.Stream().Close() -} - -func wrapStream(pss *ps.Stream) *Stream { - return (*Stream)(pss) -} - -func wrapStreams(st []*ps.Stream) []*Stream { - out := make([]*Stream, len(st)) - for i, s := range st { - out[i] = wrapStream(s) - } - return out -} diff --git a/p2p/net/swarm/swarm_test.go b/p2p/net/swarm/swarm_test.go deleted file mode 100644 index cc458c4cae9..00000000000 --- a/p2p/net/swarm/swarm_test.go +++ /dev/null @@ -1,339 +0,0 @@ -package swarm - -import ( - "bytes" - "fmt" - "io" - "net" - "sync" - "testing" - "time" - - metrics "github.com/ipfs/go-ipfs/metrics" - inet "github.com/ipfs/go-ipfs/p2p/net" - peer "github.com/ipfs/go-ipfs/p2p/peer" - testutil "github.com/ipfs/go-ipfs/util/testutil" - - ma "github.com/ipfs/go-ipfs/Godeps/_workspace/src/github.com/jbenet/go-multiaddr" - context "github.com/ipfs/go-ipfs/Godeps/_workspace/src/golang.org/x/net/context" -) - -func EchoStreamHandler(stream inet.Stream) { - go func() { - defer stream.Close() - - // pull out the ipfs conn - c := stream.Conn() - log.Infof("%s ponging to %s", c.LocalPeer(), c.RemotePeer()) - - buf := make([]byte, 4) - - for { - if _, err := stream.Read(buf); err != nil { - if err != io.EOF { - log.Info("ping receive error:", err) - } - return - } - - if !bytes.Equal(buf, []byte("ping")) { - log.Infof("ping receive error: ping != %s %v", buf, buf) - return - } - - if _, err := stream.Write([]byte("pong")); err != nil { - log.Info("pond send error:", err) - return - } - } - }() -} - -func makeSwarms(ctx context.Context, t *testing.T, num int) []*Swarm { - swarms := make([]*Swarm, 0, num) - - for i := 0; i < num; i++ { - localnp := testutil.RandPeerNetParamsOrFatal(t) - - peerstore := peer.NewPeerstore() - peerstore.AddPubKey(localnp.ID, localnp.PubKey) - peerstore.AddPrivKey(localnp.ID, localnp.PrivKey) - - addrs := []ma.Multiaddr{localnp.Addr} - swarm, err := NewSwarm(ctx, addrs, localnp.ID, peerstore, metrics.NewBandwidthCounter()) - if err != nil { - t.Fatal(err) - } - - swarm.SetStreamHandler(EchoStreamHandler) - swarms = append(swarms, swarm) - } - - return swarms -} - -func connectSwarms(t *testing.T, ctx context.Context, swarms []*Swarm) { - - var wg sync.WaitGroup - connect := func(s *Swarm, dst peer.ID, addr ma.Multiaddr) { - // TODO: make a DialAddr func. - s.peers.AddAddr(dst, addr, peer.PermanentAddrTTL) - if _, err := s.Dial(ctx, dst); err != nil { - t.Fatal("error swarm dialing to peer", err) - } - wg.Done() - } - - log.Info("Connecting swarms simultaneously.") - for _, s1 := range swarms { - for _, s2 := range swarms { - if s2.local != s1.local { // don't connect to self. - wg.Add(1) - connect(s1, s2.LocalPeer(), s2.ListenAddresses()[0]) // try the first. - } - } - } - wg.Wait() - - for _, s := range swarms { - log.Infof("%s swarm routing table: %s", s.local, s.Peers()) - } -} - -func SubtestSwarm(t *testing.T, SwarmNum int, MsgNum int) { - // t.Skip("skipping for another test") - - ctx := context.Background() - swarms := makeSwarms(ctx, t, SwarmNum) - - // connect everyone - connectSwarms(t, ctx, swarms) - - // ping/pong - for _, s1 := range swarms { - log.Debugf("-------------------------------------------------------") - log.Debugf("%s ping pong round", s1.local) - log.Debugf("-------------------------------------------------------") - - _, cancel := context.WithCancel(ctx) - got := map[peer.ID]int{} - errChan := make(chan error, MsgNum*len(swarms)) - streamChan := make(chan *Stream, MsgNum) - - // send out "ping" x MsgNum to every peer - go func() { - defer close(streamChan) - - var wg sync.WaitGroup - send := func(p peer.ID) { - defer wg.Done() - - // first, one stream per peer (nice) - stream, err := s1.NewStreamWithPeer(p) - if err != nil { - errChan <- err - return - } - - // send out ping! - for k := 0; k < MsgNum; k++ { // with k messages - msg := "ping" - log.Debugf("%s %s %s (%d)", s1.local, msg, p, k) - if _, err := stream.Write([]byte(msg)); err != nil { - errChan <- err - continue - } - } - - // read it later - streamChan <- stream - } - - for _, s2 := range swarms { - if s2.local == s1.local { - continue // dont send to self... - } - - wg.Add(1) - go send(s2.local) - } - wg.Wait() - }() - - // receive "pong" x MsgNum from every peer - go func() { - defer close(errChan) - count := 0 - countShouldBe := MsgNum * (len(swarms) - 1) - for stream := range streamChan { // one per peer - defer stream.Close() - - // get peer on the other side - p := stream.Conn().RemotePeer() - - // receive pings - msgCount := 0 - msg := make([]byte, 4) - for k := 0; k < MsgNum; k++ { // with k messages - - // read from the stream - if _, err := stream.Read(msg); err != nil { - errChan <- err - continue - } - - if string(msg) != "pong" { - errChan <- fmt.Errorf("unexpected message: %s", msg) - continue - } - - log.Debugf("%s %s %s (%d)", s1.local, msg, p, k) - msgCount++ - } - - got[p] = msgCount - count += msgCount - } - - if count != countShouldBe { - errChan <- fmt.Errorf("count mismatch: %d != %d", count, countShouldBe) - } - }() - - // check any errors (blocks till consumer is done) - for err := range errChan { - if err != nil { - t.Error(err.Error()) - } - } - - log.Debugf("%s got pongs", s1.local) - if (len(swarms) - 1) != len(got) { - t.Errorf("got (%d) less messages than sent (%d).", len(got), len(swarms)) - } - - for p, n := range got { - if n != MsgNum { - t.Error("peer did not get all msgs", p, n, "/", MsgNum) - } - } - - cancel() - <-time.After(10 * time.Millisecond) - } - - for _, s := range swarms { - s.Close() - } -} - -func TestSwarm(t *testing.T) { - // t.Skip("skipping for another test") - t.Parallel() - - // msgs := 1000 - msgs := 100 - swarms := 5 - SubtestSwarm(t, swarms, msgs) -} - -func TestBasicSwarm(t *testing.T) { - // t.Skip("skipping for another test") - t.Parallel() - - msgs := 1 - swarms := 2 - SubtestSwarm(t, swarms, msgs) -} - -func TestConnHandler(t *testing.T) { - // t.Skip("skipping for another test") - t.Parallel() - - ctx := context.Background() - swarms := makeSwarms(ctx, t, 5) - - gotconn := make(chan struct{}, 10) - swarms[0].SetConnHandler(func(conn *Conn) { - gotconn <- struct{}{} - }) - - connectSwarms(t, ctx, swarms) - - <-time.After(time.Millisecond) - // should've gotten 5 by now. - - swarms[0].SetConnHandler(nil) - - expect := 4 - for i := 0; i < expect; i++ { - select { - case <-time.After(time.Second): - t.Fatal("failed to get connections") - case <-gotconn: - } - } - - select { - case <-gotconn: - t.Fatalf("should have connected to %d swarms", expect) - default: - } -} - -func TestAddrBlocking(t *testing.T) { - ctx := context.Background() - swarms := makeSwarms(ctx, t, 2) - - swarms[0].SetConnHandler(func(conn *Conn) { - t.Fatal("no connections should happen!") - }) - - _, block, err := net.ParseCIDR("127.0.0.1/8") - if err != nil { - t.Fatal(err) - } - - swarms[1].Filters.AddDialFilter(block) - - swarms[1].peers.AddAddr(swarms[0].LocalPeer(), swarms[0].ListenAddresses()[0], peer.PermanentAddrTTL) - _, err = swarms[1].Dial(ctx, swarms[0].LocalPeer()) - if err == nil { - t.Fatal("dial should have failed") - } - - swarms[0].peers.AddAddr(swarms[1].LocalPeer(), swarms[1].ListenAddresses()[0], peer.PermanentAddrTTL) - _, err = swarms[0].Dial(ctx, swarms[1].LocalPeer()) - if err == nil { - t.Fatal("dial should have failed") - } -} - -func TestFilterBounds(t *testing.T) { - ctx := context.Background() - swarms := makeSwarms(ctx, t, 2) - - conns := make(chan struct{}, 8) - swarms[0].SetConnHandler(func(conn *Conn) { - conns <- struct{}{} - }) - - // Address that we wont be dialing from - _, block, err := net.ParseCIDR("192.0.0.1/8") - if err != nil { - t.Fatal(err) - } - - // set filter on both sides, shouldnt matter - swarms[1].Filters.AddDialFilter(block) - swarms[0].Filters.AddDialFilter(block) - - connectSwarms(t, ctx, swarms) - - select { - case <-time.After(time.Second): - t.Fatal("should have gotten connection") - case <-conns: - t.Log("got connect") - } -} diff --git a/p2p/net/transport/reuseport.go b/p2p/net/transport/reuseport.go deleted file mode 100644 index e940a486d13..00000000000 --- a/p2p/net/transport/reuseport.go +++ /dev/null @@ -1,65 +0,0 @@ -package transport - -import ( - "net" - "os" - "strings" - "syscall" - - reuseport "github.com/ipfs/go-ipfs/Godeps/_workspace/src/github.com/jbenet/go-reuseport" -) - -// envReuseport is the env variable name used to turn off reuse port. -// It default to true. -const envReuseport = "IPFS_REUSEPORT" - -// envReuseportVal stores the value of envReuseport. defaults to true. -var envReuseportVal = true - -func init() { - v := strings.ToLower(os.Getenv(envReuseport)) - if v == "false" || v == "f" || v == "0" { - envReuseportVal = false - log.Infof("REUSEPORT disabled (IPFS_REUSEPORT=%s)", v) - } -} - -// reuseportIsAvailable returns whether reuseport is available to be used. This -// is here because we want to be able to turn reuseport on and off selectively. -// For now we use an ENV variable, as this handles our pressing need: -// -// IPFS_REUSEPORT=false ipfs daemon -// -// If this becomes a sought after feature, we could add this to the config. -// In the end, reuseport is a stop-gap. -func ReuseportIsAvailable() bool { - return envReuseportVal && reuseport.Available() -} - -// ReuseErrShouldRetry diagnoses whether to retry after a reuse error. -// if we failed to bind, we should retry. if bind worked and this is a -// real dial error (remote end didnt answer) then we should not retry. -func ReuseErrShouldRetry(err error) bool { - if err == nil { - return false // hey, it worked! no need to retry. - } - - // if it's a network timeout error, it's a legitimate failure. - if nerr, ok := err.(net.Error); ok && nerr.Timeout() { - return false - } - - errno, ok := err.(syscall.Errno) - if !ok { // not an errno? who knows what this is. retry. - return true - } - - switch errno { - case syscall.EADDRINUSE, syscall.EADDRNOTAVAIL: - return true // failure to bind. retry. - case syscall.ECONNREFUSED: - return false // real dial error - default: - return true // optimistically default to retry. - } -} diff --git a/p2p/net/transport/tcp.go b/p2p/net/transport/tcp.go deleted file mode 100644 index 8b200bbd0fb..00000000000 --- a/p2p/net/transport/tcp.go +++ /dev/null @@ -1,236 +0,0 @@ -package transport - -import ( - "fmt" - "net" - "sync" - "time" - - ma "github.com/ipfs/go-ipfs/Godeps/_workspace/src/github.com/jbenet/go-multiaddr" - manet "github.com/ipfs/go-ipfs/Godeps/_workspace/src/github.com/jbenet/go-multiaddr-net" - reuseport "github.com/ipfs/go-ipfs/Godeps/_workspace/src/github.com/jbenet/go-reuseport" - context "github.com/ipfs/go-ipfs/Godeps/_workspace/src/golang.org/x/net/context" - lgbl "github.com/ipfs/go-ipfs/util/eventlog/loggables" -) - -type TcpTransport struct { - dlock sync.Mutex - dialers map[string]Dialer - - llock sync.Mutex - listeners map[string]Listener -} - -func NewTCPTransport() *TcpTransport { - return &TcpTransport{ - dialers: make(map[string]Dialer), - listeners: make(map[string]Listener), - } -} - -func (t *TcpTransport) Dialer(laddr ma.Multiaddr, opts ...DialOpt) (Dialer, error) { - t.dlock.Lock() - defer t.dlock.Unlock() - s := laddr.String() - d, found := t.dialers[s] - if found { - return d, nil - } - var base manet.Dialer - - var doReuse bool - for _, o := range opts { - switch o := o.(type) { - case TimeoutOpt: - base.Timeout = time.Duration(o) - case ReuseportOpt: - doReuse = bool(o) - default: - return nil, fmt.Errorf("unrecognized option: %#v", o) - } - } - - tcpd, err := t.newTcpDialer(base, laddr, doReuse) - if err != nil { - return nil, err - } - - t.dialers[s] = tcpd - return tcpd, nil -} - -func (t *TcpTransport) Listen(laddr ma.Multiaddr) (Listener, error) { - t.llock.Lock() - defer t.llock.Unlock() - s := laddr.String() - l, found := t.listeners[s] - if found { - return l, nil - } - - list, err := manetListen(laddr) - if err != nil { - return nil, err - } - - tlist := &tcpListener{ - list: list, - transport: t, - } - - t.listeners[s] = tlist - return tlist, nil -} - -func manetListen(addr ma.Multiaddr) (manet.Listener, error) { - network, naddr, err := manet.DialArgs(addr) - if err != nil { - return nil, err - } - - if ReuseportIsAvailable() { - nl, err := reuseport.Listen(network, naddr) - if err == nil { - // hey, it worked! - return manet.WrapNetListener(nl) - } - // reuseport is available, but we failed to listen. log debug, and retry normally. - log.Debugf("reuseport available, but failed to listen: %s %s, %s", network, naddr, err) - } - - // either reuseport not available, or it failed. try normally. - return manet.Listen(addr) -} - -func (t *TcpTransport) Matches(a ma.Multiaddr) bool { - return IsTcpMultiaddr(a) -} - -type tcpDialer struct { - laddr ma.Multiaddr - - doReuse bool - - rd reuseport.Dialer - madialer manet.Dialer - - transport Transport -} - -func (t *TcpTransport) newTcpDialer(base manet.Dialer, laddr ma.Multiaddr, doReuse bool) (*tcpDialer, error) { - // get the local net.Addr manually - la, err := manet.ToNetAddr(laddr) - if err != nil { - return nil, err // something wrong with laddr. - } - - if doReuse && ReuseportIsAvailable() { - rd := reuseport.Dialer{ - D: net.Dialer{ - LocalAddr: la, - Timeout: base.Timeout, - }, - } - - return &tcpDialer{ - doReuse: true, - laddr: laddr, - rd: rd, - madialer: base, - transport: t, - }, nil - } - - return &tcpDialer{ - doReuse: false, - laddr: laddr, - madialer: base, - transport: t, - }, nil -} - -func (d *tcpDialer) Dial(raddr ma.Multiaddr) (Conn, error) { - var c manet.Conn - var err error - if d.doReuse { - c, err = d.reuseDial(raddr) - } else { - c, err = d.madialer.Dial(raddr) - } - - if err != nil { - return nil, err - } - - return &connWrap{ - Conn: c, - transport: d.transport, - }, nil -} - -func (d *tcpDialer) reuseDial(raddr ma.Multiaddr) (manet.Conn, error) { - logdial := lgbl.Dial("conn", "", "", d.laddr, raddr) - rpev := log.EventBegin(context.TODO(), "tptDialReusePort", logdial) - - network, netraddr, err := manet.DialArgs(raddr) - if err != nil { - return nil, err - } - - con, err := d.rd.Dial(network, netraddr) - if err == nil { - logdial["reuseport"] = "success" - rpev.Done() - return manet.WrapNetConn(con) - } - - if !ReuseErrShouldRetry(err) { - logdial["reuseport"] = "failure" - logdial["error"] = err - rpev.Done() - return nil, err - } - - logdial["reuseport"] = "retry" - logdial["error"] = err - rpev.Done() - - return d.madialer.Dial(raddr) -} - -func (d *tcpDialer) Matches(a ma.Multiaddr) bool { - return IsTcpMultiaddr(a) -} - -type tcpListener struct { - list manet.Listener - transport Transport -} - -func (d *tcpListener) Accept() (Conn, error) { - c, err := d.list.Accept() - if err != nil { - return nil, err - } - - return &connWrap{ - Conn: c, - transport: d.transport, - }, nil -} - -func (d *tcpListener) Addr() net.Addr { - return d.list.Addr() -} - -func (t *tcpListener) Multiaddr() ma.Multiaddr { - return t.list.Multiaddr() -} - -func (t *tcpListener) NetListener() net.Listener { - return t.list.NetListener() -} - -func (d *tcpListener) Close() error { - return d.list.Close() -} diff --git a/p2p/net/transport/transport.go b/p2p/net/transport/transport.go deleted file mode 100644 index e75f430290b..00000000000 --- a/p2p/net/transport/transport.go +++ /dev/null @@ -1,61 +0,0 @@ -package transport - -import ( - "net" - "time" - - ma "github.com/ipfs/go-ipfs/Godeps/_workspace/src/github.com/jbenet/go-multiaddr" - manet "github.com/ipfs/go-ipfs/Godeps/_workspace/src/github.com/jbenet/go-multiaddr-net" - logging "github.com/ipfs/go-ipfs/vendor/QmQg1J6vikuXF9oDvm4wpdeAUvvkVEKW1EYDw9HhTMnP2b/go-log" -) - -var log = logging.Logger("transport") - -type Conn interface { - manet.Conn - - Transport() Transport -} - -type Transport interface { - Dialer(laddr ma.Multiaddr, opts ...DialOpt) (Dialer, error) - Listen(laddr ma.Multiaddr) (Listener, error) - Matches(ma.Multiaddr) bool -} - -type Dialer interface { - Dial(raddr ma.Multiaddr) (Conn, error) - Matches(ma.Multiaddr) bool -} - -type Listener interface { - Accept() (Conn, error) - Close() error - Addr() net.Addr - Multiaddr() ma.Multiaddr -} - -type connWrap struct { - manet.Conn - transport Transport -} - -func (cw *connWrap) Transport() Transport { - return cw.transport -} - -type DialOpt interface{} -type TimeoutOpt time.Duration -type ReuseportOpt bool - -var ReusePorts ReuseportOpt = true - -func IsTcpMultiaddr(a ma.Multiaddr) bool { - p := a.Protocols() - return len(p) == 2 && (p[0].Name == "ip4" || p[0].Name == "ip6") && p[1].Name == "tcp" -} - -func IsUtpMultiaddr(a ma.Multiaddr) bool { - p := a.Protocols() - return len(p) == 3 && p[2].Name == "utp" -} diff --git a/p2p/net/transport/utp.go b/p2p/net/transport/utp.go deleted file mode 100644 index 162816fecac..00000000000 --- a/p2p/net/transport/utp.go +++ /dev/null @@ -1,148 +0,0 @@ -package transport - -import ( - "net" - "sync" - - utp "github.com/ipfs/go-ipfs/Godeps/_workspace/src/github.com/anacrolix/utp" - ma "github.com/ipfs/go-ipfs/Godeps/_workspace/src/github.com/jbenet/go-multiaddr" - manet "github.com/ipfs/go-ipfs/Godeps/_workspace/src/github.com/jbenet/go-multiaddr-net" - mautp "github.com/ipfs/go-ipfs/Godeps/_workspace/src/github.com/jbenet/go-multiaddr-net/utp" -) - -type UtpTransport struct { - sockLock sync.Mutex - sockets map[string]*UtpSocket -} - -func NewUtpTransport() *UtpTransport { - return &UtpTransport{ - sockets: make(map[string]*UtpSocket), - } -} - -func (d *UtpTransport) Matches(a ma.Multiaddr) bool { - p := a.Protocols() - return len(p) == 3 && p[2].Name == "utp" -} - -type UtpSocket struct { - s *utp.Socket - laddr ma.Multiaddr - transport Transport -} - -func (t *UtpTransport) Listen(laddr ma.Multiaddr) (Listener, error) { - t.sockLock.Lock() - defer t.sockLock.Unlock() - s, ok := t.sockets[laddr.String()] - if ok { - return s, nil - } - - ns, err := t.newConn(laddr) - if err != nil { - return nil, err - } - - t.sockets[laddr.String()] = ns - return ns, nil -} - -func (t *UtpTransport) Dialer(laddr ma.Multiaddr, opts ...DialOpt) (Dialer, error) { - t.sockLock.Lock() - defer t.sockLock.Unlock() - s, ok := t.sockets[laddr.String()] - if ok { - return s, nil - } - - ns, err := t.newConn(laddr, opts...) - if err != nil { - return nil, err - } - - t.sockets[laddr.String()] = ns - return ns, nil -} - -func (t *UtpTransport) newConn(addr ma.Multiaddr, opts ...DialOpt) (*UtpSocket, error) { - network, netaddr, err := manet.DialArgs(addr) - if err != nil { - return nil, err - } - - s, err := utp.NewSocket("udp"+network[3:], netaddr) - if err != nil { - return nil, err - } - - laddr, err := manet.FromNetAddr(mautp.MakeAddr(s.LocalAddr())) - if err != nil { - return nil, err - } - - return &UtpSocket{ - s: s, - laddr: laddr, - transport: t, - }, nil -} - -func (s *UtpSocket) Dial(raddr ma.Multiaddr) (Conn, error) { - _, addr, err := manet.DialArgs(raddr) - if err != nil { - return nil, err - } - - con, err := s.s.Dial(addr) - if err != nil { - return nil, err - } - - mnc, err := manet.WrapNetConn(&mautp.Conn{Conn: con}) - if err != nil { - return nil, err - } - - return &connWrap{ - Conn: mnc, - transport: s.transport, - }, nil -} - -func (s *UtpSocket) Accept() (Conn, error) { - c, err := s.s.Accept() - if err != nil { - return nil, err - } - - mnc, err := manet.WrapNetConn(&mautp.Conn{Conn: c}) - if err != nil { - return nil, err - } - - return &connWrap{ - Conn: mnc, - transport: s.transport, - }, nil -} - -func (s *UtpSocket) Matches(a ma.Multiaddr) bool { - p := a.Protocols() - return len(p) == 3 && p[2].Name == "utp" -} - -func (t *UtpSocket) Close() error { - return t.s.Close() -} - -func (t *UtpSocket) Addr() net.Addr { - return t.s.Addr() -} - -func (t *UtpSocket) Multiaddr() ma.Multiaddr { - return t.laddr -} - -var _ Transport = (*UtpTransport)(nil) diff --git a/p2p/peer/addr/addrsrcs.go b/p2p/peer/addr/addrsrcs.go deleted file mode 100644 index d8b942bef99..00000000000 --- a/p2p/peer/addr/addrsrcs.go +++ /dev/null @@ -1,70 +0,0 @@ -// Package addr provides utility functions to handle peer addresses. -package addr - -import ( - ma "github.com/ipfs/go-ipfs/Godeps/_workspace/src/github.com/jbenet/go-multiaddr" -) - -// AddrSource is a source of addresses. It allows clients to retrieve -// a set of addresses at a last possible moment in time. It is used -// to query a set of addresses that may change over time, as a result -// of the network changing interfaces or mappings. -type Source interface { - Addrs() []ma.Multiaddr -} - -// CombineSources returns a new AddrSource which is the -// concatenation of all input AddrSources: -// -// combined := CombinedSources(a, b) -// combined.Addrs() // append(a.Addrs(), b.Addrs()...) -// -func CombineSources(srcs ...Source) Source { - return combinedAS(srcs) -} - -type combinedAS []Source - -func (cas combinedAS) Addrs() []ma.Multiaddr { - var addrs []ma.Multiaddr - for _, s := range cas { - addrs = append(addrs, s.Addrs()...) - } - return addrs -} - -// UniqueSource returns a new AddrSource which omits duplicate -// addresses from the inputs: -// -// unique := UniqueSource(a, b) -// unique.Addrs() // append(a.Addrs(), b.Addrs()...) -// // but only adds each addr once. -// -func UniqueSource(srcs ...Source) Source { - return uniqueAS(srcs) -} - -type uniqueAS []Source - -func (uas uniqueAS) Addrs() []ma.Multiaddr { - seen := make(map[string]struct{}) - var addrs []ma.Multiaddr - for _, s := range uas { - for _, a := range s.Addrs() { - s := a.String() - if _, found := seen[s]; !found { - addrs = append(addrs, a) - seen[s] = struct{}{} - } - } - } - return addrs -} - -// Slice is a simple slice of addresses that implements -// the AddrSource interface. -type Slice []ma.Multiaddr - -func (as Slice) Addrs() []ma.Multiaddr { - return as -} diff --git a/p2p/peer/addr/addrsrcs_test.go b/p2p/peer/addr/addrsrcs_test.go deleted file mode 100644 index 7f175306d70..00000000000 --- a/p2p/peer/addr/addrsrcs_test.go +++ /dev/null @@ -1,78 +0,0 @@ -package addr - -import ( - "fmt" - "testing" - - ma "github.com/ipfs/go-ipfs/Godeps/_workspace/src/github.com/jbenet/go-multiaddr" -) - -func newAddrOrFatal(t *testing.T, s string) ma.Multiaddr { - a, err := ma.NewMultiaddr(s) - if err != nil { - t.Fatal("error parsing multiaddr", err) - } - return a -} - -func newAddrs(t *testing.T, n int) []ma.Multiaddr { - addrs := make([]ma.Multiaddr, n) - for i := 0; i < n; i++ { - s := fmt.Sprintf("/ip4/1.2.3.4/tcp/%d", i) - addrs[i] = newAddrOrFatal(t, s) - } - return addrs -} - -func addrSetsSame(a, b []ma.Multiaddr) bool { - if len(a) != len(b) { - return false - } - for i, aa := range a { - bb := b[i] - if !aa.Equal(bb) { - return false - } - } - return true -} - -func addrSourcesSame(a, b Source) bool { - return addrSetsSame(a.Addrs(), b.Addrs()) -} - -func TestAddrCombine(t *testing.T) { - addrs := newAddrs(t, 30) - a := Slice(addrs[:10]) - b := Slice(addrs[10:20]) - c := Slice(addrs[20:30]) - d := CombineSources(a, b, c) - if !addrSetsSame(addrs, d.Addrs()) { - t.Error("addrs differ") - } - if !addrSourcesSame(Slice(addrs), d) { - t.Error("addrs differ") - } -} - -func TestAddrUnique(t *testing.T) { - - addrs := newAddrs(t, 40) - a := Slice(addrs[:20]) - b := Slice(addrs[10:30]) - c := Slice(addrs[20:40]) - d := CombineSources(a, b, c) - e := UniqueSource(a, b, c) - if addrSetsSame(addrs, d.Addrs()) { - t.Error("addrs same") - } - if addrSourcesSame(Slice(addrs), d) { - t.Error("addrs same") - } - if !addrSetsSame(addrs, e.Addrs()) { - t.Error("addrs differ", addrs, "\n\n", e.Addrs(), "\n\n") - } - if !addrSourcesSame(Slice(addrs), e) { - t.Error("addrs differ", addrs, "\n\n", e.Addrs(), "\n\n") - } -} diff --git a/p2p/peer/addr_manager.go b/p2p/peer/addr_manager.go deleted file mode 100644 index 02b0fd11876..00000000000 --- a/p2p/peer/addr_manager.go +++ /dev/null @@ -1,188 +0,0 @@ -package peer - -import ( - "sync" - "time" - - ma "github.com/ipfs/go-ipfs/Godeps/_workspace/src/github.com/jbenet/go-multiaddr" -) - -const ( - - // TempAddrTTL is the ttl used for a short lived address - TempAddrTTL = time.Second * 10 - - // ProviderAddrTTL is the TTL of an address we've received from a provider. - // This is also a temporary address, but lasts longer. After this expires, - // the records we return will require an extra lookup. - ProviderAddrTTL = time.Minute * 10 - - // RecentlyConnectedAddrTTL is used when we recently connected to a peer. - // It means that we are reasonably certain of the peer's address. - RecentlyConnectedAddrTTL = time.Minute * 10 - - // OwnObservedAddrTTL is used for our own external addresses observed by peers. - OwnObservedAddrTTL = time.Minute * 10 - - // PermanentAddrTTL is the ttl for a "permanent address" (e.g. bootstrap nodes) - // if we haven't shipped you an update to ipfs in 356 days - // we probably arent running the same bootstrap nodes... - PermanentAddrTTL = time.Hour * 24 * 356 - - // ConnectedAddrTTL is the ttl used for the addresses of a peer to whom - // we're connected directly. This is basically permanent, as we will - // clear them + re-add under a TempAddrTTL after disconnecting. - ConnectedAddrTTL = PermanentAddrTTL -) - -type expiringAddr struct { - Addr ma.Multiaddr - TTL time.Time -} - -func (e *expiringAddr) ExpiredBy(t time.Time) bool { - return t.After(e.TTL) -} - -type addrSet map[string]expiringAddr - -// AddrManager manages addresses. -// The zero-value is ready to be used. -type AddrManager struct { - addrmu sync.Mutex // guards addrs - addrs map[ID]addrSet -} - -// ensures the AddrManager is initialized. -// So we can use the zero value. -func (mgr *AddrManager) init() { - if mgr.addrs == nil { - mgr.addrs = make(map[ID]addrSet) - } -} - -func (mgr *AddrManager) Peers() []ID { - mgr.addrmu.Lock() - defer mgr.addrmu.Unlock() - if mgr.addrs == nil { - return nil - } - - pids := make([]ID, 0, len(mgr.addrs)) - for pid := range mgr.addrs { - pids = append(pids, pid) - } - return pids -} - -// AddAddr calls AddAddrs(p, []ma.Multiaddr{addr}, ttl) -func (mgr *AddrManager) AddAddr(p ID, addr ma.Multiaddr, ttl time.Duration) { - mgr.AddAddrs(p, []ma.Multiaddr{addr}, ttl) -} - -// AddAddrs gives AddrManager addresses to use, with a given ttl -// (time-to-live), after which the address is no longer valid. -// If the manager has a longer TTL, the operation is a no-op for that address -func (mgr *AddrManager) AddAddrs(p ID, addrs []ma.Multiaddr, ttl time.Duration) { - mgr.addrmu.Lock() - defer mgr.addrmu.Unlock() - - // if ttl is zero, exit. nothing to do. - if ttl <= 0 { - return - } - - // so zero value can be used - mgr.init() - - amap, found := mgr.addrs[p] - if !found { - amap = make(addrSet) - mgr.addrs[p] = amap - } - - // only expand ttls - exp := time.Now().Add(ttl) - for _, addr := range addrs { - addrstr := addr.String() - a, found := amap[addrstr] - if !found || exp.After(a.TTL) { - amap[addrstr] = expiringAddr{Addr: addr, TTL: exp} - } - } -} - -// SetAddr calls mgr.SetAddrs(p, addr, ttl) -func (mgr *AddrManager) SetAddr(p ID, addr ma.Multiaddr, ttl time.Duration) { - mgr.SetAddrs(p, []ma.Multiaddr{addr}, ttl) -} - -// SetAddrs sets the ttl on addresses. This clears any TTL there previously. -// This is used when we receive the best estimate of the validity of an address. -func (mgr *AddrManager) SetAddrs(p ID, addrs []ma.Multiaddr, ttl time.Duration) { - mgr.addrmu.Lock() - defer mgr.addrmu.Unlock() - - // so zero value can be used - mgr.init() - - amap, found := mgr.addrs[p] - if !found { - amap = make(addrSet) - mgr.addrs[p] = amap - } - - exp := time.Now().Add(ttl) - for _, addr := range addrs { - // re-set all of them for new ttl. - addrs := addr.String() - - if ttl > 0 { - amap[addrs] = expiringAddr{Addr: addr, TTL: exp} - } else { - delete(amap, addrs) - } - } -} - -// Addresses returns all known (and valid) addresses for a given -func (mgr *AddrManager) Addrs(p ID) []ma.Multiaddr { - mgr.addrmu.Lock() - defer mgr.addrmu.Unlock() - - // not initialized? nothing to give. - if mgr.addrs == nil { - return nil - } - - maddrs, found := mgr.addrs[p] - if !found { - return nil - } - - now := time.Now() - good := make([]ma.Multiaddr, 0, len(maddrs)) - var expired []string - for s, m := range maddrs { - if m.ExpiredBy(now) { - expired = append(expired, s) - } else { - good = append(good, m.Addr) - } - } - - // clean up the expired ones. - for _, s := range expired { - delete(maddrs, s) - } - return good -} - -// ClearAddresses removes all previously stored addresses -func (mgr *AddrManager) ClearAddrs(p ID) { - mgr.addrmu.Lock() - defer mgr.addrmu.Unlock() - mgr.init() - - mgr.addrs[p] = make(addrSet) // clear what was there before -} diff --git a/p2p/peer/addr_manager_test.go b/p2p/peer/addr_manager_test.go deleted file mode 100644 index 2bd480fdd57..00000000000 --- a/p2p/peer/addr_manager_test.go +++ /dev/null @@ -1,180 +0,0 @@ -package peer - -import ( - "testing" - "time" - - ma "github.com/ipfs/go-ipfs/Godeps/_workspace/src/github.com/jbenet/go-multiaddr" -) - -func IDS(t *testing.T, ids string) ID { - id, err := IDB58Decode(ids) - if err != nil { - t.Fatal(err) - } - return id -} - -func MA(t *testing.T, m string) ma.Multiaddr { - maddr, err := ma.NewMultiaddr(m) - if err != nil { - t.Fatal(err) - } - return maddr -} - -func testHas(t *testing.T, exp, act []ma.Multiaddr) { - if len(exp) != len(act) { - t.Fatal("lengths not the same") - } - - for _, a := range exp { - found := false - - for _, b := range act { - if a.Equal(b) { - found = true - break - } - } - - if !found { - t.Fatal("expected address %s not found", a) - } - } -} - -func TestAddresses(t *testing.T) { - - id1 := IDS(t, "QmcNstKuwBBoVTpSCSDrwzjgrRcaYXK833Psuz2EMHwyQN") - id2 := IDS(t, "QmRmPL3FDZKE3Qiwv1RosLdwdvbvg17b2hB39QPScgWKKZ") - id3 := IDS(t, "QmPhi7vBsChP7sjRoZGgg7bcKqF6MmCcQwvRbDte8aJ6Kn") - id4 := IDS(t, "QmPhi7vBsChP7sjRoZGgg7bcKqF6MmCcQwvRbDte8aJ5Kn") - id5 := IDS(t, "QmPhi7vBsChP7sjRoZGgg7bcKqF6MmCcQwvRbDte8aJ5Km") - - ma11 := MA(t, "/ip4/1.2.3.1/tcp/1111") - ma21 := MA(t, "/ip4/2.2.3.2/tcp/1111") - ma22 := MA(t, "/ip4/2.2.3.2/tcp/2222") - ma31 := MA(t, "/ip4/3.2.3.3/tcp/1111") - ma32 := MA(t, "/ip4/3.2.3.3/tcp/2222") - ma33 := MA(t, "/ip4/3.2.3.3/tcp/3333") - ma41 := MA(t, "/ip4/4.2.3.3/tcp/1111") - ma42 := MA(t, "/ip4/4.2.3.3/tcp/2222") - ma43 := MA(t, "/ip4/4.2.3.3/tcp/3333") - ma44 := MA(t, "/ip4/4.2.3.3/tcp/4444") - ma51 := MA(t, "/ip4/5.2.3.3/tcp/1111") - ma52 := MA(t, "/ip4/5.2.3.3/tcp/2222") - ma53 := MA(t, "/ip4/5.2.3.3/tcp/3333") - ma54 := MA(t, "/ip4/5.2.3.3/tcp/4444") - ma55 := MA(t, "/ip4/5.2.3.3/tcp/5555") - - ttl := time.Hour - m := AddrManager{} - m.AddAddr(id1, ma11, ttl) - - m.AddAddrs(id2, []ma.Multiaddr{ma21, ma22}, ttl) - m.AddAddrs(id2, []ma.Multiaddr{ma21, ma22}, ttl) // idempotency - - m.AddAddr(id3, ma31, ttl) - m.AddAddr(id3, ma32, ttl) - m.AddAddr(id3, ma33, ttl) - m.AddAddr(id3, ma33, ttl) // idempotency - m.AddAddr(id3, ma33, ttl) - - m.AddAddrs(id4, []ma.Multiaddr{ma41, ma42, ma43, ma44}, ttl) // multiple - - m.AddAddrs(id5, []ma.Multiaddr{ma21, ma22}, ttl) // clearing - m.AddAddrs(id5, []ma.Multiaddr{ma41, ma42, ma43, ma44}, ttl) // clearing - m.ClearAddrs(id5) - m.AddAddrs(id5, []ma.Multiaddr{ma51, ma52, ma53, ma54, ma55}, ttl) // clearing - - // test the Addresses return value - testHas(t, []ma.Multiaddr{ma11}, m.Addrs(id1)) - testHas(t, []ma.Multiaddr{ma21, ma22}, m.Addrs(id2)) - testHas(t, []ma.Multiaddr{ma31, ma32, ma33}, m.Addrs(id3)) - testHas(t, []ma.Multiaddr{ma41, ma42, ma43, ma44}, m.Addrs(id4)) - testHas(t, []ma.Multiaddr{ma51, ma52, ma53, ma54, ma55}, m.Addrs(id5)) - -} - -func TestAddressesExpire(t *testing.T) { - - id1 := IDS(t, "QmcNstKuwBBoVTpSCSDrwzjgrRcaYXK833Psuz2EMHwyQN") - id2 := IDS(t, "QmcNstKuwBBoVTpSCSDrwzjgrRcaYXK833Psuz2EMHwyQM") - ma11 := MA(t, "/ip4/1.2.3.1/tcp/1111") - ma12 := MA(t, "/ip4/2.2.3.2/tcp/2222") - ma13 := MA(t, "/ip4/3.2.3.3/tcp/3333") - ma24 := MA(t, "/ip4/4.2.3.3/tcp/4444") - ma25 := MA(t, "/ip4/5.2.3.3/tcp/5555") - - m := AddrManager{} - m.AddAddr(id1, ma11, time.Hour) - m.AddAddr(id1, ma12, time.Hour) - m.AddAddr(id1, ma13, time.Hour) - m.AddAddr(id2, ma24, time.Hour) - m.AddAddr(id2, ma25, time.Hour) - - testHas(t, []ma.Multiaddr{ma11, ma12, ma13}, m.Addrs(id1)) - testHas(t, []ma.Multiaddr{ma24, ma25}, m.Addrs(id2)) - - m.SetAddr(id1, ma11, 2*time.Hour) - m.SetAddr(id1, ma12, 2*time.Hour) - m.SetAddr(id1, ma13, 2*time.Hour) - m.SetAddr(id2, ma24, 2*time.Hour) - m.SetAddr(id2, ma25, 2*time.Hour) - - testHas(t, []ma.Multiaddr{ma11, ma12, ma13}, m.Addrs(id1)) - testHas(t, []ma.Multiaddr{ma24, ma25}, m.Addrs(id2)) - - m.SetAddr(id1, ma11, time.Millisecond) - <-time.After(time.Millisecond) - testHas(t, []ma.Multiaddr{ma12, ma13}, m.Addrs(id1)) - testHas(t, []ma.Multiaddr{ma24, ma25}, m.Addrs(id2)) - - m.SetAddr(id1, ma13, time.Millisecond) - <-time.After(time.Millisecond) - testHas(t, []ma.Multiaddr{ma12}, m.Addrs(id1)) - testHas(t, []ma.Multiaddr{ma24, ma25}, m.Addrs(id2)) - - m.SetAddr(id2, ma24, time.Millisecond) - <-time.After(time.Millisecond) - testHas(t, []ma.Multiaddr{ma12}, m.Addrs(id1)) - testHas(t, []ma.Multiaddr{ma25}, m.Addrs(id2)) - - m.SetAddr(id2, ma25, time.Millisecond) - <-time.After(time.Millisecond) - testHas(t, []ma.Multiaddr{ma12}, m.Addrs(id1)) - testHas(t, nil, m.Addrs(id2)) - - m.SetAddr(id1, ma12, time.Millisecond) - <-time.After(time.Millisecond) - testHas(t, nil, m.Addrs(id1)) - testHas(t, nil, m.Addrs(id2)) -} - -func TestClearWorks(t *testing.T) { - - id1 := IDS(t, "QmcNstKuwBBoVTpSCSDrwzjgrRcaYXK833Psuz2EMHwyQN") - id2 := IDS(t, "QmcNstKuwBBoVTpSCSDrwzjgrRcaYXK833Psuz2EMHwyQM") - ma11 := MA(t, "/ip4/1.2.3.1/tcp/1111") - ma12 := MA(t, "/ip4/2.2.3.2/tcp/2222") - ma13 := MA(t, "/ip4/3.2.3.3/tcp/3333") - ma24 := MA(t, "/ip4/4.2.3.3/tcp/4444") - ma25 := MA(t, "/ip4/5.2.3.3/tcp/5555") - - m := AddrManager{} - m.AddAddr(id1, ma11, time.Hour) - m.AddAddr(id1, ma12, time.Hour) - m.AddAddr(id1, ma13, time.Hour) - m.AddAddr(id2, ma24, time.Hour) - m.AddAddr(id2, ma25, time.Hour) - - testHas(t, []ma.Multiaddr{ma11, ma12, ma13}, m.Addrs(id1)) - testHas(t, []ma.Multiaddr{ma24, ma25}, m.Addrs(id2)) - - m.ClearAddrs(id1) - m.ClearAddrs(id2) - - testHas(t, nil, m.Addrs(id1)) - testHas(t, nil, m.Addrs(id2)) -} diff --git a/p2p/peer/metrics.go b/p2p/peer/metrics.go deleted file mode 100644 index 6cad11cdfd4..00000000000 --- a/p2p/peer/metrics.go +++ /dev/null @@ -1,63 +0,0 @@ -package peer - -import ( - "sync" - "time" -) - -// LatencyEWMASmooting governs the decay of the EWMA (the speed -// at which it changes). This must be a normalized (0-1) value. -// 1 is 100% change, 0 is no change. -var LatencyEWMASmoothing = 0.1 - -// Metrics is just an object that tracks metrics -// across a set of peers. -type Metrics interface { - - // RecordLatency records a new latency measurement - RecordLatency(ID, time.Duration) - - // LatencyEWMA returns an exponentially-weighted moving avg. - // of all measurements of a peer's latency. - LatencyEWMA(ID) time.Duration -} - -type metrics struct { - latmap map[ID]time.Duration - latmu sync.RWMutex -} - -func NewMetrics() Metrics { - return &metrics{ - latmap: make(map[ID]time.Duration), - } -} - -// RecordLatency records a new latency measurement -func (m *metrics) RecordLatency(p ID, next time.Duration) { - nextf := float64(next) - s := LatencyEWMASmoothing - if s > 1 || s < 0 { - s = 0.1 // ignore the knob. it's broken. look, it jiggles. - } - - m.latmu.Lock() - ewma, found := m.latmap[p] - ewmaf := float64(ewma) - if !found { - m.latmap[p] = next // when no data, just take it as the mean. - } else { - nextf = ((1.0 - s) * ewmaf) + (s * nextf) - m.latmap[p] = time.Duration(nextf) - } - m.latmu.Unlock() -} - -// LatencyEWMA returns an exponentially-weighted moving avg. -// of all measurements of a peer's latency. -func (m *metrics) LatencyEWMA(p ID) time.Duration { - m.latmu.RLock() - lat := m.latmap[p] - m.latmu.RUnlock() - return time.Duration(lat) -} diff --git a/p2p/peer/metrics_test.go b/p2p/peer/metrics_test.go deleted file mode 100644 index db5f3a94d84..00000000000 --- a/p2p/peer/metrics_test.go +++ /dev/null @@ -1,40 +0,0 @@ -package peer_test - -import ( - "fmt" - "math/rand" - "testing" - "time" - - peer "github.com/ipfs/go-ipfs/p2p/peer" - testutil "github.com/ipfs/go-ipfs/util/testutil" -) - -func TestLatencyEWMAFun(t *testing.T) { - t.Skip("run it for fun") - - m := peer.NewMetrics() - id, err := testutil.RandPeerID() - if err != nil { - t.Fatal(err) - } - - mu := 100.0 - sig := 10.0 - next := func() time.Duration { - mu = (rand.NormFloat64() * sig) + mu - return time.Duration(mu) - } - - print := func() { - fmt.Printf("%3.f %3.f --> %d\n", sig, mu, m.LatencyEWMA(id)) - } - - for { - select { - case <-time.After(200 * time.Millisecond): - m.RecordLatency(id, next()) - print() - } - } -} diff --git a/p2p/peer/peer.go b/p2p/peer/peer.go deleted file mode 100644 index a7b403becf5..00000000000 --- a/p2p/peer/peer.go +++ /dev/null @@ -1,180 +0,0 @@ -// package peer implements an object used to represent peers in the ipfs network. -package peer - -import ( - "encoding/hex" - "encoding/json" - "fmt" - "strings" - - b58 "github.com/ipfs/go-ipfs/Godeps/_workspace/src/github.com/jbenet/go-base58" - ma "github.com/ipfs/go-ipfs/Godeps/_workspace/src/github.com/jbenet/go-multiaddr" - mh "github.com/ipfs/go-ipfs/Godeps/_workspace/src/github.com/jbenet/go-multihash" - - ic "github.com/ipfs/go-ipfs/p2p/crypto" - u "github.com/ipfs/go-ipfs/util" - logging "github.com/ipfs/go-ipfs/vendor/QmQg1J6vikuXF9oDvm4wpdeAUvvkVEKW1EYDw9HhTMnP2b/go-log" -) - -var log = logging.Logger("peer") - -// ID represents the identity of a peer. -type ID string - -// Pretty returns a b58-encoded string of the ID -func (id ID) Pretty() string { - return IDB58Encode(id) -} - -func (id ID) Loggable() map[string]interface{} { - return map[string]interface{}{ - "peerID": id.Pretty(), - } -} - -// String prints out the peer. -// -// TODO(brian): ensure correctness at ID generation and -// enforce this by only exposing functions that generate -// IDs safely. Then any peer.ID type found in the -// codebase is known to be correct. -func (id ID) String() string { - pid := id.Pretty() - - //All sha256 nodes start with Qm - //We can skip the Qm to make the peer.ID more useful - if strings.HasPrefix(pid, "Qm") { - pid = pid[2:] - } - - maxRunes := 6 - if len(pid) < maxRunes { - maxRunes = len(pid) - } - return fmt.Sprintf("", pid[:maxRunes]) -} - -// MatchesPrivateKey tests whether this ID was derived from sk -func (id ID) MatchesPrivateKey(sk ic.PrivKey) bool { - return id.MatchesPublicKey(sk.GetPublic()) -} - -// MatchesPublicKey tests whether this ID was derived from pk -func (id ID) MatchesPublicKey(pk ic.PubKey) bool { - oid, err := IDFromPublicKey(pk) - if err != nil { - return false - } - return oid == id -} - -// IDFromString cast a string to ID type, and validate -// the id to make sure it is a multihash. -func IDFromString(s string) (ID, error) { - if _, err := mh.Cast([]byte(s)); err != nil { - return ID(""), err - } - return ID(s), nil -} - -// IDFromBytes cast a string to ID type, and validate -// the id to make sure it is a multihash. -func IDFromBytes(b []byte) (ID, error) { - if _, err := mh.Cast(b); err != nil { - return ID(""), err - } - return ID(b), nil -} - -// IDB58Decode returns a b58-decoded Peer -func IDB58Decode(s string) (ID, error) { - m, err := mh.FromB58String(s) - if err != nil { - return "", err - } - return ID(m), err -} - -// IDB58Encode returns b58-encoded string -func IDB58Encode(id ID) string { - return b58.Encode([]byte(id)) -} - -// IDHexDecode returns a b58-decoded Peer -func IDHexDecode(s string) (ID, error) { - m, err := mh.FromHexString(s) - if err != nil { - return "", err - } - return ID(m), err -} - -// IDHexEncode returns b58-encoded string -func IDHexEncode(id ID) string { - return hex.EncodeToString([]byte(id)) -} - -// IDFromPublicKey returns the Peer ID corresponding to pk -func IDFromPublicKey(pk ic.PubKey) (ID, error) { - b, err := pk.Bytes() - if err != nil { - return "", err - } - hash := u.Hash(b) - return ID(hash), nil -} - -// IDFromPrivateKey returns the Peer ID corresponding to sk -func IDFromPrivateKey(sk ic.PrivKey) (ID, error) { - return IDFromPublicKey(sk.GetPublic()) -} - -// Map maps a Peer ID to a struct. -type Set map[ID]struct{} - -// PeerInfo is a small struct used to pass around a peer with -// a set of addresses (and later, keys?). This is not meant to be -// a complete view of the system, but rather to model updates to -// the peerstore. It is used by things like the routing system. -type PeerInfo struct { - ID ID - Addrs []ma.Multiaddr -} - -func (pi *PeerInfo) MarshalJSON() ([]byte, error) { - out := make(map[string]interface{}) - out["ID"] = IDB58Encode(pi.ID) - var addrs []string - for _, a := range pi.Addrs { - addrs = append(addrs, a.String()) - } - out["Addrs"] = addrs - return json.Marshal(out) -} - -func (pi *PeerInfo) UnmarshalJSON(b []byte) error { - var data map[string]interface{} - err := json.Unmarshal(b, &data) - if err != nil { - return err - } - pid, err := IDB58Decode(data["ID"].(string)) - if err != nil { - return err - } - pi.ID = pid - addrs, ok := data["Addrs"].([]interface{}) - if ok { - for _, a := range addrs { - pi.Addrs = append(pi.Addrs, ma.StringCast(a.(string))) - } - } - return nil -} - -// IDSlice for sorting peers -type IDSlice []ID - -func (es IDSlice) Len() int { return len(es) } -func (es IDSlice) Swap(i, j int) { es[i], es[j] = es[j], es[i] } -func (es IDSlice) Less(i, j int) bool { return string(es[i]) < string(es[j]) } diff --git a/p2p/peer/peer_test.go b/p2p/peer/peer_test.go deleted file mode 100644 index 80d6d9f0797..00000000000 --- a/p2p/peer/peer_test.go +++ /dev/null @@ -1,163 +0,0 @@ -package peer_test - -import ( - "encoding/base64" - "fmt" - "strings" - "testing" - - ic "github.com/ipfs/go-ipfs/p2p/crypto" - . "github.com/ipfs/go-ipfs/p2p/peer" - u "github.com/ipfs/go-ipfs/util" - tu "github.com/ipfs/go-ipfs/util/testutil" - - b58 "github.com/ipfs/go-ipfs/Godeps/_workspace/src/github.com/jbenet/go-base58" -) - -var gen1 keyset // generated -var gen2 keyset // generated -var man keyset // manual - -func init() { - if err := gen1.generate(); err != nil { - panic(err) - } - if err := gen2.generate(); err != nil { - panic(err) - } - - skManBytes = strings.Replace(skManBytes, "\n", "", -1) - if err := man.load(hpkpMan, skManBytes); err != nil { - panic(err) - } -} - -type keyset struct { - sk ic.PrivKey - pk ic.PubKey - hpk string - hpkp string -} - -func (ks *keyset) generate() error { - var err error - ks.sk, ks.pk, err = tu.RandTestKeyPair(512) - if err != nil { - return err - } - - bpk, err := ks.pk.Bytes() - if err != nil { - return err - } - - ks.hpk = string(u.Hash(bpk)) - ks.hpkp = b58.Encode([]byte(ks.hpk)) - return nil -} - -func (ks *keyset) load(hpkp, skBytesStr string) error { - skBytes, err := base64.StdEncoding.DecodeString(skBytesStr) - if err != nil { - return err - } - - ks.sk, err = ic.UnmarshalPrivateKey(skBytes) - if err != nil { - return err - } - - ks.pk = ks.sk.GetPublic() - bpk, err := ks.pk.Bytes() - if err != nil { - return err - } - - ks.hpk = string(u.Hash(bpk)) - ks.hpkp = b58.Encode([]byte(ks.hpk)) - if ks.hpkp != hpkp { - return fmt.Errorf("hpkp doesn't match key. %s", hpkp) - } - return nil -} - -func TestIDMatchesPublicKey(t *testing.T) { - - test := func(ks keyset) { - p1, err := IDB58Decode(ks.hpkp) - if err != nil { - t.Fatal(err) - } - - if ks.hpk != string(p1) { - t.Error("p1 and hpk differ") - } - - if !p1.MatchesPublicKey(ks.pk) { - t.Fatal("p1 does not match pk") - } - - p2, err := IDFromPublicKey(ks.pk) - if err != nil { - t.Fatal(err) - } - - if p1 != p2 { - t.Error("p1 and p2 differ", p1.Pretty(), p2.Pretty()) - } - - if p2.Pretty() != ks.hpkp { - t.Error("hpkp and p2.Pretty differ", ks.hpkp, p2.Pretty()) - } - } - - test(gen1) - test(gen2) - test(man) -} - -func TestIDMatchesPrivateKey(t *testing.T) { - - test := func(ks keyset) { - p1, err := IDB58Decode(ks.hpkp) - if err != nil { - t.Fatal(err) - } - - if ks.hpk != string(p1) { - t.Error("p1 and hpk differ") - } - - if !p1.MatchesPrivateKey(ks.sk) { - t.Fatal("p1 does not match sk") - } - - p2, err := IDFromPrivateKey(ks.sk) - if err != nil { - t.Fatal(err) - } - - if p1 != p2 { - t.Error("p1 and p2 differ", p1.Pretty(), p2.Pretty()) - } - } - - test(gen1) - test(gen2) - test(man) -} - -var hpkpMan = `QmRK3JgmVEGiewxWbhpXLJyjWuGuLeSTMTndA1coMHEy5o` -var skManBytes = ` -CAAS4AQwggJcAgEAAoGBAL7w+Wc4VhZhCdM/+Hccg5Nrf4q9NXWwJylbSrXz/unFS24wyk6pEk0zi3W -7li+vSNVO+NtJQw9qGNAMtQKjVTP+3Vt/jfQRnQM3s6awojtjueEWuLYVt62z7mofOhCtj+VwIdZNBo -/EkLZ0ETfcvN5LVtLYa8JkXybnOPsLvK+PAgMBAAECgYBdk09HDM7zzL657uHfzfOVrdslrTCj6p5mo -DzvCxLkkjIzYGnlPuqfNyGjozkpSWgSUc+X+EGLLl3WqEOVdWJtbM61fewEHlRTM5JzScvwrJ39t7o6 -CCAjKA0cBWBd6UWgbN/t53RoWvh9HrA2AW5YrT0ZiAgKe9y7EMUaENVJ8QJBAPhpdmb4ZL4Fkm4OKia -NEcjzn6mGTlZtef7K/0oRC9+2JkQnCuf6HBpaRhJoCJYg7DW8ZY+AV6xClKrgjBOfERMCQQDExhnzu2 -dsQ9k8QChBlpHO0TRbZBiQfC70oU31kM1AeLseZRmrxv9Yxzdl8D693NNWS2JbKOXl0kMHHcuGQLMVA -kBZ7WvkmPV3aPL6jnwp2pXepntdVnaTiSxJ1dkXShZ/VSSDNZMYKY306EtHrIu3NZHtXhdyHKcggDXr -qkBrdgErAkAlpGPojUwemOggr4FD8sLX1ot2hDJyyV7OK2FXfajWEYJyMRL1Gm9Uk1+Un53RAkJneqp -JGAzKpyttXBTIDO51AkEA98KTiROMnnU8Y6Mgcvr68/SMIsvCYMt9/mtwSBGgl80VaTQ5Hpaktl6Xbh -VUt5Wv0tRxlXZiViCGCD1EtrrwTw== -` diff --git a/p2p/peer/peerstore.go b/p2p/peer/peerstore.go deleted file mode 100644 index 6fdb87726c9..00000000000 --- a/p2p/peer/peerstore.go +++ /dev/null @@ -1,216 +0,0 @@ -package peer - -import ( - "errors" - "sync" - "time" - - ic "github.com/ipfs/go-ipfs/p2p/crypto" - - ds "github.com/ipfs/go-ipfs/Godeps/_workspace/src/github.com/ipfs/go-datastore" - dssync "github.com/ipfs/go-ipfs/Godeps/_workspace/src/github.com/ipfs/go-datastore/sync" - ma "github.com/ipfs/go-ipfs/Godeps/_workspace/src/github.com/jbenet/go-multiaddr" -) - -const ( - // AddressTTL is the expiration time of addresses. - AddressTTL = time.Hour -) - -// Peerstore provides a threadsafe store of Peer related -// information. -type Peerstore interface { - AddrBook - KeyBook - Metrics - - // Peers returns a list of all peer.IDs in this Peerstore - Peers() []ID - - // PeerInfo returns a peer.PeerInfo struct for given peer.ID. - // This is a small slice of the information Peerstore has on - // that peer, useful to other services. - PeerInfo(ID) PeerInfo - - // Get/Put is a simple registry for other peer-related key/value pairs. - // if we find something we use often, it should become its own set of - // methods. this is a last resort. - Get(id ID, key string) (interface{}, error) - Put(id ID, key string, val interface{}) error -} - -// AddrBook is an interface that fits the new AddrManager. I'm patching -// it up in here to avoid changing a ton of the codebase. -type AddrBook interface { - - // AddAddr calls AddAddrs(p, []ma.Multiaddr{addr}, ttl) - AddAddr(p ID, addr ma.Multiaddr, ttl time.Duration) - - // AddAddrs gives AddrManager addresses to use, with a given ttl - // (time-to-live), after which the address is no longer valid. - // If the manager has a longer TTL, the operation is a no-op for that address - AddAddrs(p ID, addrs []ma.Multiaddr, ttl time.Duration) - - // SetAddr calls mgr.SetAddrs(p, addr, ttl) - SetAddr(p ID, addr ma.Multiaddr, ttl time.Duration) - - // SetAddrs sets the ttl on addresses. This clears any TTL there previously. - // This is used when we receive the best estimate of the validity of an address. - SetAddrs(p ID, addrs []ma.Multiaddr, ttl time.Duration) - - // Addresses returns all known (and valid) addresses for a given - Addrs(p ID) []ma.Multiaddr - - // ClearAddresses removes all previously stored addresses - ClearAddrs(p ID) -} - -// KeyBook tracks the Public keys of Peers. -type KeyBook interface { - PubKey(ID) ic.PubKey - AddPubKey(ID, ic.PubKey) error - - PrivKey(ID) ic.PrivKey - AddPrivKey(ID, ic.PrivKey) error -} - -type keybook struct { - pks map[ID]ic.PubKey - sks map[ID]ic.PrivKey - - sync.RWMutex // same lock. wont happen a ton. -} - -func newKeybook() *keybook { - return &keybook{ - pks: map[ID]ic.PubKey{}, - sks: map[ID]ic.PrivKey{}, - } -} - -func (kb *keybook) Peers() []ID { - kb.RLock() - ps := make([]ID, 0, len(kb.pks)+len(kb.sks)) - for p := range kb.pks { - ps = append(ps, p) - } - for p := range kb.sks { - if _, found := kb.pks[p]; !found { - ps = append(ps, p) - } - } - kb.RUnlock() - return ps -} - -func (kb *keybook) PubKey(p ID) ic.PubKey { - kb.RLock() - pk := kb.pks[p] - kb.RUnlock() - return pk -} - -func (kb *keybook) AddPubKey(p ID, pk ic.PubKey) error { - - // check it's correct first - if !p.MatchesPublicKey(pk) { - return errors.New("ID does not match PublicKey") - } - - kb.Lock() - kb.pks[p] = pk - kb.Unlock() - return nil -} - -func (kb *keybook) PrivKey(p ID) ic.PrivKey { - kb.RLock() - sk := kb.sks[p] - kb.RUnlock() - return sk -} - -func (kb *keybook) AddPrivKey(p ID, sk ic.PrivKey) error { - - if sk == nil { - return errors.New("sk is nil (PrivKey)") - } - - // check it's correct first - if !p.MatchesPrivateKey(sk) { - return errors.New("ID does not match PrivateKey") - } - - kb.Lock() - kb.sks[p] = sk - kb.Unlock() - return nil -} - -type peerstore struct { - keybook - metrics - AddrManager - - // store other data, like versions - ds ds.ThreadSafeDatastore -} - -// NewPeerstore creates a threadsafe collection of peers. -func NewPeerstore() Peerstore { - return &peerstore{ - keybook: *newKeybook(), - metrics: *(NewMetrics()).(*metrics), - AddrManager: AddrManager{}, - ds: dssync.MutexWrap(ds.NewMapDatastore()), - } -} - -func (ps *peerstore) Put(p ID, key string, val interface{}) error { - dsk := ds.NewKey(string(p) + "/" + key) - return ps.ds.Put(dsk, val) -} - -func (ps *peerstore) Get(p ID, key string) (interface{}, error) { - dsk := ds.NewKey(string(p) + "/" + key) - return ps.ds.Get(dsk) -} - -func (ps *peerstore) Peers() []ID { - set := map[ID]struct{}{} - for _, p := range ps.keybook.Peers() { - set[p] = struct{}{} - } - for _, p := range ps.AddrManager.Peers() { - set[p] = struct{}{} - } - - pps := make([]ID, 0, len(set)) - for p := range set { - pps = append(pps, p) - } - return pps -} - -func (ps *peerstore) PeerInfo(p ID) PeerInfo { - return PeerInfo{ - ID: p, - Addrs: ps.AddrManager.Addrs(p), - } -} - -func PeerInfos(ps Peerstore, peers []ID) []PeerInfo { - pi := make([]PeerInfo, len(peers)) - for i, p := range peers { - pi[i] = ps.PeerInfo(p) - } - return pi -} - -func PeerInfoIDs(pis []PeerInfo) []ID { - ps := make([]ID, len(pis)) - for i, pi := range pis { - ps[i] = pi.ID - } - return ps -} diff --git a/p2p/peer/queue/distance.go b/p2p/peer/queue/distance.go deleted file mode 100644 index 2b3bce82d37..00000000000 --- a/p2p/peer/queue/distance.go +++ /dev/null @@ -1,101 +0,0 @@ -package queue - -import ( - "container/heap" - "math/big" - "sync" - - key "github.com/ipfs/go-ipfs/blocks/key" - peer "github.com/ipfs/go-ipfs/p2p/peer" - ks "github.com/ipfs/go-ipfs/routing/keyspace" -) - -// peerMetric tracks a peer and its distance to something else. -type peerMetric struct { - // the peer - peer peer.ID - - // big.Int for XOR metric - metric *big.Int -} - -// peerMetricHeap implements a heap of peerDistances -type peerMetricHeap []*peerMetric - -func (ph peerMetricHeap) Len() int { - return len(ph) -} - -func (ph peerMetricHeap) Less(i, j int) bool { - return -1 == ph[i].metric.Cmp(ph[j].metric) -} - -func (ph peerMetricHeap) Swap(i, j int) { - ph[i], ph[j] = ph[j], ph[i] -} - -func (ph *peerMetricHeap) Push(x interface{}) { - item := x.(*peerMetric) - *ph = append(*ph, item) -} - -func (ph *peerMetricHeap) Pop() interface{} { - old := *ph - n := len(old) - item := old[n-1] - *ph = old[0 : n-1] - return item -} - -// distancePQ implements heap.Interface and PeerQueue -type distancePQ struct { - // from is the Key this PQ measures against - from ks.Key - - // heap is a heap of peerDistance items - heap peerMetricHeap - - sync.RWMutex -} - -func (pq *distancePQ) Len() int { - pq.Lock() - defer pq.Unlock() - return len(pq.heap) -} - -func (pq *distancePQ) Enqueue(p peer.ID) { - pq.Lock() - defer pq.Unlock() - - distance := ks.XORKeySpace.Key([]byte(p)).Distance(pq.from) - - heap.Push(&pq.heap, &peerMetric{ - peer: p, - metric: distance, - }) -} - -func (pq *distancePQ) Dequeue() peer.ID { - pq.Lock() - defer pq.Unlock() - - if len(pq.heap) < 1 { - panic("called Dequeue on an empty PeerQueue") - // will panic internally anyway, but we can help debug here - } - - o := heap.Pop(&pq.heap) - p := o.(*peerMetric) - return p.peer -} - -// NewXORDistancePQ returns a PeerQueue which maintains its peers sorted -// in terms of their distances to each other in an XORKeySpace (i.e. using -// XOR as a metric of distance). -func NewXORDistancePQ(fromKey key.Key) PeerQueue { - return &distancePQ{ - from: ks.XORKeySpace.Key([]byte(fromKey)), - heap: peerMetricHeap{}, - } -} diff --git a/p2p/peer/queue/interface.go b/p2p/peer/queue/interface.go deleted file mode 100644 index 6b0f8c5c9ea..00000000000 --- a/p2p/peer/queue/interface.go +++ /dev/null @@ -1,18 +0,0 @@ -package queue - -import peer "github.com/ipfs/go-ipfs/p2p/peer" - -// PeerQueue maintains a set of peers ordered according to a metric. -// Implementations of PeerQueue could order peers based on distances along -// a KeySpace, latency measurements, trustworthiness, reputation, etc. -type PeerQueue interface { - - // Len returns the number of items in PeerQueue - Len() int - - // Enqueue adds this node to the queue. - Enqueue(peer.ID) - - // Dequeue retrieves the highest (smallest int) priority node - Dequeue() peer.ID -} diff --git a/p2p/peer/queue/queue_test.go b/p2p/peer/queue/queue_test.go deleted file mode 100644 index c303550a92b..00000000000 --- a/p2p/peer/queue/queue_test.go +++ /dev/null @@ -1,141 +0,0 @@ -package queue - -import ( - "fmt" - "sync" - "testing" - "time" - - key "github.com/ipfs/go-ipfs/blocks/key" - peer "github.com/ipfs/go-ipfs/p2p/peer" - u "github.com/ipfs/go-ipfs/util" - - context "github.com/ipfs/go-ipfs/Godeps/_workspace/src/golang.org/x/net/context" -) - -func TestQueue(t *testing.T) { - - p1 := peer.ID("11140beec7b5ea3f0fdbc95d0dd47f3c5bc275da8a31") // these aren't valid, because need to hex-decode. - p2 := peer.ID("11140beec7b5ea3f0fdbc95d0dd47f3c5bc275da8a32") // these aren't valid, because need to hex-decode. - p3 := peer.ID("11140beec7b5ea3f0fdbc95d0dd47f3c5bc275da8a33") // these aren't valid, because need to hex-decode. - p4 := peer.ID("11140beec7b5ea3f0fdbc95d0dd47f3c5bc275da8a34") // these aren't valid, because need to hex-decode. - p5 := peer.ID("11140beec7b5ea3f0fdbc95d0dd47f3c5bc275da8a31") // these aren't valid, because need to hex-decode. - // but they work. - - // these are the peer.IDs' XORKeySpace Key values: - // [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] - // [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] - // [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] - // [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] - - pq := NewXORDistancePQ(key.Key("11140beec7b5ea3f0fdbc95d0dd47f3c5bc275da8a31")) - pq.Enqueue(p3) - pq.Enqueue(p1) - pq.Enqueue(p2) - pq.Enqueue(p4) - pq.Enqueue(p5) - pq.Enqueue(p1) - - // should come out as: p1, p4, p3, p2 - - if d := pq.Dequeue(); d != p1 && d != p5 { - t.Error("ordering failed") - } - - if d := pq.Dequeue(); d != p1 && d != p5 { - t.Error("ordering failed") - } - - if d := pq.Dequeue(); d != p1 && d != p5 { - t.Error("ordering failed") - } - - if pq.Dequeue() != p4 { - t.Error("ordering failed") - } - - if pq.Dequeue() != p3 { - t.Error("ordering failed") - } - - if pq.Dequeue() != p2 { - t.Error("ordering failed") - } - -} - -func newPeerTime(t time.Time) peer.ID { - s := fmt.Sprintf("hmmm time: %v", t) - h := u.Hash([]byte(s)) - return peer.ID(h) -} - -func TestSyncQueue(t *testing.T) { - tickT := time.Microsecond * 50 - max := 5000 - consumerN := 10 - countsIn := make([]int, consumerN*2) - countsOut := make([]int, consumerN) - - if testing.Short() { - max = 1000 - } - - ctx := context.Background() - pq := NewXORDistancePQ(key.Key("11140beec7b5ea3f0fdbc95d0dd47f3c5bc275da8a31")) - cq := NewChanQueue(ctx, pq) - wg := sync.WaitGroup{} - - produce := func(p int) { - defer wg.Done() - - tick := time.Tick(tickT) - for i := 0; i < max; i++ { - select { - case tim := <-tick: - countsIn[p]++ - cq.EnqChan <- newPeerTime(tim) - case <-ctx.Done(): - return - } - } - } - - consume := func(c int) { - defer wg.Done() - - for { - select { - case <-cq.DeqChan: - countsOut[c]++ - if countsOut[c] >= max*2 { - return - } - case <-ctx.Done(): - return - } - } - } - - // make n * 2 producers and n consumers - for i := 0; i < consumerN; i++ { - wg.Add(3) - go produce(i) - go produce(consumerN + i) - go consume(i) - } - - wg.Wait() - - sum := func(ns []int) int { - total := 0 - for _, n := range ns { - total += n - } - return total - } - - if sum(countsIn) != sum(countsOut) { - t.Errorf("didnt get all of them out: %d/%d", sum(countsOut), sum(countsIn)) - } -} diff --git a/p2p/peer/queue/sync.go b/p2p/peer/queue/sync.go deleted file mode 100644 index da7377a5a95..00000000000 --- a/p2p/peer/queue/sync.go +++ /dev/null @@ -1,84 +0,0 @@ -package queue - -import ( - context "github.com/ipfs/go-ipfs/Godeps/_workspace/src/golang.org/x/net/context" - peer "github.com/ipfs/go-ipfs/p2p/peer" - logging "github.com/ipfs/go-ipfs/vendor/QmQg1J6vikuXF9oDvm4wpdeAUvvkVEKW1EYDw9HhTMnP2b/go-log" -) - -var log = logging.Logger("peerqueue") - -// ChanQueue makes any PeerQueue synchronizable through channels. -type ChanQueue struct { - Queue PeerQueue - EnqChan chan<- peer.ID - DeqChan <-chan peer.ID -} - -// NewChanQueue creates a ChanQueue by wrapping pq. -func NewChanQueue(ctx context.Context, pq PeerQueue) *ChanQueue { - cq := &ChanQueue{Queue: pq} - cq.process(ctx) - return cq -} - -func (cq *ChanQueue) process(ctx context.Context) { - // construct the channels here to be able to use them bidirectionally - enqChan := make(chan peer.ID) - deqChan := make(chan peer.ID) - - cq.EnqChan = enqChan - cq.DeqChan = deqChan - - go func() { - log.Debug("processing") - defer log.Debug("closed") - defer close(deqChan) - - var next peer.ID - var item peer.ID - var more bool - - for { - if cq.Queue.Len() == 0 { - // log.Debug("wait for enqueue") - select { - case next, more = <-enqChan: - if !more { - return - } - // log.Debug("got", next) - - case <-ctx.Done(): - return - } - - } else { - next = cq.Queue.Dequeue() - // log.Debug("peek", next) - } - - select { - case item, more = <-enqChan: - if !more { - if cq.Queue.Len() > 0 { - return // we're done done. - } - enqChan = nil // closed, so no use. - } - // log.Debug("got", item) - cq.Queue.Enqueue(item) - cq.Queue.Enqueue(next) // order may have changed. - next = "" - - case deqChan <- next: - // log.Debug("dequeued", next) - next = "" - - case <-ctx.Done(): - return - } - } - - }() -} diff --git a/p2p/protocol/identify/id.go b/p2p/protocol/identify/id.go deleted file mode 100644 index a8408b61de5..00000000000 --- a/p2p/protocol/identify/id.go +++ /dev/null @@ -1,334 +0,0 @@ -package identify - -import ( - "strings" - "sync" - - semver "github.com/ipfs/go-ipfs/Godeps/_workspace/src/github.com/coreos/go-semver/semver" - ggio "github.com/ipfs/go-ipfs/Godeps/_workspace/src/github.com/gogo/protobuf/io" - ma "github.com/ipfs/go-ipfs/Godeps/_workspace/src/github.com/jbenet/go-multiaddr" - msmux "github.com/ipfs/go-ipfs/Godeps/_workspace/src/github.com/whyrusleeping/go-multistream" - context "github.com/ipfs/go-ipfs/Godeps/_workspace/src/golang.org/x/net/context" - - mstream "github.com/ipfs/go-ipfs/metrics/stream" - host "github.com/ipfs/go-ipfs/p2p/host" - inet "github.com/ipfs/go-ipfs/p2p/net" - peer "github.com/ipfs/go-ipfs/p2p/peer" - pb "github.com/ipfs/go-ipfs/p2p/protocol/identify/pb" - config "github.com/ipfs/go-ipfs/repo/config" - lgbl "github.com/ipfs/go-ipfs/util/eventlog/loggables" - logging "github.com/ipfs/go-ipfs/vendor/QmQg1J6vikuXF9oDvm4wpdeAUvvkVEKW1EYDw9HhTMnP2b/go-log" -) - -var log = logging.Logger("net/identify") - -// ID is the protocol.ID of the Identify Service. -const ID = "/ipfs/identify" - -// IpfsVersion holds the current protocol version for a client running this code -// TODO(jbenet): fix the versioning mess. -const IpfsVersion = "ipfs/0.1.0" -const ClientVersion = "go-ipfs/" + config.CurrentVersionNumber - -// IDService is a structure that implements ProtocolIdentify. -// It is a trivial service that gives the other peer some -// useful information about the local peer. A sort of hello. -// -// The IDService sends: -// * Our IPFS Protocol Version -// * Our IPFS Agent Version -// * Our public Listen Addresses -type IDService struct { - Host host.Host - - // connections undergoing identification - // for wait purposes - currid map[inet.Conn]chan struct{} - currmu sync.RWMutex - - // our own observed addresses. - // TODO: instead of expiring, remove these when we disconnect - observedAddrs ObservedAddrSet -} - -func NewIDService(h host.Host) *IDService { - s := &IDService{ - Host: h, - currid: make(map[inet.Conn]chan struct{}), - } - h.SetStreamHandler(ID, s.RequestHandler) - return s -} - -// OwnObservedAddrs returns the addresses peers have reported we've dialed from -func (ids *IDService) OwnObservedAddrs() []ma.Multiaddr { - return ids.observedAddrs.Addrs() -} - -func (ids *IDService) IdentifyConn(c inet.Conn) { - ids.currmu.Lock() - if wait, found := ids.currid[c]; found { - ids.currmu.Unlock() - log.Debugf("IdentifyConn called twice on: %s", c) - <-wait // already identifying it. wait for it. - return - } - ids.currid[c] = make(chan struct{}) - ids.currmu.Unlock() - - s, err := c.NewStream() - if err != nil { - log.Debugf("error opening initial stream for %s", ID) - log.Event(context.TODO(), "IdentifyOpenFailed", c.RemotePeer()) - c.Close() - return - } else { - bwc := ids.Host.GetBandwidthReporter() - s = mstream.WrapStream(s, ID, bwc) - - // ok give the response to our handler. - if err := msmux.SelectProtoOrFail(ID, s); err != nil { - log.Debugf("error writing stream header for %s", ID) - log.Event(context.TODO(), "IdentifyOpenFailed", c.RemotePeer()) - s.Close() - return - } else { - ids.ResponseHandler(s) - } - } - - ids.currmu.Lock() - ch, found := ids.currid[c] - delete(ids.currid, c) - ids.currmu.Unlock() - - if !found { - log.Debugf("IdentifyConn failed to find channel (programmer error) for %s", c) - return - } - - close(ch) // release everyone waiting. -} - -func (ids *IDService) RequestHandler(s inet.Stream) { - defer s.Close() - c := s.Conn() - - bwc := ids.Host.GetBandwidthReporter() - s = mstream.WrapStream(s, ID, bwc) - - w := ggio.NewDelimitedWriter(s) - mes := pb.Identify{} - ids.populateMessage(&mes, s.Conn()) - w.WriteMsg(&mes) - - log.Debugf("%s sent message to %s %s", ID, - c.RemotePeer(), c.RemoteMultiaddr()) -} - -func (ids *IDService) ResponseHandler(s inet.Stream) { - defer s.Close() - c := s.Conn() - - r := ggio.NewDelimitedReader(s, 2048) - mes := pb.Identify{} - if err := r.ReadMsg(&mes); err != nil { - return - } - ids.consumeMessage(&mes, c) - - log.Debugf("%s received message from %s %s", ID, - c.RemotePeer(), c.RemoteMultiaddr()) -} - -func (ids *IDService) populateMessage(mes *pb.Identify, c inet.Conn) { - - // set protocols this node is currently handling - protos := ids.Host.Mux().Protocols() - mes.Protocols = make([]string, len(protos)) - for i, p := range protos { - mes.Protocols[i] = string(p) - } - - // observed address so other side is informed of their - // "public" address, at least in relation to us. - mes.ObservedAddr = c.RemoteMultiaddr().Bytes() - - // set listen addrs, get our latest addrs from Host. - laddrs := ids.Host.Addrs() - mes.ListenAddrs = make([][]byte, len(laddrs)) - for i, addr := range laddrs { - mes.ListenAddrs[i] = addr.Bytes() - } - log.Debugf("%s sent listen addrs to %s: %s", c.LocalPeer(), c.RemotePeer(), laddrs) - - // set protocol versions - pv := IpfsVersion - av := ClientVersion - mes.ProtocolVersion = &pv - mes.AgentVersion = &av -} - -func (ids *IDService) consumeMessage(mes *pb.Identify, c inet.Conn) { - p := c.RemotePeer() - - // mes.Protocols - - // mes.ObservedAddr - ids.consumeObservedAddress(mes.GetObservedAddr(), c) - - // mes.ListenAddrs - laddrs := mes.GetListenAddrs() - lmaddrs := make([]ma.Multiaddr, 0, len(laddrs)) - for _, addr := range laddrs { - maddr, err := ma.NewMultiaddrBytes(addr) - if err != nil { - log.Debugf("%s failed to parse multiaddr from %s %s", ID, - p, c.RemoteMultiaddr()) - continue - } - lmaddrs = append(lmaddrs, maddr) - } - - // update our peerstore with the addresses. here, we SET the addresses, clearing old ones. - // We are receiving from the peer itself. this is current address ground truth. - ids.Host.Peerstore().SetAddrs(p, lmaddrs, peer.ConnectedAddrTTL) - log.Debugf("%s received listen addrs for %s: %s", c.LocalPeer(), c.RemotePeer(), lmaddrs) - - // get protocol versions - pv := mes.GetProtocolVersion() - av := mes.GetAgentVersion() - - // version check. if we shouldn't talk, bail. - // TODO: at this point, we've already exchanged information. - // move this into a first handshake before the connection can open streams. - if !protocolVersionsAreCompatible(pv, IpfsVersion) { - logProtocolMismatchDisconnect(c, pv, av) - c.Close() - return - } - - ids.Host.Peerstore().Put(p, "ProtocolVersion", pv) - ids.Host.Peerstore().Put(p, "AgentVersion", av) -} - -// IdentifyWait returns a channel which will be closed once -// "ProtocolIdentify" (handshake3) finishes on given conn. -// This happens async so the connection can start to be used -// even if handshake3 knowledge is not necesary. -// Users **MUST** call IdentifyWait _after_ IdentifyConn -func (ids *IDService) IdentifyWait(c inet.Conn) <-chan struct{} { - ids.currmu.Lock() - ch, found := ids.currid[c] - ids.currmu.Unlock() - if found { - return ch - } - - // if not found, it means we are already done identifying it, or - // haven't even started. either way, return a new channel closed. - ch = make(chan struct{}) - close(ch) - return ch -} - -func (ids *IDService) consumeObservedAddress(observed []byte, c inet.Conn) { - if observed == nil { - return - } - - maddr, err := ma.NewMultiaddrBytes(observed) - if err != nil { - log.Debugf("error parsing received observed addr for %s: %s", c, err) - return - } - - // we should only use ObservedAddr when our connection's LocalAddr is one - // of our ListenAddrs. If we Dial out using an ephemeral addr, knowing that - // address's external mapping is not very useful because the port will not be - // the same as the listen addr. - ifaceaddrs, err := ids.Host.Network().InterfaceListenAddresses() - if err != nil { - log.Infof("failed to get interface listen addrs", err) - return - } - - log.Debugf("identify identifying observed multiaddr: %s %s", c.LocalMultiaddr(), ifaceaddrs) - if !addrInAddrs(c.LocalMultiaddr(), ifaceaddrs) { - // not in our list - return - } - - // ok! we have the observed version of one of our ListenAddresses! - log.Debugf("added own observed listen addr: %s --> %s", c.LocalMultiaddr(), maddr) - ids.observedAddrs.Add(maddr, c.RemoteMultiaddr()) -} - -func addrInAddrs(a ma.Multiaddr, as []ma.Multiaddr) bool { - for _, b := range as { - if a.Equal(b) { - return true - } - } - return false -} - -// protocolVersionsAreCompatible checks that the two implementations -// can talk to each other. It will use semver, but for now while -// we're in tight development, we will return false for minor version -// changes too. -func protocolVersionsAreCompatible(v1, v2 string) bool { - if strings.HasPrefix(v1, "ipfs/") { - v1 = v1[5:] - } - if strings.HasPrefix(v2, "ipfs/") { - v2 = v2[5:] - } - - v1s, err := semver.NewVersion(v1) - if err != nil { - return false - } - - v2s, err := semver.NewVersion(v2) - if err != nil { - return false - } - - return v1s.Major == v2s.Major && v1s.Minor == v2s.Minor -} - -// netNotifiee defines methods to be used with the IpfsDHT -type netNotifiee IDService - -func (nn *netNotifiee) IDService() *IDService { - return (*IDService)(nn) -} - -func (nn *netNotifiee) Connected(n inet.Network, v inet.Conn) { - // TODO: deprecate the setConnHandler hook, and kick off - // identification here. -} - -func (nn *netNotifiee) Disconnected(n inet.Network, v inet.Conn) { - // undo the setting of addresses to peer.ConnectedAddrTTL we did - ids := nn.IDService() - ps := ids.Host.Peerstore() - addrs := ps.Addrs(v.RemotePeer()) - ps.SetAddrs(v.RemotePeer(), addrs, peer.RecentlyConnectedAddrTTL) -} - -func (nn *netNotifiee) OpenedStream(n inet.Network, v inet.Stream) {} -func (nn *netNotifiee) ClosedStream(n inet.Network, v inet.Stream) {} -func (nn *netNotifiee) Listen(n inet.Network, a ma.Multiaddr) {} -func (nn *netNotifiee) ListenClose(n inet.Network, a ma.Multiaddr) {} - -func logProtocolMismatchDisconnect(c inet.Conn, protocol, agent string) { - lm := make(lgbl.DeferredMap) - lm["remotePeer"] = func() interface{} { return c.RemotePeer().Pretty() } - lm["remoteAddr"] = func() interface{} { return c.RemoteMultiaddr().String() } - lm["protocolVersion"] = protocol - lm["agentVersion"] = agent - log.Event(context.TODO(), "IdentifyProtocolMismatch", lm) - log.Debug("IdentifyProtocolMismatch %s %s %s (disconnected)", c.RemotePeer(), protocol, agent) -} diff --git a/p2p/protocol/identify/id_test.go b/p2p/protocol/identify/id_test.go deleted file mode 100644 index 5669a5e6cef..00000000000 --- a/p2p/protocol/identify/id_test.go +++ /dev/null @@ -1,106 +0,0 @@ -package identify_test - -import ( - "testing" - "time" - - host "github.com/ipfs/go-ipfs/p2p/host" - peer "github.com/ipfs/go-ipfs/p2p/peer" - identify "github.com/ipfs/go-ipfs/p2p/protocol/identify" - testutil "github.com/ipfs/go-ipfs/p2p/test/util" - - ma "github.com/ipfs/go-ipfs/Godeps/_workspace/src/github.com/jbenet/go-multiaddr" - context "github.com/ipfs/go-ipfs/Godeps/_workspace/src/golang.org/x/net/context" -) - -func subtestIDService(t *testing.T, postDialWait time.Duration) { - - // the generated networks should have the id service wired in. - ctx := context.Background() - h1 := testutil.GenHostSwarm(t, ctx) - h2 := testutil.GenHostSwarm(t, ctx) - - h1p := h1.ID() - h2p := h2.ID() - - testKnowsAddrs(t, h1, h2p, []ma.Multiaddr{}) // nothing - testKnowsAddrs(t, h2, h1p, []ma.Multiaddr{}) // nothing - - h2pi := h2.Peerstore().PeerInfo(h2p) - if err := h1.Connect(ctx, h2pi); err != nil { - t.Fatal(err) - } - - // we need to wait here if Dial returns before ID service is finished. - if postDialWait > 0 { - <-time.After(postDialWait) - } - - // the IDService should be opened automatically, by the network. - // what we should see now is that both peers know about each others listen addresses. - testKnowsAddrs(t, h1, h2p, h2.Peerstore().Addrs(h2p)) // has them - testHasProtocolVersions(t, h1, h2p) - - // now, this wait we do have to do. it's the wait for the Listening side - // to be done identifying the connection. - c := h2.Network().ConnsToPeer(h1.ID()) - if len(c) < 1 { - t.Fatal("should have connection by now at least.") - } - <-h2.IDService().IdentifyWait(c[0]) - - // and the protocol versions. - testKnowsAddrs(t, h2, h1p, h1.Peerstore().Addrs(h1p)) // has them - testHasProtocolVersions(t, h2, h1p) -} - -func testKnowsAddrs(t *testing.T, h host.Host, p peer.ID, expected []ma.Multiaddr) { - actual := h.Peerstore().Addrs(p) - - if len(actual) != len(expected) { - t.Error("dont have the same addresses") - } - - have := map[string]struct{}{} - for _, addr := range actual { - have[addr.String()] = struct{}{} - } - for _, addr := range expected { - if _, found := have[addr.String()]; !found { - t.Errorf("%s did not have addr for %s: %s", h.ID(), p, addr) - // panic("ahhhhhhh") - } - } -} - -func testHasProtocolVersions(t *testing.T, h host.Host, p peer.ID) { - v, err := h.Peerstore().Get(p, "ProtocolVersion") - if v == nil { - t.Error("no protocol version") - return - } - if v.(string) != identify.IpfsVersion { - t.Error("protocol mismatch", err) - } - v, err = h.Peerstore().Get(p, "AgentVersion") - if v.(string) != identify.ClientVersion { - t.Error("agent version mismatch", err) - } -} - -// TestIDServiceWait gives the ID service 100ms to finish after dialing -// this is becasue it used to be concurrent. Now, Dial wait till the -// id service is done. -func TestIDServiceWait(t *testing.T) { - N := 3 - for i := 0; i < N; i++ { - subtestIDService(t, 100*time.Millisecond) - } -} - -func TestIDServiceNoWait(t *testing.T) { - N := 3 - for i := 0; i < N; i++ { - subtestIDService(t, 0) - } -} diff --git a/p2p/protocol/identify/obsaddr.go b/p2p/protocol/identify/obsaddr.go deleted file mode 100644 index f4033949b9a..00000000000 --- a/p2p/protocol/identify/obsaddr.go +++ /dev/null @@ -1,121 +0,0 @@ -package identify - -import ( - "sync" - "time" - - peer "github.com/ipfs/go-ipfs/p2p/peer" - - ma "github.com/ipfs/go-ipfs/Godeps/_workspace/src/github.com/jbenet/go-multiaddr" -) - -// ObservedAddr is an entry for an address reported by our peers. -// We only use addresses that: -// - have been observed more than once. (counter symmetric nats) -// - have been observed recently (10min), because our position in the -// network, or network port mapppings, may have changed. -type ObservedAddr struct { - Addr ma.Multiaddr - SeenBy map[string]struct{} - LastSeen time.Time -} - -// ObservedAddrSet keeps track of a set of ObservedAddrs -// the zero-value is ready to be used. -type ObservedAddrSet struct { - sync.Mutex // guards whole datastruct. - - addrs map[string]*ObservedAddr - ttl time.Duration -} - -func (oas *ObservedAddrSet) Addrs() []ma.Multiaddr { - oas.Lock() - defer oas.Unlock() - - // for zero-value. - if oas.addrs == nil { - return nil - } - - now := time.Now() - addrs := make([]ma.Multiaddr, 0, len(oas.addrs)) - for s, a := range oas.addrs { - // remove timed out addresses. - if now.Sub(a.LastSeen) > oas.ttl { - delete(oas.addrs, s) - continue - } - - // we only use an address if we've seen it more than once - // because symmetric nats may cause all our peers to see - // different port numbers and thus report always different - // addresses (different ports) for us. These wouldn't be - // very useful. We make the assumption that if we've - // connected to two different peers, and they both have - // reported seeing the same address, it is probably useful. - // - // Note: make sure not to double count observers. - if len(a.SeenBy) > 1 { - addrs = append(addrs, a.Addr) - } - } - return addrs -} - -func (oas *ObservedAddrSet) Add(addr ma.Multiaddr, observer ma.Multiaddr) { - oas.Lock() - defer oas.Unlock() - - // for zero-value. - if oas.addrs == nil { - oas.addrs = make(map[string]*ObservedAddr) - oas.ttl = peer.OwnObservedAddrTTL - } - - s := addr.String() - oa, found := oas.addrs[s] - - // first time seeing address. - if !found { - oa = &ObservedAddr{ - Addr: addr, - SeenBy: make(map[string]struct{}), - } - oas.addrs[s] = oa - } - - // mark the observer - oa.SeenBy[observerGroup(observer)] = struct{}{} - oa.LastSeen = time.Now() -} - -// observerGroup is a function that determines what part of -// a multiaddr counts as a different observer. for example, -// two ipfs nodes at the same IP/TCP transport would get -// the exact same NAT mapping; they would count as the -// same observer. This may protect against NATs who assign -// different ports to addresses at different IP hosts, but -// not TCP ports. -// -// Here, we use the root multiaddr address. This is mostly -// IP addresses. In practice, this is what we want. -func observerGroup(m ma.Multiaddr) string { - return ma.Split(m)[0].String() -} - -func (oas *ObservedAddrSet) SetTTL(ttl time.Duration) { - oas.Lock() - defer oas.Unlock() - oas.ttl = ttl -} - -func (oas *ObservedAddrSet) TTL() time.Duration { - oas.Lock() - defer oas.Unlock() - // for zero-value. - if oas.addrs == nil { - oas.ttl = peer.OwnObservedAddrTTL - } - return oas.ttl -} diff --git a/p2p/protocol/identify/obsaddr_test.go b/p2p/protocol/identify/obsaddr_test.go deleted file mode 100644 index dba76959406..00000000000 --- a/p2p/protocol/identify/obsaddr_test.go +++ /dev/null @@ -1,99 +0,0 @@ -package identify - -import ( - "testing" - "time" - - ma "github.com/ipfs/go-ipfs/Godeps/_workspace/src/github.com/jbenet/go-multiaddr" -) - -// TestObsAddrSet -func TestObsAddrSet(t *testing.T) { - m := func(s string) ma.Multiaddr { - m, err := ma.NewMultiaddr(s) - if err != nil { - t.Error(err) - } - return m - } - - addrsMarch := func(a, b []ma.Multiaddr) bool { - for _, aa := range a { - found := false - for _, bb := range b { - if aa.Equal(bb) { - found = true - break - } - } - if !found { - return false - } - } - return true - } - - a1 := m("/ip4/1.2.3.4/tcp/1231") - a2 := m("/ip4/1.2.3.4/tcp/1232") - a3 := m("/ip4/1.2.3.4/tcp/1233") - a4 := m("/ip4/1.2.3.4/tcp/1234") - a5 := m("/ip4/1.2.3.4/tcp/1235") - a6 := m("/ip4/1.2.3.6/tcp/1236") - a7 := m("/ip4/1.2.3.7/tcp/1237") - - oas := ObservedAddrSet{} - - if !addrsMarch(oas.Addrs(), nil) { - t.Error("addrs should be empty") - } - - oas.Add(a1, a4) - oas.Add(a2, a4) - oas.Add(a3, a4) - - // these are all different so we should not yet get them. - if !addrsMarch(oas.Addrs(), nil) { - t.Error("addrs should _still_ be empty (once)") - } - - // same observer, so should not yet get them. - oas.Add(a1, a4) - oas.Add(a2, a4) - oas.Add(a3, a4) - if !addrsMarch(oas.Addrs(), nil) { - t.Error("addrs should _still_ be empty (same obs)") - } - - // different observer, but same observer group. - oas.Add(a1, a5) - oas.Add(a2, a5) - oas.Add(a3, a5) - if !addrsMarch(oas.Addrs(), nil) { - t.Error("addrs should _still_ be empty (same obs group)") - } - - oas.Add(a1, a6) - if !addrsMarch(oas.Addrs(), []ma.Multiaddr{a1}) { - t.Error("addrs should only have a1") - } - - oas.Add(a2, a5) - oas.Add(a1, a5) - oas.Add(a1, a5) - oas.Add(a2, a6) - oas.Add(a1, a6) - oas.Add(a1, a6) - oas.Add(a2, a7) - oas.Add(a1, a7) - oas.Add(a1, a7) - if !addrsMarch(oas.Addrs(), []ma.Multiaddr{a1, a2}) { - t.Error("addrs should only have a1, a2") - } - - // change the timeout constant so we can time it out. - oas.SetTTL(time.Millisecond * 200) - <-time.After(time.Millisecond * 210) - if !addrsMarch(oas.Addrs(), []ma.Multiaddr{nil}) { - t.Error("addrs should have timed out") - } -} diff --git a/p2p/protocol/identify/pb/Makefile b/p2p/protocol/identify/pb/Makefile deleted file mode 100644 index d08f1c3ebbe..00000000000 --- a/p2p/protocol/identify/pb/Makefile +++ /dev/null @@ -1,11 +0,0 @@ - -PB = $(wildcard *.proto) -GO = $(PB:.proto=.pb.go) - -all: $(GO) - -%.pb.go: %.proto - protoc --gogo_out=. --proto_path=../../../../../../:/usr/local/opt/protobuf/include:. $< - -clean: - rm *.pb.go diff --git a/p2p/protocol/identify/pb/identify.pb.go b/p2p/protocol/identify/pb/identify.pb.go deleted file mode 100644 index 861437f1192..00000000000 --- a/p2p/protocol/identify/pb/identify.pb.go +++ /dev/null @@ -1,91 +0,0 @@ -// Code generated by protoc-gen-gogo. -// source: identify.proto -// DO NOT EDIT! - -/* -Package identify_pb is a generated protocol buffer package. - -It is generated from these files: - identify.proto - -It has these top-level messages: - Identify -*/ -package identify_pb - -import proto "github.com/ipfs/go-ipfs/Godeps/_workspace/src/github.com/gogo/protobuf/proto" -import math "math" - -// Reference imports to suppress errors if they are not otherwise used. -var _ = proto.Marshal -var _ = math.Inf - -type Identify struct { - // protocolVersion determines compatibility between peers - ProtocolVersion *string `protobuf:"bytes,5,opt,name=protocolVersion" json:"protocolVersion,omitempty"` - // agentVersion is like a UserAgent string in browsers, or client version in bittorrent - // includes the client name and client. - AgentVersion *string `protobuf:"bytes,6,opt,name=agentVersion" json:"agentVersion,omitempty"` - // publicKey is this node's public key (which also gives its node.ID) - // - may not need to be sent, as secure channel implies it has been sent. - // - then again, if we change / disable secure channel, may still want it. - PublicKey []byte `protobuf:"bytes,1,opt,name=publicKey" json:"publicKey,omitempty"` - // listenAddrs are the multiaddrs the sender node listens for open connections on - ListenAddrs [][]byte `protobuf:"bytes,2,rep,name=listenAddrs" json:"listenAddrs,omitempty"` - // oservedAddr is the multiaddr of the remote endpoint that the sender node perceives - // this is useful information to convey to the other side, as it helps the remote endpoint - // determine whether its connection to the local peer goes through NAT. - ObservedAddr []byte `protobuf:"bytes,4,opt,name=observedAddr" json:"observedAddr,omitempty"` - // protocols are the services this node is running - Protocols []string `protobuf:"bytes,3,rep,name=protocols" json:"protocols,omitempty"` - XXX_unrecognized []byte `json:"-"` -} - -func (m *Identify) Reset() { *m = Identify{} } -func (m *Identify) String() string { return proto.CompactTextString(m) } -func (*Identify) ProtoMessage() {} - -func (m *Identify) GetProtocolVersion() string { - if m != nil && m.ProtocolVersion != nil { - return *m.ProtocolVersion - } - return "" -} - -func (m *Identify) GetAgentVersion() string { - if m != nil && m.AgentVersion != nil { - return *m.AgentVersion - } - return "" -} - -func (m *Identify) GetPublicKey() []byte { - if m != nil { - return m.PublicKey - } - return nil -} - -func (m *Identify) GetListenAddrs() [][]byte { - if m != nil { - return m.ListenAddrs - } - return nil -} - -func (m *Identify) GetObservedAddr() []byte { - if m != nil { - return m.ObservedAddr - } - return nil -} - -func (m *Identify) GetProtocols() []string { - if m != nil { - return m.Protocols - } - return nil -} - -func init() { -} diff --git a/p2p/protocol/identify/pb/identify.proto b/p2p/protocol/identify/pb/identify.proto deleted file mode 100644 index 7d31e0474a9..00000000000 --- a/p2p/protocol/identify/pb/identify.proto +++ /dev/null @@ -1,27 +0,0 @@ -package identify.pb; - -message Identify { - - // protocolVersion determines compatibility between peers - optional string protocolVersion = 5; // e.g. ipfs/1.0.0 - - // agentVersion is like a UserAgent string in browsers, or client version in bittorrent - // includes the client name and client. - optional string agentVersion = 6; // e.g. go-ipfs/0.1.0 - - // publicKey is this node's public key (which also gives its node.ID) - // - may not need to be sent, as secure channel implies it has been sent. - // - then again, if we change / disable secure channel, may still want it. - optional bytes publicKey = 1; - - // listenAddrs are the multiaddrs the sender node listens for open connections on - repeated bytes listenAddrs = 2; - - // oservedAddr is the multiaddr of the remote endpoint that the sender node perceives - // this is useful information to convey to the other side, as it helps the remote endpoint - // determine whether its connection to the local peer goes through NAT. - optional bytes observedAddr = 4; - - // protocols are the services this node is running - repeated string protocols = 3; -} diff --git a/p2p/protocol/ping/ping.go b/p2p/protocol/ping/ping.go deleted file mode 100644 index c5e5a8a1293..00000000000 --- a/p2p/protocol/ping/ping.go +++ /dev/null @@ -1,105 +0,0 @@ -package ping - -import ( - "bytes" - "errors" - "io" - "time" - - context "github.com/ipfs/go-ipfs/Godeps/_workspace/src/golang.org/x/net/context" - - host "github.com/ipfs/go-ipfs/p2p/host" - inet "github.com/ipfs/go-ipfs/p2p/net" - peer "github.com/ipfs/go-ipfs/p2p/peer" - u "github.com/ipfs/go-ipfs/util" - logging "github.com/ipfs/go-ipfs/vendor/QmQg1J6vikuXF9oDvm4wpdeAUvvkVEKW1EYDw9HhTMnP2b/go-log" -) - -var log = logging.Logger("ping") - -const PingSize = 32 - -const ID = "/ipfs/ping" - -type PingService struct { - Host host.Host -} - -func NewPingService(h host.Host) *PingService { - ps := &PingService{h} - h.SetStreamHandler(ID, ps.PingHandler) - return ps -} - -func (p *PingService) PingHandler(s inet.Stream) { - buf := make([]byte, PingSize) - - for { - _, err := io.ReadFull(s, buf) - if err != nil { - log.Debug(err) - return - } - - _, err = s.Write(buf) - if err != nil { - log.Debug(err) - return - } - } -} - -func (ps *PingService) Ping(ctx context.Context, p peer.ID) (<-chan time.Duration, error) { - s, err := ps.Host.NewStream(ID, p) - if err != nil { - return nil, err - } - - out := make(chan time.Duration) - go func() { - defer close(out) - for { - select { - case <-ctx.Done(): - return - default: - t, err := ping(s) - if err != nil { - log.Debugf("ping error: %s", err) - return - } - - select { - case out <- t: - case <-ctx.Done(): - return - } - } - } - }() - - return out, nil -} - -func ping(s inet.Stream) (time.Duration, error) { - buf := make([]byte, PingSize) - u.NewTimeSeededRand().Read(buf) - - before := time.Now() - _, err := s.Write(buf) - if err != nil { - return 0, err - } - - rbuf := make([]byte, PingSize) - _, err = io.ReadFull(s, rbuf) - if err != nil { - return 0, err - } - - if !bytes.Equal(buf, rbuf) { - return 0, errors.New("ping packet was incorrect!") - } - - return time.Now().Sub(before), nil -} diff --git a/p2p/protocol/ping/ping_test.go b/p2p/protocol/ping/ping_test.go deleted file mode 100644 index 85bb342199c..00000000000 --- a/p2p/protocol/ping/ping_test.go +++ /dev/null @@ -1,51 +0,0 @@ -package ping - -import ( - "testing" - "time" - - context "github.com/ipfs/go-ipfs/Godeps/_workspace/src/golang.org/x/net/context" - peer "github.com/ipfs/go-ipfs/p2p/peer" - netutil "github.com/ipfs/go-ipfs/p2p/test/util" -) - -func TestPing(t *testing.T) { - ctx, cancel := context.WithCancel(context.Background()) - defer cancel() - h1 := netutil.GenHostSwarm(t, ctx) - h2 := netutil.GenHostSwarm(t, ctx) - - err := h1.Connect(ctx, peer.PeerInfo{ - ID: h2.ID(), - Addrs: h2.Addrs(), - }) - - if err != nil { - t.Fatal(err) - } - - ps1 := NewPingService(h1) - ps2 := NewPingService(h2) - - testPing(t, ps1, h2.ID()) - testPing(t, ps2, h1.ID()) -} - -func testPing(t *testing.T, ps *PingService, p peer.ID) { - pctx, cancel := context.WithCancel(context.Background()) - defer cancel() - ts, err := ps.Ping(pctx, p) - if err != nil { - t.Fatal(err) - } - - for i := 0; i < 5; i++ { - select { - case took := <-ts: - t.Log("ping took: ", took) - case <-time.After(time.Second * 4): - t.Fatal("failed to receive ping") - } - } - -} diff --git a/p2p/protocol/protocol.go b/p2p/protocol/protocol.go deleted file mode 100644 index f7e4a32baf0..00000000000 --- a/p2p/protocol/protocol.go +++ /dev/null @@ -1,9 +0,0 @@ -package protocol - -// ID is an identifier used to write protocol headers in streams. -type ID string - -// These are reserved protocol.IDs. -const ( - TestingID ID = "/p2p/_testing" -) diff --git a/p2p/protocol/relay/relay.go b/p2p/protocol/relay/relay.go deleted file mode 100644 index d76f57ffede..00000000000 --- a/p2p/protocol/relay/relay.go +++ /dev/null @@ -1,156 +0,0 @@ -package relay - -import ( - "fmt" - "io" - - mh "github.com/ipfs/go-ipfs/Godeps/_workspace/src/github.com/jbenet/go-multihash" - - host "github.com/ipfs/go-ipfs/p2p/host" - inet "github.com/ipfs/go-ipfs/p2p/net" - peer "github.com/ipfs/go-ipfs/p2p/peer" - protocol "github.com/ipfs/go-ipfs/p2p/protocol" - logging "github.com/ipfs/go-ipfs/vendor/QmQg1J6vikuXF9oDvm4wpdeAUvvkVEKW1EYDw9HhTMnP2b/go-log" -) - -var log = logging.Logger("p2p/protocol/relay") - -// ID is the protocol.ID of the Relay Service. -const ID protocol.ID = "/ipfs/relay" - -// Relay is a structure that implements ProtocolRelay. -// It is a simple relay service which forwards traffic -// between two directly connected peers. -// -// the protocol is very simple: -// -// /ipfs/relay\n -// -// -// -// -type RelayService struct { - host host.Host - handler inet.StreamHandler // for streams sent to us locally. -} - -func NewRelayService(h host.Host, sh inet.StreamHandler) *RelayService { - s := &RelayService{ - host: h, - handler: sh, - } - h.SetStreamHandler(ID, s.requestHandler) - return s -} - -// requestHandler is the function called by clients -func (rs *RelayService) requestHandler(s inet.Stream) { - if err := rs.handleStream(s); err != nil { - log.Debugf("RelayService error:", err) - } -} - -// handleStream is our own handler, which returns an error for simplicity. -func (rs *RelayService) handleStream(s inet.Stream) error { - defer s.Close() - - // read the header (src and dst peer.IDs) - src, dst, err := ReadHeader(s) - if err != nil { - return fmt.Errorf("stream with bad header: %s", err) - } - - local := rs.host.ID() - - switch { - case src == local: - return fmt.Errorf("relaying from self") - case dst == local: // it's for us! yaaay. - log.Debugf("%s consuming stream from %s", local, src) - return rs.consumeStream(s) - default: // src and dst are not local. relay it. - log.Debugf("%s relaying stream %s <--> %s", local, src, dst) - return rs.pipeStream(src, dst, s) - } -} - -// consumeStream connects streams directed to the local peer -// to our handler, with the header now stripped (read). -func (rs *RelayService) consumeStream(s inet.Stream) error { - rs.handler(s) // boom. - return nil -} - -// pipeStream relays over a stream to a remote peer. It's like `cat` -func (rs *RelayService) pipeStream(src, dst peer.ID, s inet.Stream) error { - s2, err := rs.openStreamToPeer(dst) - if err != nil { - return fmt.Errorf("failed to open stream to peer: %s -- %s", dst, err) - } - - if err := WriteHeader(s2, src, dst); err != nil { - return err - } - - // connect the series of tubes. - done := make(chan retio, 2) - go func() { - n, err := io.Copy(s2, s) - done <- retio{n, err} - }() - go func() { - n, err := io.Copy(s, s2) - done <- retio{n, err} - }() - - r1 := <-done - r2 := <-done - log.Infof("%s relayed %d/%d bytes between %s and %s", rs.host.ID(), r1.n, r2.n, src, dst) - - if r1.err != nil { - return r1.err - } - return r2.err -} - -// openStreamToPeer opens a pipe to a remote endpoint -// for now, can only open streams to directly connected peers. -// maybe we can do some routing later on. -func (rs *RelayService) openStreamToPeer(p peer.ID) (inet.Stream, error) { - return rs.host.NewStream(ID, p) -} - -func ReadHeader(r io.Reader) (src, dst peer.ID, err error) { - - mhr := mh.NewReader(r) - - s, err := mhr.ReadMultihash() - if err != nil { - return "", "", err - } - - d, err := mhr.ReadMultihash() - if err != nil { - return "", "", err - } - - return peer.ID(s), peer.ID(d), nil -} - -func WriteHeader(w io.Writer, src, dst peer.ID) error { - // write header to w. - mhw := mh.NewWriter(w) - if err := mhw.WriteMultihash(mh.Multihash(src)); err != nil { - return fmt.Errorf("failed to write relay header: %s -- %s", dst, err) - } - if err := mhw.WriteMultihash(mh.Multihash(dst)); err != nil { - return fmt.Errorf("failed to write relay header: %s -- %s", dst, err) - } - - return nil -} - -type retio struct { - n int64 - err error -} diff --git a/p2p/protocol/relay/relay_test.go b/p2p/protocol/relay/relay_test.go deleted file mode 100644 index 671f6dddad2..00000000000 --- a/p2p/protocol/relay/relay_test.go +++ /dev/null @@ -1,304 +0,0 @@ -package relay_test - -import ( - "io" - "testing" - - inet "github.com/ipfs/go-ipfs/p2p/net" - protocol "github.com/ipfs/go-ipfs/p2p/protocol" - relay "github.com/ipfs/go-ipfs/p2p/protocol/relay" - testutil "github.com/ipfs/go-ipfs/p2p/test/util" - logging "github.com/ipfs/go-ipfs/vendor/QmQg1J6vikuXF9oDvm4wpdeAUvvkVEKW1EYDw9HhTMnP2b/go-log" - - msmux "github.com/ipfs/go-ipfs/Godeps/_workspace/src/github.com/whyrusleeping/go-multistream" - context "github.com/ipfs/go-ipfs/Godeps/_workspace/src/golang.org/x/net/context" -) - -var log = logging.Logger("relay_test") - -func TestRelaySimple(t *testing.T) { - - ctx := context.Background() - - // these networks have the relay service wired in already. - n1 := testutil.GenHostSwarm(t, ctx) - n2 := testutil.GenHostSwarm(t, ctx) - n3 := testutil.GenHostSwarm(t, ctx) - - n1p := n1.ID() - n2p := n2.ID() - n3p := n3.ID() - - n2pi := n2.Peerstore().PeerInfo(n2p) - if err := n1.Connect(ctx, n2pi); err != nil { - t.Fatal("Failed to connect:", err) - } - if err := n3.Connect(ctx, n2pi); err != nil { - t.Fatal("Failed to connect:", err) - } - - // setup handler on n3 to copy everything over to the pipe. - piper, pipew := io.Pipe() - n3.SetStreamHandler(protocol.TestingID, func(s inet.Stream) { - log.Debug("relay stream opened to n3!") - log.Debug("piping and echoing everything") - w := io.MultiWriter(s, pipew) - io.Copy(w, s) - log.Debug("closing stream") - s.Close() - }) - - // ok, now we can try to relay n1--->n2--->n3. - log.Debug("open relay stream") - s, err := n1.NewStream(relay.ID, n2p) - if err != nil { - t.Fatal(err) - } - - // ok first thing we write the relay header n1->n3 - log.Debug("write relay header") - if err := relay.WriteHeader(s, n1p, n3p); err != nil { - t.Fatal(err) - } - - // ok now the header's there, we can write the next protocol header. - log.Debug("write testing header") - if err := msmux.SelectProtoOrFail(string(protocol.TestingID), s); err != nil { - t.Fatal(err) - } - - // okay, now we should be able to write text, and read it out. - buf1 := []byte("abcdefghij") - buf2 := make([]byte, 10) - buf3 := make([]byte, 10) - log.Debug("write in some text.") - if _, err := s.Write(buf1); err != nil { - t.Fatal(err) - } - - // read it out from the pipe. - log.Debug("read it out from the pipe.") - if _, err := io.ReadFull(piper, buf2); err != nil { - t.Fatal(err) - } - if string(buf1) != string(buf2) { - t.Fatal("should've gotten that text out of the pipe") - } - - // read it out from the stream (echoed) - log.Debug("read it out from the stream (echoed).") - if _, err := io.ReadFull(s, buf3); err != nil { - t.Fatal(err) - } - if string(buf1) != string(buf3) { - t.Fatal("should've gotten that text out of the stream") - } - - // sweet. relay works. - log.Debug("sweet, relay works.") - s.Close() -} - -func TestRelayAcrossFour(t *testing.T) { - - ctx := context.Background() - - // these networks have the relay service wired in already. - n1 := testutil.GenHostSwarm(t, ctx) - n2 := testutil.GenHostSwarm(t, ctx) - n3 := testutil.GenHostSwarm(t, ctx) - n4 := testutil.GenHostSwarm(t, ctx) - n5 := testutil.GenHostSwarm(t, ctx) - - n1p := n1.ID() - n2p := n2.ID() - n3p := n3.ID() - n4p := n4.ID() - n5p := n5.ID() - - n2pi := n2.Peerstore().PeerInfo(n2p) - n4pi := n4.Peerstore().PeerInfo(n4p) - - if err := n1.Connect(ctx, n2pi); err != nil { - t.Fatalf("Failed to dial:", err) - } - if err := n3.Connect(ctx, n2pi); err != nil { - t.Fatalf("Failed to dial:", err) - } - if err := n3.Connect(ctx, n4pi); err != nil { - t.Fatalf("Failed to dial:", err) - } - if err := n5.Connect(ctx, n4pi); err != nil { - t.Fatalf("Failed to dial:", err) - } - - // setup handler on n5 to copy everything over to the pipe. - piper, pipew := io.Pipe() - n5.SetStreamHandler(protocol.TestingID, func(s inet.Stream) { - log.Debug("relay stream opened to n5!") - log.Debug("piping and echoing everything") - w := io.MultiWriter(s, pipew) - io.Copy(w, s) - log.Debug("closing stream") - s.Close() - }) - - // ok, now we can try to relay n1--->n2--->n3--->n4--->n5 - log.Debug("open relay stream") - s, err := n1.NewStream(relay.ID, n2p) - if err != nil { - t.Fatal(err) - } - - log.Debugf("write relay header n1->n3 (%s -> %s)", n1p, n3p) - if err := relay.WriteHeader(s, n1p, n3p); err != nil { - t.Fatal(err) - } - - log.Debugf("write relay header n1->n4 (%s -> %s)", n1p, n4p) - if err := msmux.SelectProtoOrFail(string(relay.ID), s); err != nil { - t.Fatal(err) - } - if err := relay.WriteHeader(s, n1p, n4p); err != nil { - t.Fatal(err) - } - - log.Debugf("write relay header n1->n5 (%s -> %s)", n1p, n5p) - if err := msmux.SelectProtoOrFail(string(relay.ID), s); err != nil { - t.Fatal(err) - } - if err := relay.WriteHeader(s, n1p, n5p); err != nil { - t.Fatal(err) - } - - // ok now the header's there, we can write the next protocol header. - log.Debug("write testing header") - if err := msmux.SelectProtoOrFail(string(protocol.TestingID), s); err != nil { - t.Fatal(err) - } - - // okay, now we should be able to write text, and read it out. - buf1 := []byte("abcdefghij") - buf2 := make([]byte, 10) - buf3 := make([]byte, 10) - log.Debug("write in some text.") - if _, err := s.Write(buf1); err != nil { - t.Fatal(err) - } - - // read it out from the pipe. - log.Debug("read it out from the pipe.") - if _, err := io.ReadFull(piper, buf2); err != nil { - t.Fatal(err) - } - if string(buf1) != string(buf2) { - t.Fatal("should've gotten that text out of the pipe") - } - - // read it out from the stream (echoed) - log.Debug("read it out from the stream (echoed).") - if _, err := io.ReadFull(s, buf3); err != nil { - t.Fatal(err) - } - if string(buf1) != string(buf3) { - t.Fatal("should've gotten that text out of the stream") - } - - // sweet. relay works. - log.Debug("sweet, relaying across 4 works.") - s.Close() -} - -func TestRelayStress(t *testing.T) { - buflen := 1 << 18 - iterations := 10 - - ctx := context.Background() - - // these networks have the relay service wired in already. - n1 := testutil.GenHostSwarm(t, ctx) - n2 := testutil.GenHostSwarm(t, ctx) - n3 := testutil.GenHostSwarm(t, ctx) - - n1p := n1.ID() - n2p := n2.ID() - n3p := n3.ID() - - n2pi := n2.Peerstore().PeerInfo(n2p) - if err := n1.Connect(ctx, n2pi); err != nil { - t.Fatalf("Failed to dial:", err) - } - if err := n3.Connect(ctx, n2pi); err != nil { - t.Fatalf("Failed to dial:", err) - } - - // setup handler on n3 to copy everything over to the pipe. - piper, pipew := io.Pipe() - n3.SetStreamHandler(protocol.TestingID, func(s inet.Stream) { - log.Debug("relay stream opened to n3!") - log.Debug("piping and echoing everything") - w := io.MultiWriter(s, pipew) - io.Copy(w, s) - log.Debug("closing stream") - s.Close() - }) - - // ok, now we can try to relay n1--->n2--->n3. - log.Debug("open relay stream") - s, err := n1.NewStream(relay.ID, n2p) - if err != nil { - t.Fatal(err) - } - - // ok first thing we write the relay header n1->n3 - log.Debug("write relay header") - if err := relay.WriteHeader(s, n1p, n3p); err != nil { - t.Fatal(err) - } - - // ok now the header's there, we can write the next protocol header. - log.Debug("write testing header") - if err := msmux.SelectProtoOrFail(string(protocol.TestingID), s); err != nil { - t.Fatal(err) - } - - // okay, now write lots of text and read it back out from both - // the pipe and the stream. - buf1 := make([]byte, buflen) - buf2 := make([]byte, len(buf1)) - buf3 := make([]byte, len(buf1)) - - fillbuf := func(buf []byte, b byte) { - for i := range buf { - buf[i] = b - } - } - - for i := 0; i < iterations; i++ { - fillbuf(buf1, byte(int('a')+i)) - log.Debugf("writing %d bytes (%d/%d)", len(buf1), i, iterations) - if _, err := s.Write(buf1); err != nil { - t.Fatal(err) - } - - log.Debug("read it out from the pipe.") - if _, err := io.ReadFull(piper, buf2); err != nil { - t.Fatal(err) - } - if string(buf1) != string(buf2) { - t.Fatal("should've gotten that text out of the pipe") - } - - // read it out from the stream (echoed) - log.Debug("read it out from the stream (echoed).") - if _, err := io.ReadFull(s, buf3); err != nil { - t.Fatal(err) - } - if string(buf1) != string(buf3) { - t.Fatal("should've gotten that text out of the stream") - } - } - - log.Debug("sweet, relay works under stress.") - s.Close() -} diff --git a/p2p/test/backpressure/backpressure.go b/p2p/test/backpressure/backpressure.go deleted file mode 100644 index 19950a72801..00000000000 --- a/p2p/test/backpressure/backpressure.go +++ /dev/null @@ -1 +0,0 @@ -package backpressure_tests diff --git a/p2p/test/backpressure/backpressure_test.go b/p2p/test/backpressure/backpressure_test.go deleted file mode 100644 index b13d772469b..00000000000 --- a/p2p/test/backpressure/backpressure_test.go +++ /dev/null @@ -1,380 +0,0 @@ -package backpressure_tests - -import ( - "io" - "math/rand" - "testing" - "time" - - host "github.com/ipfs/go-ipfs/p2p/host" - inet "github.com/ipfs/go-ipfs/p2p/net" - peer "github.com/ipfs/go-ipfs/p2p/peer" - protocol "github.com/ipfs/go-ipfs/p2p/protocol" - testutil "github.com/ipfs/go-ipfs/p2p/test/util" - logging "github.com/ipfs/go-ipfs/vendor/QmQg1J6vikuXF9oDvm4wpdeAUvvkVEKW1EYDw9HhTMnP2b/go-log" - - context "github.com/ipfs/go-ipfs/Godeps/_workspace/src/golang.org/x/net/context" - u "github.com/ipfs/go-ipfs/util" -) - -var log = logging.Logger("backpressure") - -// TestBackpressureStreamHandler tests whether mux handler -// ratelimiting works. Meaning, since the handler is sequential -// it should block senders. -// -// Important note: spdystream (which peerstream uses) has a set -// of n workers (n=spdsystream.FRAME_WORKERS) which handle new -// frames, including those starting new streams. So all of them -// can be in the handler at one time. Also, the sending side -// does not rate limit unless we call stream.Wait() -// -// -// Note: right now, this happens muxer-wide. the muxer should -// learn to flow control, so handlers cant block each other. -func TestBackpressureStreamHandler(t *testing.T) { - t.Skip(`Sadly, as cool as this test is, it doesn't work -Because spdystream doesnt handle stream open backpressure -well IMO. I'll see about rewriting that part when it becomes -a problem. -`) - - // a number of concurrent request handlers - limit := 10 - - // our way to signal that we're done with 1 request - requestHandled := make(chan struct{}) - - // handler rate limiting - receiverRatelimit := make(chan struct{}, limit) - for i := 0; i < limit; i++ { - receiverRatelimit <- struct{}{} - } - - // sender counter of successfully opened streams - senderOpened := make(chan struct{}, limit*100) - - // sender signals it's done (errored out) - senderDone := make(chan struct{}) - - // the receiver handles requests with some rate limiting - receiver := func(s inet.Stream) { - log.Debug("receiver received a stream") - - <-receiverRatelimit // acquire - go func() { - // our request handler. can do stuff here. we - // simulate something taking time by waiting - // on requestHandled - log.Debug("request worker handling...") - <-requestHandled - log.Debug("request worker done!") - receiverRatelimit <- struct{}{} // release - }() - } - - // the sender opens streams as fast as possible - sender := func(host host.Host, remote peer.ID) { - var s inet.Stream - var err error - defer func() { - t.Error(err) - log.Debug("sender error. exiting.") - senderDone <- struct{}{} - }() - - for { - s, err = host.NewStream(protocol.TestingID, remote) - if err != nil { - return - } - - _ = s - // if err = s.SwarmStream().Stream().Wait(); err != nil { - // return - // } - - // "count" another successfully opened stream - // (large buffer so shouldn't block in normal operation) - log.Debug("sender opened another stream!") - senderOpened <- struct{}{} - } - } - - // count our senderOpened events - countStreamsOpenedBySender := func(min int) int { - opened := 0 - for opened < min { - log.Debugf("countStreamsOpenedBySender got %d (min %d)", opened, min) - select { - case <-senderOpened: - opened++ - case <-time.After(10 * time.Millisecond): - } - } - return opened - } - - // count our received events - // waitForNReceivedStreams := func(n int) { - // for n > 0 { - // log.Debugf("waiting for %d received streams...", n) - // select { - // case <-receiverRatelimit: - // n-- - // } - // } - // } - - testStreamsOpened := func(expected int) { - log.Debugf("testing rate limited to %d streams", expected) - if n := countStreamsOpenedBySender(expected); n != expected { - t.Fatalf("rate limiting did not work :( -- %d != %d", expected, n) - } - } - - // ok that's enough setup. let's do it! - - ctx := context.Background() - h1 := testutil.GenHostSwarm(t, ctx) - h2 := testutil.GenHostSwarm(t, ctx) - - // setup receiver handler - h1.SetStreamHandler(protocol.TestingID, receiver) - - h2pi := h2.Peerstore().PeerInfo(h2.ID()) - log.Debugf("dialing %s", h2pi.Addrs) - if err := h1.Connect(ctx, h2pi); err != nil { - t.Fatalf("Failed to connect:", err) - } - - // launch sender! - go sender(h2, h1.ID()) - - // ok, what do we expect to happen? the receiver should - // receive 10 requests and stop receiving, blocking the sender. - // we can test this by counting 10x senderOpened requests - - <-senderOpened // wait for the sender to successfully open some. - testStreamsOpened(limit - 1) - - // let's "handle" 3 requests. - <-requestHandled - <-requestHandled - <-requestHandled - // the sender should've now been able to open exactly 3 more. - - testStreamsOpened(3) - - // shouldn't have opened anything more - testStreamsOpened(0) - - // let's "handle" 100 requests in batches of 5 - for i := 0; i < 20; i++ { - <-requestHandled - <-requestHandled - <-requestHandled - <-requestHandled - <-requestHandled - testStreamsOpened(5) - } - - // success! - - // now for the sugar on top: let's tear down the receiver. it should - // exit the sender. - h1.Close() - - // shouldn't have opened anything more - testStreamsOpened(0) - - select { - case <-time.After(100 * time.Millisecond): - t.Error("receiver shutdown failed to exit sender") - case <-senderDone: - log.Info("handler backpressure works!") - } -} - -// TestStBackpressureStreamWrite tests whether streams see proper -// backpressure when writing data over the network streams. -func TestStBackpressureStreamWrite(t *testing.T) { - - // senderWrote signals that the sender wrote bytes to remote. - // the value is the count of bytes written. - senderWrote := make(chan int, 10000) - - // sender signals it's done (errored out) - senderDone := make(chan struct{}) - - // writeStats lets us listen to all the writes and return - // how many happened and how much was written - writeStats := func() (int, int) { - writes := 0 - bytes := 0 - for { - select { - case n := <-senderWrote: - writes++ - bytes = bytes + n - default: - log.Debugf("stats: sender wrote %d bytes, %d writes", bytes, writes) - return bytes, writes - } - } - } - - // sender attempts to write as fast as possible, signaling on the - // completion of every write. This makes it possible to see how - // fast it's actually writing. We pair this with a receiver - // that waits for a signal to read. - sender := func(s inet.Stream) { - defer func() { - s.Close() - senderDone <- struct{}{} - }() - - // ready a buffer of random data - buf := make([]byte, 65536) - u.NewTimeSeededRand().Read(buf) - - for { - // send a randomly sized subchunk - from := rand.Intn(len(buf) / 2) - to := rand.Intn(len(buf) / 2) - sendbuf := buf[from : from+to] - - n, err := s.Write(sendbuf) - if err != nil { - log.Debug("sender error. exiting:", err) - return - } - - log.Debugf("sender wrote %d bytes", n) - senderWrote <- n - } - } - - // receive a number of bytes from a stream. - // returns the number of bytes written. - receive := func(s inet.Stream, expect int) { - log.Debugf("receiver to read %d bytes", expect) - rbuf := make([]byte, expect) - n, err := io.ReadFull(s, rbuf) - if err != nil { - t.Error("read failed:", err) - } - if expect != n { - t.Error("read len differs: %d != %d", expect, n) - } - } - - // ok let's do it! - - // setup the networks - ctx := context.Background() - h1 := testutil.GenHostSwarm(t, ctx) - h2 := testutil.GenHostSwarm(t, ctx) - - // setup sender handler on 1 - h1.SetStreamHandler(protocol.TestingID, sender) - - h2pi := h2.Peerstore().PeerInfo(h2.ID()) - log.Debugf("dialing %s", h2pi.Addrs) - if err := h1.Connect(ctx, h2pi); err != nil { - t.Fatalf("Failed to connect:", err) - } - - // open a stream, from 2->1, this is our reader - s, err := h2.NewStream(protocol.TestingID, h1.ID()) - if err != nil { - t.Fatal(err) - } - - // let's make sure r/w works. - testSenderWrote := func(bytesE int) { - bytesA, writesA := writeStats() - if bytesA != bytesE { - t.Errorf("numbers failed: %d =?= %d bytes, via %d writes", bytesA, bytesE, writesA) - } - } - - // trigger lazy connection handshaking - _, err = s.Read(nil) - if err != nil { - t.Fatal(err) - } - - // 500ms rounds of lockstep write + drain - roundsStart := time.Now() - roundsTotal := 0 - for roundsTotal < (2 << 20) { - // let the sender fill its buffers, it will stop sending. - <-time.After(300 * time.Millisecond) - b, _ := writeStats() - testSenderWrote(0) - testSenderWrote(0) - - // drain it all, wait again - receive(s, b) - roundsTotal = roundsTotal + b - } - roundsTime := time.Now().Sub(roundsStart) - - // now read continously, while we measure stats. - stop := make(chan struct{}) - contStart := time.Now() - - go func() { - for { - select { - case <-stop: - return - default: - receive(s, 2<<15) - } - } - }() - - contTotal := 0 - for contTotal < (2 << 20) { - n := <-senderWrote - contTotal += n - } - stop <- struct{}{} - contTime := time.Now().Sub(contStart) - - // now compare! continuous should've been faster AND larger - if roundsTime < contTime { - t.Error("continuous should have been faster") - } - - if roundsTotal < contTotal { - t.Error("continuous should have been larger, too!") - } - - // and a couple rounds more for good measure ;) - for i := 0; i < 3; i++ { - // let the sender fill its buffers, it will stop sending. - <-time.After(300 * time.Millisecond) - b, _ := writeStats() - testSenderWrote(0) - testSenderWrote(0) - - // drain it all, wait again - receive(s, b) - } - - // this doesn't work :(: - // // now for the sugar on top: let's tear down the receiver. it should - // // exit the sender. - // n1.Close() - // testSenderWrote(0) - // testSenderWrote(0) - // select { - // case <-time.After(2 * time.Second): - // t.Error("receiver shutdown failed to exit sender") - // case <-senderDone: - // log.Info("handler backpressure works!") - // } -} diff --git a/p2p/test/reconnects/reconnect.go b/p2p/test/reconnects/reconnect.go deleted file mode 100644 index a0f356d2e73..00000000000 --- a/p2p/test/reconnects/reconnect.go +++ /dev/null @@ -1,2 +0,0 @@ -// Package reconnect tests connect -> disconnect -> reconnect works -package reconnect diff --git a/p2p/test/reconnects/reconnect_test.go b/p2p/test/reconnects/reconnect_test.go deleted file mode 100644 index ae2355205ab..00000000000 --- a/p2p/test/reconnects/reconnect_test.go +++ /dev/null @@ -1,234 +0,0 @@ -package reconnect - -import ( - "io" - "math/rand" - "sync" - "testing" - "time" - - host "github.com/ipfs/go-ipfs/p2p/host" - inet "github.com/ipfs/go-ipfs/p2p/net" - swarm "github.com/ipfs/go-ipfs/p2p/net/swarm" - protocol "github.com/ipfs/go-ipfs/p2p/protocol" - testutil "github.com/ipfs/go-ipfs/p2p/test/util" - u "github.com/ipfs/go-ipfs/util" - logging "github.com/ipfs/go-ipfs/vendor/QmQg1J6vikuXF9oDvm4wpdeAUvvkVEKW1EYDw9HhTMnP2b/go-log" - - ps "github.com/ipfs/go-ipfs/Godeps/_workspace/src/github.com/jbenet/go-peerstream" - context "github.com/ipfs/go-ipfs/Godeps/_workspace/src/golang.org/x/net/context" -) - -func init() { - // change the garbage collect timeout for testing. - ps.GarbageCollectTimeout = 10 * time.Millisecond -} - -var log = logging.Logger("reconnect") - -func EchoStreamHandler(stream inet.Stream) { - c := stream.Conn() - log.Debugf("%s echoing %s", c.LocalPeer(), c.RemotePeer()) - go func() { - defer stream.Close() - io.Copy(stream, stream) - }() -} - -type sendChans struct { - send chan struct{} - sent chan struct{} - read chan struct{} - close_ chan struct{} - closed chan struct{} -} - -func newSendChans() sendChans { - return sendChans{ - send: make(chan struct{}), - sent: make(chan struct{}), - read: make(chan struct{}), - close_: make(chan struct{}), - closed: make(chan struct{}), - } -} - -func newSender() (chan sendChans, func(s inet.Stream)) { - scc := make(chan sendChans) - return scc, func(s inet.Stream) { - sc := newSendChans() - scc <- sc - - defer func() { - s.Close() - sc.closed <- struct{}{} - }() - - buf := make([]byte, 65536) - buf2 := make([]byte, 65536) - u.NewTimeSeededRand().Read(buf) - - for { - select { - case <-sc.close_: - return - case <-sc.send: - } - - // send a randomly sized subchunk - from := rand.Intn(len(buf) / 2) - to := rand.Intn(len(buf) / 2) - sendbuf := buf[from : from+to] - - log.Debugf("sender sending %d bytes", len(sendbuf)) - n, err := s.Write(sendbuf) - if err != nil { - log.Debug("sender error. exiting:", err) - return - } - - log.Debugf("sender wrote %d bytes", n) - sc.sent <- struct{}{} - - if n, err = io.ReadFull(s, buf2[:len(sendbuf)]); err != nil { - log.Debug("sender error. failed to read:", err) - return - } - - log.Debugf("sender read %d bytes", n) - sc.read <- struct{}{} - } - } -} - -// TestReconnect tests whether hosts are able to disconnect and reconnect. -func TestReconnect2(t *testing.T) { - ctx := context.Background() - h1 := testutil.GenHostSwarm(t, ctx) - h2 := testutil.GenHostSwarm(t, ctx) - hosts := []host.Host{h1, h2} - - h1.SetStreamHandler(protocol.TestingID, EchoStreamHandler) - h2.SetStreamHandler(protocol.TestingID, EchoStreamHandler) - - rounds := 8 - if testing.Short() { - rounds = 4 - } - for i := 0; i < rounds; i++ { - log.Debugf("TestReconnect: %d/%d\n", i, rounds) - SubtestConnSendDisc(t, hosts) - } -} - -// TestReconnect tests whether hosts are able to disconnect and reconnect. -func TestReconnect5(t *testing.T) { - ctx := context.Background() - h1 := testutil.GenHostSwarm(t, ctx) - h2 := testutil.GenHostSwarm(t, ctx) - h3 := testutil.GenHostSwarm(t, ctx) - h4 := testutil.GenHostSwarm(t, ctx) - h5 := testutil.GenHostSwarm(t, ctx) - hosts := []host.Host{h1, h2, h3, h4, h5} - - h1.SetStreamHandler(protocol.TestingID, EchoStreamHandler) - h2.SetStreamHandler(protocol.TestingID, EchoStreamHandler) - h3.SetStreamHandler(protocol.TestingID, EchoStreamHandler) - h4.SetStreamHandler(protocol.TestingID, EchoStreamHandler) - h5.SetStreamHandler(protocol.TestingID, EchoStreamHandler) - - rounds := 4 - if testing.Short() { - rounds = 2 - } - for i := 0; i < rounds; i++ { - log.Debugf("TestReconnect: %d/%d\n", i, rounds) - SubtestConnSendDisc(t, hosts) - } -} - -func SubtestConnSendDisc(t *testing.T, hosts []host.Host) { - - ctx := context.Background() - numStreams := 3 * len(hosts) - numMsgs := 10 - - if testing.Short() { - numStreams = 5 * len(hosts) - numMsgs = 4 - } - - ss, sF := newSender() - - for _, h1 := range hosts { - for _, h2 := range hosts { - if h1.ID() >= h2.ID() { - continue - } - - h2pi := h2.Peerstore().PeerInfo(h2.ID()) - log.Debugf("dialing %s", h2pi.Addrs) - if err := h1.Connect(ctx, h2pi); err != nil { - t.Fatalf("Failed to connect:", err) - } - } - } - - var wg sync.WaitGroup - for i := 0; i < numStreams; i++ { - h1 := hosts[i%len(hosts)] - h2 := hosts[(i+1)%len(hosts)] - s, err := h1.NewStream(protocol.TestingID, h2.ID()) - if err != nil { - t.Error(err) - } - - wg.Add(1) - go func(j int) { - defer wg.Done() - - go sF(s) - log.Debugf("getting handle %d", j) - sc := <-ss // wait to get handle. - log.Debugf("spawning worker %d", j) - - for k := 0; k < numMsgs; k++ { - sc.send <- struct{}{} - <-sc.sent - log.Debugf("%d sent %d", j, k) - <-sc.read - log.Debugf("%d read %d", j, k) - } - sc.close_ <- struct{}{} - <-sc.closed - log.Debugf("closed %d", j) - }(i) - } - wg.Wait() - - for i, h1 := range hosts { - log.Debugf("host %d has %d conns", i, len(h1.Network().Conns())) - } - - for _, h1 := range hosts { - // close connection - cs := h1.Network().Conns() - for _, c := range cs { - sc := c.(*swarm.Conn) - if sc.LocalPeer() > sc.RemotePeer() { - continue // only close it on one side. - } - - log.Debugf("closing: %s", sc.RawConn()) - sc.Close() - } - } - - <-time.After(20 * time.Millisecond) - - for i, h := range hosts { - if len(h.Network().Conns()) > 0 { - t.Fatalf("host %d %s has %d conns! not zero.", i, h.ID(), len(h.Network().Conns())) - } - } -} diff --git a/p2p/test/util/key.go b/p2p/test/util/key.go deleted file mode 100644 index 9f1a7a17d75..00000000000 --- a/p2p/test/util/key.go +++ /dev/null @@ -1,165 +0,0 @@ -package testutil - -import ( - "bytes" - "io" - "testing" - - u "github.com/ipfs/go-ipfs/util" - testutil "github.com/ipfs/go-ipfs/util/testutil" - logging "github.com/ipfs/go-ipfs/vendor/QmQg1J6vikuXF9oDvm4wpdeAUvvkVEKW1EYDw9HhTMnP2b/go-log" - - ic "github.com/ipfs/go-ipfs/p2p/crypto" - peer "github.com/ipfs/go-ipfs/p2p/peer" - - ma "github.com/ipfs/go-ipfs/Godeps/_workspace/src/github.com/jbenet/go-multiaddr" -) - -var log = logging.Logger("boguskey") - -// TestBogusPrivateKey is a key used for testing (to avoid expensive keygen) -type TestBogusPrivateKey []byte - -// TestBogusPublicKey is a key used for testing (to avoid expensive keygen) -type TestBogusPublicKey []byte - -func (pk TestBogusPublicKey) Verify(data, sig []byte) (bool, error) { - log.Errorf("TestBogusPublicKey.Verify -- this better be a test!") - return bytes.Equal(data, reverse(sig)), nil -} - -func (pk TestBogusPublicKey) Bytes() ([]byte, error) { - return []byte(pk), nil -} - -func (pk TestBogusPublicKey) Encrypt(b []byte) ([]byte, error) { - log.Errorf("TestBogusPublicKey.Encrypt -- this better be a test!") - return reverse(b), nil -} - -// Equals checks whether this key is equal to another -func (pk TestBogusPublicKey) Equals(k ic.Key) bool { - return ic.KeyEqual(pk, k) -} - -func (pk TestBogusPublicKey) Hash() ([]byte, error) { - return ic.KeyHash(pk) -} - -func (sk TestBogusPrivateKey) GenSecret() []byte { - return []byte(sk) -} - -func (sk TestBogusPrivateKey) Sign(message []byte) ([]byte, error) { - log.Errorf("TestBogusPrivateKey.Sign -- this better be a test!") - return reverse(message), nil -} - -func (sk TestBogusPrivateKey) GetPublic() ic.PubKey { - return TestBogusPublicKey(sk) -} - -func (sk TestBogusPrivateKey) Decrypt(b []byte) ([]byte, error) { - log.Errorf("TestBogusPrivateKey.Decrypt -- this better be a test!") - return reverse(b), nil -} - -func (sk TestBogusPrivateKey) Bytes() ([]byte, error) { - return []byte(sk), nil -} - -// Equals checks whether this key is equal to another -func (sk TestBogusPrivateKey) Equals(k ic.Key) bool { - return ic.KeyEqual(sk, k) -} - -func (sk TestBogusPrivateKey) Hash() ([]byte, error) { - return ic.KeyHash(sk) -} - -func RandTestBogusPrivateKey() (TestBogusPrivateKey, error) { - r := u.NewTimeSeededRand() - k := make([]byte, 5) - if _, err := io.ReadFull(r, k); err != nil { - return nil, err - } - return TestBogusPrivateKey(k), nil -} - -func RandTestBogusPublicKey() (TestBogusPublicKey, error) { - k, err := RandTestBogusPrivateKey() - return TestBogusPublicKey(k), err -} - -func RandTestBogusPrivateKeyOrFatal(t *testing.T) TestBogusPrivateKey { - k, err := RandTestBogusPrivateKey() - if err != nil { - t.Fatal(err) - } - return k -} - -func RandTestBogusPublicKeyOrFatal(t *testing.T) TestBogusPublicKey { - k, err := RandTestBogusPublicKey() - if err != nil { - t.Fatal(err) - } - return k -} - -func RandTestBogusIdentity() (testutil.Identity, error) { - k, err := RandTestBogusPrivateKey() - if err != nil { - return nil, err - } - - id, err := peer.IDFromPrivateKey(k) - if err != nil { - return nil, err - } - - return &identity{ - k: k, - id: id, - a: testutil.RandLocalTCPAddress(), - }, nil -} - -func RandTestBogusIdentityOrFatal(t *testing.T) testutil.Identity { - k, err := RandTestBogusIdentity() - if err != nil { - t.Fatal(err) - } - return k -} - -// identity is a temporary shim to delay binding of PeerNetParams. -type identity struct { - k TestBogusPrivateKey - id peer.ID - a ma.Multiaddr -} - -func (p *identity) ID() peer.ID { - return p.id -} - -func (p *identity) Address() ma.Multiaddr { - return p.a -} - -func (p *identity) PrivateKey() ic.PrivKey { - return p.k -} - -func (p *identity) PublicKey() ic.PubKey { - return p.k.GetPublic() -} - -func reverse(a []byte) []byte { - b := make([]byte, len(a)) - for i := 0; i < len(a); i++ { - b[i] = a[len(a)-1-i] - } - return b -} diff --git a/p2p/test/util/util.go b/p2p/test/util/util.go deleted file mode 100644 index bcc02021d30..00000000000 --- a/p2p/test/util/util.go +++ /dev/null @@ -1,41 +0,0 @@ -package testutil - -import ( - "testing" - - metrics "github.com/ipfs/go-ipfs/metrics" - bhost "github.com/ipfs/go-ipfs/p2p/host/basic" - inet "github.com/ipfs/go-ipfs/p2p/net" - swarm "github.com/ipfs/go-ipfs/p2p/net/swarm" - peer "github.com/ipfs/go-ipfs/p2p/peer" - tu "github.com/ipfs/go-ipfs/util/testutil" - - ma "github.com/ipfs/go-ipfs/Godeps/_workspace/src/github.com/jbenet/go-multiaddr" - context "github.com/ipfs/go-ipfs/Godeps/_workspace/src/golang.org/x/net/context" -) - -func GenSwarmNetwork(t *testing.T, ctx context.Context) *swarm.Network { - p := tu.RandPeerNetParamsOrFatal(t) - ps := peer.NewPeerstore() - ps.AddPubKey(p.ID, p.PubKey) - ps.AddPrivKey(p.ID, p.PrivKey) - n, err := swarm.NewNetwork(ctx, []ma.Multiaddr{p.Addr}, p.ID, ps, metrics.NewBandwidthCounter()) - if err != nil { - t.Fatal(err) - } - ps.AddAddrs(p.ID, n.ListenAddresses(), peer.PermanentAddrTTL) - return n -} - -func DivulgeAddresses(a, b inet.Network) { - id := a.LocalPeer() - addrs := a.Peerstore().Addrs(id) - b.Peerstore().AddAddrs(id, addrs, peer.PermanentAddrTTL) -} - -func GenHostSwarm(t *testing.T, ctx context.Context) *bhost.BasicHost { - n := GenSwarmNetwork(t, ctx) - return bhost.New(n) -} - -var RandPeerID = tu.RandPeerID diff --git a/package.json b/package.json index 1d318a43e4f..751db38d5ae 100644 --- a/package.json +++ b/package.json @@ -1,18 +1,18 @@ { "name": "go-ipfs", - "version": "0.3.8", + "version": "0.4.0", "gxDependencies": [ { "name": "go-log", - "hash": "QmQg1J6vikuXF9oDvm4wpdeAUvvkVEKW1EYDw9HhTMnP2b", + "hash": "Qmazh5oNUVsDZTs2g59rq8aYQqwpss8tcUWQzor5sCCEuH", "version": "1.0.0" }, { - "name": "dir-index-html", - "hash": "QmdDfkqDWheE4gsCXNrhixwTwSHnZMPT2cGLcNbiBNcMyU", - "version": "1.0.0", - "linkname": "dir-index-html-v1.0.0" + "name": "go-libp2p", + "hash": "QmUBogf4nUefBjmYjn6jfsfPJRkmDGSeMhNj4usRKq69f4", + "version": "1.0.0" } ], - "language": "go" + "language": "go", + "issues_url": "https://github.com/ipfs/go-ipfs" } \ No newline at end of file diff --git a/path/resolver.go b/path/resolver.go index 4ed7b67e94c..569a4d1be72 100644 --- a/path/resolver.go +++ b/path/resolver.go @@ -7,11 +7,11 @@ import ( "time" mh "github.com/ipfs/go-ipfs/Godeps/_workspace/src/github.com/jbenet/go-multihash" - "github.com/ipfs/go-ipfs/Godeps/_workspace/src/golang.org/x/net/context" + "gx/ipfs/QmZy2y8t9zQH2a1b8q2ZSLKp17ATuJoCNxxyMFG5qFExpt/go-net/context" key "github.com/ipfs/go-ipfs/blocks/key" merkledag "github.com/ipfs/go-ipfs/merkledag" - logging "github.com/ipfs/go-ipfs/vendor/QmQg1J6vikuXF9oDvm4wpdeAUvvkVEKW1EYDw9HhTMnP2b/go-log" + logging "gx/ipfs/Qmazh5oNUVsDZTs2g59rq8aYQqwpss8tcUWQzor5sCCEuH/go-log" ) var log = logging.Logger("path") diff --git a/path/resolver_test.go b/path/resolver_test.go index c0342fd6217..9ebb3f7a95c 100644 --- a/path/resolver_test.go +++ b/path/resolver_test.go @@ -4,7 +4,7 @@ import ( "fmt" "testing" - context "github.com/ipfs/go-ipfs/Godeps/_workspace/src/golang.org/x/net/context" + context "gx/ipfs/QmZy2y8t9zQH2a1b8q2ZSLKp17ATuJoCNxxyMFG5qFExpt/go-net/context" key "github.com/ipfs/go-ipfs/blocks/key" merkledag "github.com/ipfs/go-ipfs/merkledag" diff --git a/pin/gc/gc.go b/pin/gc/gc.go index 5cf35fb7e8f..695da62ec88 100644 --- a/pin/gc/gc.go +++ b/pin/gc/gc.go @@ -8,8 +8,8 @@ import ( dag "github.com/ipfs/go-ipfs/merkledag" pin "github.com/ipfs/go-ipfs/pin" - context "github.com/ipfs/go-ipfs/Godeps/_workspace/src/golang.org/x/net/context" - logging "github.com/ipfs/go-ipfs/vendor/QmQg1J6vikuXF9oDvm4wpdeAUvvkVEKW1EYDw9HhTMnP2b/go-log" + context "gx/ipfs/QmZy2y8t9zQH2a1b8q2ZSLKp17ATuJoCNxxyMFG5qFExpt/go-net/context" + logging "gx/ipfs/Qmazh5oNUVsDZTs2g59rq8aYQqwpss8tcUWQzor5sCCEuH/go-log" ) var log = logging.Logger("gc") diff --git a/pin/pin.go b/pin/pin.go index 86b0d58daa8..fb6269d3ebe 100644 --- a/pin/pin.go +++ b/pin/pin.go @@ -8,11 +8,11 @@ import ( "time" ds "github.com/ipfs/go-ipfs/Godeps/_workspace/src/github.com/ipfs/go-datastore" - context "github.com/ipfs/go-ipfs/Godeps/_workspace/src/golang.org/x/net/context" key "github.com/ipfs/go-ipfs/blocks/key" "github.com/ipfs/go-ipfs/blocks/set" mdag "github.com/ipfs/go-ipfs/merkledag" - logging "github.com/ipfs/go-ipfs/vendor/QmQg1J6vikuXF9oDvm4wpdeAUvvkVEKW1EYDw9HhTMnP2b/go-log" + context "gx/ipfs/QmZy2y8t9zQH2a1b8q2ZSLKp17ATuJoCNxxyMFG5qFExpt/go-net/context" + logging "gx/ipfs/Qmazh5oNUVsDZTs2g59rq8aYQqwpss8tcUWQzor5sCCEuH/go-log" ) var log = logging.Logger("pin") diff --git a/pin/pin_test.go b/pin/pin_test.go index 9356d3101c9..5dd9c45cfd3 100644 --- a/pin/pin_test.go +++ b/pin/pin_test.go @@ -4,7 +4,7 @@ import ( "testing" "time" - context "github.com/ipfs/go-ipfs/Godeps/_workspace/src/golang.org/x/net/context" + context "gx/ipfs/QmZy2y8t9zQH2a1b8q2ZSLKp17ATuJoCNxxyMFG5qFExpt/go-net/context" ds "github.com/ipfs/go-ipfs/Godeps/_workspace/src/github.com/ipfs/go-datastore" dssync "github.com/ipfs/go-ipfs/Godeps/_workspace/src/github.com/ipfs/go-datastore/sync" diff --git a/pin/set.go b/pin/set.go index 71851af6eda..a07762a3195 100644 --- a/pin/set.go +++ b/pin/set.go @@ -12,10 +12,10 @@ import ( "unsafe" "github.com/ipfs/go-ipfs/Godeps/_workspace/src/github.com/gogo/protobuf/proto" - "github.com/ipfs/go-ipfs/Godeps/_workspace/src/golang.org/x/net/context" "github.com/ipfs/go-ipfs/blocks/key" "github.com/ipfs/go-ipfs/merkledag" "github.com/ipfs/go-ipfs/pin/internal/pb" + "gx/ipfs/QmZy2y8t9zQH2a1b8q2ZSLKp17ATuJoCNxxyMFG5qFExpt/go-net/context" ) const ( diff --git a/pin/set_test.go b/pin/set_test.go index b076c41466b..3ef7ce51ba0 100644 --- a/pin/set_test.go +++ b/pin/set_test.go @@ -6,12 +6,12 @@ import ( "github.com/ipfs/go-ipfs/Godeps/_workspace/src/github.com/ipfs/go-datastore" dssync "github.com/ipfs/go-ipfs/Godeps/_workspace/src/github.com/ipfs/go-datastore/sync" - "github.com/ipfs/go-ipfs/Godeps/_workspace/src/golang.org/x/net/context" "github.com/ipfs/go-ipfs/blocks/blockstore" "github.com/ipfs/go-ipfs/blocks/key" "github.com/ipfs/go-ipfs/blockservice" "github.com/ipfs/go-ipfs/exchange/offline" "github.com/ipfs/go-ipfs/merkledag" + "gx/ipfs/QmZy2y8t9zQH2a1b8q2ZSLKp17ATuJoCNxxyMFG5qFExpt/go-net/context" ) func ignoreKeys(key.Key) {} diff --git a/repo/config/config.go b/repo/config/config.go index d8f5720e58d..76280256164 100644 --- a/repo/config/config.go +++ b/repo/config/config.go @@ -10,7 +10,7 @@ import ( "strings" u "github.com/ipfs/go-ipfs/util" - logging "github.com/ipfs/go-ipfs/vendor/QmQg1J6vikuXF9oDvm4wpdeAUvvkVEKW1EYDw9HhTMnP2b/go-log" + logging "gx/ipfs/Qmazh5oNUVsDZTs2g59rq8aYQqwpss8tcUWQzor5sCCEuH/go-log" ) var log = logging.Logger("config") diff --git a/repo/config/identity.go b/repo/config/identity.go index d2298fbcd86..e09bedcdf80 100644 --- a/repo/config/identity.go +++ b/repo/config/identity.go @@ -2,7 +2,7 @@ package config import ( "encoding/base64" - ic "github.com/ipfs/go-ipfs/p2p/crypto" + ic "gx/ipfs/QmUBogf4nUefBjmYjn6jfsfPJRkmDGSeMhNj4usRKq69f4/go-libp2p/p2p/crypto" ) // Identity tracks the configuration of the local node's identity. diff --git a/repo/config/init.go b/repo/config/init.go index 1835833c568..9bb7b4e0556 100644 --- a/repo/config/init.go +++ b/repo/config/init.go @@ -6,8 +6,8 @@ import ( "fmt" "io" - ci "github.com/ipfs/go-ipfs/p2p/crypto" - peer "github.com/ipfs/go-ipfs/p2p/peer" + ci "gx/ipfs/QmUBogf4nUefBjmYjn6jfsfPJRkmDGSeMhNj4usRKq69f4/go-libp2p/p2p/crypto" + peer "gx/ipfs/QmUBogf4nUefBjmYjn6jfsfPJRkmDGSeMhNj4usRKq69f4/go-libp2p/p2p/peer" ) func Init(out io.Writer, nBitsForKeypair int) (*Config, error) { diff --git a/repo/fsrepo/fsrepo.go b/repo/fsrepo/fsrepo.go index 8c551e2fd2a..356e33cd191 100644 --- a/repo/fsrepo/fsrepo.go +++ b/repo/fsrepo/fsrepo.go @@ -20,7 +20,7 @@ import ( serialize "github.com/ipfs/go-ipfs/repo/fsrepo/serialize" dir "github.com/ipfs/go-ipfs/thirdparty/dir" util "github.com/ipfs/go-ipfs/util" - logging "github.com/ipfs/go-ipfs/vendor/QmQg1J6vikuXF9oDvm4wpdeAUvvkVEKW1EYDw9HhTMnP2b/go-log" + logging "gx/ipfs/Qmazh5oNUVsDZTs2g59rq8aYQqwpss8tcUWQzor5sCCEuH/go-log" ) var log = logging.Logger("fsrepo") diff --git a/repo/fsrepo/serialize/serialize.go b/repo/fsrepo/serialize/serialize.go index 52186cc23c1..64e897b78c9 100644 --- a/repo/fsrepo/serialize/serialize.go +++ b/repo/fsrepo/serialize/serialize.go @@ -11,7 +11,7 @@ import ( "github.com/ipfs/go-ipfs/Godeps/_workspace/src/github.com/facebookgo/atomicfile" "github.com/ipfs/go-ipfs/repo/config" "github.com/ipfs/go-ipfs/util" - logging "github.com/ipfs/go-ipfs/vendor/QmQg1J6vikuXF9oDvm4wpdeAUvvkVEKW1EYDw9HhTMnP2b/go-log" + logging "gx/ipfs/Qmazh5oNUVsDZTs2g59rq8aYQqwpss8tcUWQzor5sCCEuH/go-log" ) var log = logging.Logger("fsrepo") diff --git a/routing/dht/dht.go b/routing/dht/dht.go index 31979aa8b89..eadd5b4be39 100644 --- a/routing/dht/dht.go +++ b/routing/dht/dht.go @@ -10,21 +10,21 @@ import ( "time" key "github.com/ipfs/go-ipfs/blocks/key" - ci "github.com/ipfs/go-ipfs/p2p/crypto" - host "github.com/ipfs/go-ipfs/p2p/host" - peer "github.com/ipfs/go-ipfs/p2p/peer" - protocol "github.com/ipfs/go-ipfs/p2p/protocol" routing "github.com/ipfs/go-ipfs/routing" pb "github.com/ipfs/go-ipfs/routing/dht/pb" kb "github.com/ipfs/go-ipfs/routing/kbucket" record "github.com/ipfs/go-ipfs/routing/record" - logging "github.com/ipfs/go-ipfs/vendor/QmQg1J6vikuXF9oDvm4wpdeAUvvkVEKW1EYDw9HhTMnP2b/go-log" + ci "gx/ipfs/QmUBogf4nUefBjmYjn6jfsfPJRkmDGSeMhNj4usRKq69f4/go-libp2p/p2p/crypto" + host "gx/ipfs/QmUBogf4nUefBjmYjn6jfsfPJRkmDGSeMhNj4usRKq69f4/go-libp2p/p2p/host" + peer "gx/ipfs/QmUBogf4nUefBjmYjn6jfsfPJRkmDGSeMhNj4usRKq69f4/go-libp2p/p2p/peer" + protocol "gx/ipfs/QmUBogf4nUefBjmYjn6jfsfPJRkmDGSeMhNj4usRKq69f4/go-libp2p/p2p/protocol" + logging "gx/ipfs/Qmazh5oNUVsDZTs2g59rq8aYQqwpss8tcUWQzor5sCCEuH/go-log" proto "github.com/ipfs/go-ipfs/Godeps/_workspace/src/github.com/gogo/protobuf/proto" ds "github.com/ipfs/go-ipfs/Godeps/_workspace/src/github.com/ipfs/go-datastore" goprocess "github.com/ipfs/go-ipfs/Godeps/_workspace/src/github.com/jbenet/goprocess" goprocessctx "github.com/ipfs/go-ipfs/Godeps/_workspace/src/github.com/jbenet/goprocess/context" - context "github.com/ipfs/go-ipfs/Godeps/_workspace/src/golang.org/x/net/context" + context "gx/ipfs/QmZy2y8t9zQH2a1b8q2ZSLKp17ATuJoCNxxyMFG5qFExpt/go-net/context" ) var log = logging.Logger("dht") diff --git a/routing/dht/dht_bootstrap.go b/routing/dht/dht_bootstrap.go index 4a07d9f0ba6..3865bca13a0 100644 --- a/routing/dht/dht_bootstrap.go +++ b/routing/dht/dht_bootstrap.go @@ -8,13 +8,13 @@ import ( "sync" "time" - peer "github.com/ipfs/go-ipfs/p2p/peer" routing "github.com/ipfs/go-ipfs/routing" u "github.com/ipfs/go-ipfs/util" + peer "gx/ipfs/QmUBogf4nUefBjmYjn6jfsfPJRkmDGSeMhNj4usRKq69f4/go-libp2p/p2p/peer" goprocess "github.com/ipfs/go-ipfs/Godeps/_workspace/src/github.com/jbenet/goprocess" periodicproc "github.com/ipfs/go-ipfs/Godeps/_workspace/src/github.com/jbenet/goprocess/periodic" - context "github.com/ipfs/go-ipfs/Godeps/_workspace/src/golang.org/x/net/context" + context "gx/ipfs/QmZy2y8t9zQH2a1b8q2ZSLKp17ATuJoCNxxyMFG5qFExpt/go-net/context" ) // BootstrapConfig specifies parameters used bootstrapping the DHT. diff --git a/routing/dht/dht_net.go b/routing/dht/dht_net.go index 722ece7ea28..e88a94dc6b8 100644 --- a/routing/dht/dht_net.go +++ b/routing/dht/dht_net.go @@ -6,10 +6,10 @@ import ( ggio "github.com/ipfs/go-ipfs/Godeps/_workspace/src/github.com/gogo/protobuf/io" ctxio "github.com/ipfs/go-ipfs/Godeps/_workspace/src/github.com/jbenet/go-context/io" - context "github.com/ipfs/go-ipfs/Godeps/_workspace/src/golang.org/x/net/context" - inet "github.com/ipfs/go-ipfs/p2p/net" - peer "github.com/ipfs/go-ipfs/p2p/peer" pb "github.com/ipfs/go-ipfs/routing/dht/pb" + inet "gx/ipfs/QmUBogf4nUefBjmYjn6jfsfPJRkmDGSeMhNj4usRKq69f4/go-libp2p/p2p/net" + peer "gx/ipfs/QmUBogf4nUefBjmYjn6jfsfPJRkmDGSeMhNj4usRKq69f4/go-libp2p/p2p/peer" + context "gx/ipfs/QmZy2y8t9zQH2a1b8q2ZSLKp17ATuJoCNxxyMFG5qFExpt/go-net/context" ) // handleNewStream implements the inet.StreamHandler @@ -71,7 +71,7 @@ func (dht *IpfsDHT) handleNewMessage(s inet.Stream) { func (dht *IpfsDHT) sendRequest(ctx context.Context, p peer.ID, pmes *pb.Message) (*pb.Message, error) { log.Debugf("%s dht starting stream", dht.self) - s, err := dht.host.NewStream(ProtocolDHT, p) + s, err := dht.host.NewStream(ctx, ProtocolDHT, p) if err != nil { return nil, err } @@ -109,7 +109,7 @@ func (dht *IpfsDHT) sendRequest(ctx context.Context, p peer.ID, pmes *pb.Message func (dht *IpfsDHT) sendMessage(ctx context.Context, p peer.ID, pmes *pb.Message) error { log.Debugf("%s dht starting stream", dht.self) - s, err := dht.host.NewStream(ProtocolDHT, p) + s, err := dht.host.NewStream(ctx, ProtocolDHT, p) if err != nil { return err } diff --git a/routing/dht/dht_test.go b/routing/dht/dht_test.go index 32560c59f85..55ed11c55ca 100644 --- a/routing/dht/dht_test.go +++ b/routing/dht/dht_test.go @@ -11,15 +11,15 @@ import ( ds "github.com/ipfs/go-ipfs/Godeps/_workspace/src/github.com/ipfs/go-datastore" dssync "github.com/ipfs/go-ipfs/Godeps/_workspace/src/github.com/ipfs/go-datastore/sync" - ma "github.com/ipfs/go-ipfs/Godeps/_workspace/src/github.com/jbenet/go-multiaddr" - context "github.com/ipfs/go-ipfs/Godeps/_workspace/src/golang.org/x/net/context" + ma "gx/ipfs/QmR3JkmZBKYXgNMNsNZawm914455Qof3PEopwuVSeXG7aV/go-multiaddr" + context "gx/ipfs/QmZy2y8t9zQH2a1b8q2ZSLKp17ATuJoCNxxyMFG5qFExpt/go-net/context" key "github.com/ipfs/go-ipfs/blocks/key" - peer "github.com/ipfs/go-ipfs/p2p/peer" - netutil "github.com/ipfs/go-ipfs/p2p/test/util" routing "github.com/ipfs/go-ipfs/routing" record "github.com/ipfs/go-ipfs/routing/record" u "github.com/ipfs/go-ipfs/util" + peer "gx/ipfs/QmUBogf4nUefBjmYjn6jfsfPJRkmDGSeMhNj4usRKq69f4/go-libp2p/p2p/peer" + netutil "gx/ipfs/QmUBogf4nUefBjmYjn6jfsfPJRkmDGSeMhNj4usRKq69f4/go-libp2p/p2p/test/util" ci "github.com/ipfs/go-ipfs/util/testutil/ci" travisci "github.com/ipfs/go-ipfs/util/testutil/ci/travis" diff --git a/routing/dht/diag.go b/routing/dht/diag.go index a7a632c3e8c..3f8a7a92921 100644 --- a/routing/dht/diag.go +++ b/routing/dht/diag.go @@ -4,7 +4,7 @@ import ( "encoding/json" "time" - peer "github.com/ipfs/go-ipfs/p2p/peer" + peer "gx/ipfs/QmUBogf4nUefBjmYjn6jfsfPJRkmDGSeMhNj4usRKq69f4/go-libp2p/p2p/peer" ) type connDiagInfo struct { diff --git a/routing/dht/ext_test.go b/routing/dht/ext_test.go index a770a0962dd..adff49c90cb 100644 --- a/routing/dht/ext_test.go +++ b/routing/dht/ext_test.go @@ -10,16 +10,16 @@ import ( ggio "github.com/ipfs/go-ipfs/Godeps/_workspace/src/github.com/gogo/protobuf/io" ds "github.com/ipfs/go-ipfs/Godeps/_workspace/src/github.com/ipfs/go-datastore" dssync "github.com/ipfs/go-ipfs/Godeps/_workspace/src/github.com/ipfs/go-datastore/sync" - context "github.com/ipfs/go-ipfs/Godeps/_workspace/src/golang.org/x/net/context" + context "gx/ipfs/QmZy2y8t9zQH2a1b8q2ZSLKp17ATuJoCNxxyMFG5qFExpt/go-net/context" key "github.com/ipfs/go-ipfs/blocks/key" - inet "github.com/ipfs/go-ipfs/p2p/net" - mocknet "github.com/ipfs/go-ipfs/p2p/net/mock" - peer "github.com/ipfs/go-ipfs/p2p/peer" routing "github.com/ipfs/go-ipfs/routing" pb "github.com/ipfs/go-ipfs/routing/dht/pb" record "github.com/ipfs/go-ipfs/routing/record" u "github.com/ipfs/go-ipfs/util" + inet "gx/ipfs/QmUBogf4nUefBjmYjn6jfsfPJRkmDGSeMhNj4usRKq69f4/go-libp2p/p2p/net" + mocknet "gx/ipfs/QmUBogf4nUefBjmYjn6jfsfPJRkmDGSeMhNj4usRKq69f4/go-libp2p/p2p/net/mock" + peer "gx/ipfs/QmUBogf4nUefBjmYjn6jfsfPJRkmDGSeMhNj4usRKq69f4/go-libp2p/p2p/peer" ) func TestGetFailures(t *testing.T) { @@ -120,7 +120,7 @@ func TestGetFailures(t *testing.T) { Record: rec, } - s, err := hosts[1].NewStream(ProtocolDHT, hosts[0].ID()) + s, err := hosts[1].NewStream(context.Background(), ProtocolDHT, hosts[0].ID()) if err != nil { t.Fatal(err) } diff --git a/routing/dht/handlers.go b/routing/dht/handlers.go index 121f7623b10..265ff49f916 100644 --- a/routing/dht/handlers.go +++ b/routing/dht/handlers.go @@ -7,12 +7,12 @@ import ( proto "github.com/ipfs/go-ipfs/Godeps/_workspace/src/github.com/gogo/protobuf/proto" ds "github.com/ipfs/go-ipfs/Godeps/_workspace/src/github.com/ipfs/go-datastore" - context "github.com/ipfs/go-ipfs/Godeps/_workspace/src/golang.org/x/net/context" key "github.com/ipfs/go-ipfs/blocks/key" - peer "github.com/ipfs/go-ipfs/p2p/peer" pb "github.com/ipfs/go-ipfs/routing/dht/pb" u "github.com/ipfs/go-ipfs/util" lgbl "github.com/ipfs/go-ipfs/util/eventlog/loggables" + peer "gx/ipfs/QmUBogf4nUefBjmYjn6jfsfPJRkmDGSeMhNj4usRKq69f4/go-libp2p/p2p/peer" + context "gx/ipfs/QmZy2y8t9zQH2a1b8q2ZSLKp17ATuJoCNxxyMFG5qFExpt/go-net/context" ) // The number of closer peers to send on requests. diff --git a/routing/dht/lookup.go b/routing/dht/lookup.go index dc377e8b7f0..140fcae213e 100644 --- a/routing/dht/lookup.go +++ b/routing/dht/lookup.go @@ -1,12 +1,12 @@ package dht import ( - context "github.com/ipfs/go-ipfs/Godeps/_workspace/src/golang.org/x/net/context" key "github.com/ipfs/go-ipfs/blocks/key" notif "github.com/ipfs/go-ipfs/notifications" - peer "github.com/ipfs/go-ipfs/p2p/peer" kb "github.com/ipfs/go-ipfs/routing/kbucket" pset "github.com/ipfs/go-ipfs/util/peerset" + peer "gx/ipfs/QmUBogf4nUefBjmYjn6jfsfPJRkmDGSeMhNj4usRKq69f4/go-libp2p/p2p/peer" + context "gx/ipfs/QmZy2y8t9zQH2a1b8q2ZSLKp17ATuJoCNxxyMFG5qFExpt/go-net/context" ) // Required in order for proper JSON marshaling diff --git a/routing/dht/notif.go b/routing/dht/notif.go index cfe411c38ee..2fe6cce4042 100644 --- a/routing/dht/notif.go +++ b/routing/dht/notif.go @@ -1,9 +1,9 @@ package dht import ( - ma "github.com/ipfs/go-ipfs/Godeps/_workspace/src/github.com/jbenet/go-multiaddr" + ma "gx/ipfs/QmR3JkmZBKYXgNMNsNZawm914455Qof3PEopwuVSeXG7aV/go-multiaddr" - inet "github.com/ipfs/go-ipfs/p2p/net" + inet "gx/ipfs/QmUBogf4nUefBjmYjn6jfsfPJRkmDGSeMhNj4usRKq69f4/go-libp2p/p2p/net" ) // netNotifiee defines methods to be used with the IpfsDHT diff --git a/routing/dht/pb/message.go b/routing/dht/pb/message.go index f780b1b057c..a1c4887e11c 100644 --- a/routing/dht/pb/message.go +++ b/routing/dht/pb/message.go @@ -1,12 +1,12 @@ package dht_pb import ( - ma "github.com/ipfs/go-ipfs/Godeps/_workspace/src/github.com/jbenet/go-multiaddr" + ma "gx/ipfs/QmR3JkmZBKYXgNMNsNZawm914455Qof3PEopwuVSeXG7aV/go-multiaddr" key "github.com/ipfs/go-ipfs/blocks/key" - inet "github.com/ipfs/go-ipfs/p2p/net" - peer "github.com/ipfs/go-ipfs/p2p/peer" - logging "github.com/ipfs/go-ipfs/vendor/QmQg1J6vikuXF9oDvm4wpdeAUvvkVEKW1EYDw9HhTMnP2b/go-log" + inet "gx/ipfs/QmUBogf4nUefBjmYjn6jfsfPJRkmDGSeMhNj4usRKq69f4/go-libp2p/p2p/net" + peer "gx/ipfs/QmUBogf4nUefBjmYjn6jfsfPJRkmDGSeMhNj4usRKq69f4/go-libp2p/p2p/peer" + logging "gx/ipfs/Qmazh5oNUVsDZTs2g59rq8aYQqwpss8tcUWQzor5sCCEuH/go-log" ) var log = logging.Logger("dht.pb") diff --git a/routing/dht/providers.go b/routing/dht/providers.go index 17455b33682..c0c16c54e09 100644 --- a/routing/dht/providers.go +++ b/routing/dht/providers.go @@ -6,9 +6,9 @@ import ( "github.com/ipfs/go-ipfs/Godeps/_workspace/src/github.com/jbenet/goprocess" goprocessctx "github.com/ipfs/go-ipfs/Godeps/_workspace/src/github.com/jbenet/goprocess/context" key "github.com/ipfs/go-ipfs/blocks/key" - peer "github.com/ipfs/go-ipfs/p2p/peer" + peer "gx/ipfs/QmUBogf4nUefBjmYjn6jfsfPJRkmDGSeMhNj4usRKq69f4/go-libp2p/p2p/peer" - context "github.com/ipfs/go-ipfs/Godeps/_workspace/src/golang.org/x/net/context" + context "gx/ipfs/QmZy2y8t9zQH2a1b8q2ZSLKp17ATuJoCNxxyMFG5qFExpt/go-net/context" ) type ProviderManager struct { diff --git a/routing/dht/providers_test.go b/routing/dht/providers_test.go index 7e2e47d9334..ec3b7a5d1fa 100644 --- a/routing/dht/providers_test.go +++ b/routing/dht/providers_test.go @@ -4,9 +4,9 @@ import ( "testing" key "github.com/ipfs/go-ipfs/blocks/key" - peer "github.com/ipfs/go-ipfs/p2p/peer" + peer "gx/ipfs/QmUBogf4nUefBjmYjn6jfsfPJRkmDGSeMhNj4usRKq69f4/go-libp2p/p2p/peer" - context "github.com/ipfs/go-ipfs/Godeps/_workspace/src/golang.org/x/net/context" + context "gx/ipfs/QmZy2y8t9zQH2a1b8q2ZSLKp17ATuJoCNxxyMFG5qFExpt/go-net/context" ) func TestProviderManager(t *testing.T) { diff --git a/routing/dht/query.go b/routing/dht/query.go index d64e432ea54..53e75fecbce 100644 --- a/routing/dht/query.go +++ b/routing/dht/query.go @@ -5,17 +5,17 @@ import ( key "github.com/ipfs/go-ipfs/blocks/key" notif "github.com/ipfs/go-ipfs/notifications" - peer "github.com/ipfs/go-ipfs/p2p/peer" - queue "github.com/ipfs/go-ipfs/p2p/peer/queue" "github.com/ipfs/go-ipfs/routing" u "github.com/ipfs/go-ipfs/util" pset "github.com/ipfs/go-ipfs/util/peerset" todoctr "github.com/ipfs/go-ipfs/util/todocounter" - logging "github.com/ipfs/go-ipfs/vendor/QmQg1J6vikuXF9oDvm4wpdeAUvvkVEKW1EYDw9HhTMnP2b/go-log" + peer "gx/ipfs/QmUBogf4nUefBjmYjn6jfsfPJRkmDGSeMhNj4usRKq69f4/go-libp2p/p2p/peer" + queue "gx/ipfs/QmUBogf4nUefBjmYjn6jfsfPJRkmDGSeMhNj4usRKq69f4/go-libp2p/p2p/peer/queue" + logging "gx/ipfs/Qmazh5oNUVsDZTs2g59rq8aYQqwpss8tcUWQzor5sCCEuH/go-log" process "github.com/ipfs/go-ipfs/Godeps/_workspace/src/github.com/jbenet/goprocess" ctxproc "github.com/ipfs/go-ipfs/Godeps/_workspace/src/github.com/jbenet/goprocess/context" - context "github.com/ipfs/go-ipfs/Godeps/_workspace/src/golang.org/x/net/context" + context "gx/ipfs/QmZy2y8t9zQH2a1b8q2ZSLKp17ATuJoCNxxyMFG5qFExpt/go-net/context" ) var maxQueryConcurrency = AlphaValue @@ -90,7 +90,7 @@ func newQueryRunner(q *dhtQuery) *dhtQueryRunner { ctx := ctxproc.OnClosingContext(proc) return &dhtQueryRunner{ query: q, - peersToQuery: queue.NewChanQueue(ctx, queue.NewXORDistancePQ(q.key)), + peersToQuery: queue.NewChanQueue(ctx, queue.NewXORDistancePQ(string(q.key))), peersRemaining: todoctr.NewSyncCounter(), peersSeen: pset.New(), rateLimit: make(chan struct{}, q.concurrency), diff --git a/routing/dht/records.go b/routing/dht/records.go index 49a06d55744..06a4e70b16e 100644 --- a/routing/dht/records.go +++ b/routing/dht/records.go @@ -5,12 +5,12 @@ import ( "time" ctxfrac "github.com/ipfs/go-ipfs/Godeps/_workspace/src/github.com/jbenet/go-context/frac" - "github.com/ipfs/go-ipfs/Godeps/_workspace/src/golang.org/x/net/context" - ci "github.com/ipfs/go-ipfs/p2p/crypto" - peer "github.com/ipfs/go-ipfs/p2p/peer" routing "github.com/ipfs/go-ipfs/routing" pb "github.com/ipfs/go-ipfs/routing/dht/pb" record "github.com/ipfs/go-ipfs/routing/record" + ci "gx/ipfs/QmUBogf4nUefBjmYjn6jfsfPJRkmDGSeMhNj4usRKq69f4/go-libp2p/p2p/crypto" + peer "gx/ipfs/QmUBogf4nUefBjmYjn6jfsfPJRkmDGSeMhNj4usRKq69f4/go-libp2p/p2p/peer" + "gx/ipfs/QmZy2y8t9zQH2a1b8q2ZSLKp17ATuJoCNxxyMFG5qFExpt/go-net/context" ) // MaxRecordAge specifies the maximum time that any node will hold onto a record diff --git a/routing/dht/routing.go b/routing/dht/routing.go index 627c936078c..e0feda4ec89 100644 --- a/routing/dht/routing.go +++ b/routing/dht/routing.go @@ -5,16 +5,16 @@ import ( "sync" "time" - context "github.com/ipfs/go-ipfs/Godeps/_workspace/src/golang.org/x/net/context" key "github.com/ipfs/go-ipfs/blocks/key" notif "github.com/ipfs/go-ipfs/notifications" - inet "github.com/ipfs/go-ipfs/p2p/net" - peer "github.com/ipfs/go-ipfs/p2p/peer" "github.com/ipfs/go-ipfs/routing" pb "github.com/ipfs/go-ipfs/routing/dht/pb" kb "github.com/ipfs/go-ipfs/routing/kbucket" record "github.com/ipfs/go-ipfs/routing/record" pset "github.com/ipfs/go-ipfs/util/peerset" + inet "gx/ipfs/QmUBogf4nUefBjmYjn6jfsfPJRkmDGSeMhNj4usRKq69f4/go-libp2p/p2p/net" + peer "gx/ipfs/QmUBogf4nUefBjmYjn6jfsfPJRkmDGSeMhNj4usRKq69f4/go-libp2p/p2p/peer" + context "gx/ipfs/QmZy2y8t9zQH2a1b8q2ZSLKp17ATuJoCNxxyMFG5qFExpt/go-net/context" ) // asyncQueryBuffer is the size of buffered channels in async queries. This diff --git a/routing/kbucket/bucket.go b/routing/kbucket/bucket.go index 35ceed385ed..8924a63d4d5 100644 --- a/routing/kbucket/bucket.go +++ b/routing/kbucket/bucket.go @@ -4,7 +4,7 @@ import ( "container/list" "sync" - peer "github.com/ipfs/go-ipfs/p2p/peer" + peer "gx/ipfs/QmUBogf4nUefBjmYjn6jfsfPJRkmDGSeMhNj4usRKq69f4/go-libp2p/p2p/peer" ) // Bucket holds a list of peers. diff --git a/routing/kbucket/sorting.go b/routing/kbucket/sorting.go index 875b822615c..e1e0a1bbfc8 100644 --- a/routing/kbucket/sorting.go +++ b/routing/kbucket/sorting.go @@ -2,7 +2,7 @@ package kbucket import ( "container/list" - peer "github.com/ipfs/go-ipfs/p2p/peer" + peer "gx/ipfs/QmUBogf4nUefBjmYjn6jfsfPJRkmDGSeMhNj4usRKq69f4/go-libp2p/p2p/peer" "sort" ) diff --git a/routing/kbucket/table.go b/routing/kbucket/table.go index d4cf051f330..5128b7821d1 100644 --- a/routing/kbucket/table.go +++ b/routing/kbucket/table.go @@ -7,8 +7,8 @@ import ( "sync" "time" - peer "github.com/ipfs/go-ipfs/p2p/peer" - logging "github.com/ipfs/go-ipfs/vendor/QmQg1J6vikuXF9oDvm4wpdeAUvvkVEKW1EYDw9HhTMnP2b/go-log" + peer "gx/ipfs/QmUBogf4nUefBjmYjn6jfsfPJRkmDGSeMhNj4usRKq69f4/go-libp2p/p2p/peer" + logging "gx/ipfs/Qmazh5oNUVsDZTs2g59rq8aYQqwpss8tcUWQzor5sCCEuH/go-log" ) var log = logging.Logger("table") diff --git a/routing/kbucket/table_test.go b/routing/kbucket/table_test.go index e5b01cc721c..13f02df897f 100644 --- a/routing/kbucket/table_test.go +++ b/routing/kbucket/table_test.go @@ -7,7 +7,7 @@ import ( tu "github.com/ipfs/go-ipfs/util/testutil" - peer "github.com/ipfs/go-ipfs/p2p/peer" + peer "gx/ipfs/QmUBogf4nUefBjmYjn6jfsfPJRkmDGSeMhNj4usRKq69f4/go-libp2p/p2p/peer" ) // Test basic features of the bucket struct diff --git a/routing/kbucket/util.go b/routing/kbucket/util.go index e37a701830c..73602d185d5 100644 --- a/routing/kbucket/util.go +++ b/routing/kbucket/util.go @@ -6,9 +6,9 @@ import ( "errors" key "github.com/ipfs/go-ipfs/blocks/key" - peer "github.com/ipfs/go-ipfs/p2p/peer" ks "github.com/ipfs/go-ipfs/routing/keyspace" u "github.com/ipfs/go-ipfs/util" + peer "gx/ipfs/QmUBogf4nUefBjmYjn6jfsfPJRkmDGSeMhNj4usRKq69f4/go-libp2p/p2p/peer" ) // Returned if a routing table query returns no results. This is NOT expected diff --git a/routing/mock/centralized_client.go b/routing/mock/centralized_client.go index f360f9a8ae1..407f0c09424 100644 --- a/routing/mock/centralized_client.go +++ b/routing/mock/centralized_client.go @@ -6,15 +6,15 @@ import ( proto "github.com/ipfs/go-ipfs/Godeps/_workspace/src/github.com/gogo/protobuf/proto" ds "github.com/ipfs/go-ipfs/Godeps/_workspace/src/github.com/ipfs/go-datastore" - ma "github.com/ipfs/go-ipfs/Godeps/_workspace/src/github.com/jbenet/go-multiaddr" - context "github.com/ipfs/go-ipfs/Godeps/_workspace/src/golang.org/x/net/context" key "github.com/ipfs/go-ipfs/blocks/key" - peer "github.com/ipfs/go-ipfs/p2p/peer" routing "github.com/ipfs/go-ipfs/routing" dhtpb "github.com/ipfs/go-ipfs/routing/dht/pb" u "github.com/ipfs/go-ipfs/util" "github.com/ipfs/go-ipfs/util/testutil" - logging "github.com/ipfs/go-ipfs/vendor/QmQg1J6vikuXF9oDvm4wpdeAUvvkVEKW1EYDw9HhTMnP2b/go-log" + ma "gx/ipfs/QmR3JkmZBKYXgNMNsNZawm914455Qof3PEopwuVSeXG7aV/go-multiaddr" + peer "gx/ipfs/QmUBogf4nUefBjmYjn6jfsfPJRkmDGSeMhNj4usRKq69f4/go-libp2p/p2p/peer" + context "gx/ipfs/QmZy2y8t9zQH2a1b8q2ZSLKp17ATuJoCNxxyMFG5qFExpt/go-net/context" + logging "gx/ipfs/Qmazh5oNUVsDZTs2g59rq8aYQqwpss8tcUWQzor5sCCEuH/go-log" ) var log = logging.Logger("mockrouter") diff --git a/routing/mock/centralized_server.go b/routing/mock/centralized_server.go index 075750c3ad6..8e8d5d0b217 100644 --- a/routing/mock/centralized_server.go +++ b/routing/mock/centralized_server.go @@ -6,10 +6,10 @@ import ( "time" ds "github.com/ipfs/go-ipfs/Godeps/_workspace/src/github.com/ipfs/go-datastore" - context "github.com/ipfs/go-ipfs/Godeps/_workspace/src/golang.org/x/net/context" key "github.com/ipfs/go-ipfs/blocks/key" - peer "github.com/ipfs/go-ipfs/p2p/peer" "github.com/ipfs/go-ipfs/util/testutil" + peer "gx/ipfs/QmUBogf4nUefBjmYjn6jfsfPJRkmDGSeMhNj4usRKq69f4/go-libp2p/p2p/peer" + context "gx/ipfs/QmZy2y8t9zQH2a1b8q2ZSLKp17ATuJoCNxxyMFG5qFExpt/go-net/context" ) // server is the mockrouting.Client's private interface to the routing server diff --git a/routing/mock/centralized_test.go b/routing/mock/centralized_test.go index a719570aa0a..d71b24c0bdd 100644 --- a/routing/mock/centralized_test.go +++ b/routing/mock/centralized_test.go @@ -4,11 +4,11 @@ import ( "testing" "time" - context "github.com/ipfs/go-ipfs/Godeps/_workspace/src/golang.org/x/net/context" key "github.com/ipfs/go-ipfs/blocks/key" - peer "github.com/ipfs/go-ipfs/p2p/peer" delay "github.com/ipfs/go-ipfs/thirdparty/delay" "github.com/ipfs/go-ipfs/util/testutil" + peer "gx/ipfs/QmUBogf4nUefBjmYjn6jfsfPJRkmDGSeMhNj4usRKq69f4/go-libp2p/p2p/peer" + context "gx/ipfs/QmZy2y8t9zQH2a1b8q2ZSLKp17ATuJoCNxxyMFG5qFExpt/go-net/context" ) func TestKeyNotFound(t *testing.T) { diff --git a/routing/mock/dht.go b/routing/mock/dht.go index fc3b876e7fd..99ef8ba8825 100644 --- a/routing/mock/dht.go +++ b/routing/mock/dht.go @@ -3,10 +3,10 @@ package mockrouting import ( ds "github.com/ipfs/go-ipfs/Godeps/_workspace/src/github.com/ipfs/go-datastore" sync "github.com/ipfs/go-ipfs/Godeps/_workspace/src/github.com/ipfs/go-datastore/sync" - context "github.com/ipfs/go-ipfs/Godeps/_workspace/src/golang.org/x/net/context" - mocknet "github.com/ipfs/go-ipfs/p2p/net/mock" dht "github.com/ipfs/go-ipfs/routing/dht" "github.com/ipfs/go-ipfs/util/testutil" + mocknet "gx/ipfs/QmUBogf4nUefBjmYjn6jfsfPJRkmDGSeMhNj4usRKq69f4/go-libp2p/p2p/net/mock" + context "gx/ipfs/QmZy2y8t9zQH2a1b8q2ZSLKp17ATuJoCNxxyMFG5qFExpt/go-net/context" ) type mocknetserver struct { diff --git a/routing/mock/interface.go b/routing/mock/interface.go index b16b99046f7..75daee9e96a 100644 --- a/routing/mock/interface.go +++ b/routing/mock/interface.go @@ -6,12 +6,12 @@ package mockrouting import ( ds "github.com/ipfs/go-ipfs/Godeps/_workspace/src/github.com/ipfs/go-datastore" - context "github.com/ipfs/go-ipfs/Godeps/_workspace/src/golang.org/x/net/context" key "github.com/ipfs/go-ipfs/blocks/key" - peer "github.com/ipfs/go-ipfs/p2p/peer" routing "github.com/ipfs/go-ipfs/routing" delay "github.com/ipfs/go-ipfs/thirdparty/delay" "github.com/ipfs/go-ipfs/util/testutil" + peer "gx/ipfs/QmUBogf4nUefBjmYjn6jfsfPJRkmDGSeMhNj4usRKq69f4/go-libp2p/p2p/peer" + context "gx/ipfs/QmZy2y8t9zQH2a1b8q2ZSLKp17ATuJoCNxxyMFG5qFExpt/go-net/context" ) // Server provides mockrouting Clients diff --git a/routing/none/none_client.go b/routing/none/none_client.go index 6d16a88bf73..1f7c9749f94 100644 --- a/routing/none/none_client.go +++ b/routing/none/none_client.go @@ -3,13 +3,13 @@ package nilrouting import ( "errors" - context "github.com/ipfs/go-ipfs/Godeps/_workspace/src/golang.org/x/net/context" key "github.com/ipfs/go-ipfs/blocks/key" - p2phost "github.com/ipfs/go-ipfs/p2p/host" - peer "github.com/ipfs/go-ipfs/p2p/peer" repo "github.com/ipfs/go-ipfs/repo" routing "github.com/ipfs/go-ipfs/routing" - logging "github.com/ipfs/go-ipfs/vendor/QmQg1J6vikuXF9oDvm4wpdeAUvvkVEKW1EYDw9HhTMnP2b/go-log" + p2phost "gx/ipfs/QmUBogf4nUefBjmYjn6jfsfPJRkmDGSeMhNj4usRKq69f4/go-libp2p/p2p/host" + peer "gx/ipfs/QmUBogf4nUefBjmYjn6jfsfPJRkmDGSeMhNj4usRKq69f4/go-libp2p/p2p/peer" + context "gx/ipfs/QmZy2y8t9zQH2a1b8q2ZSLKp17ATuJoCNxxyMFG5qFExpt/go-net/context" + logging "gx/ipfs/Qmazh5oNUVsDZTs2g59rq8aYQqwpss8tcUWQzor5sCCEuH/go-log" ) var log = logging.Logger("mockrouter") diff --git a/routing/offline/offline.go b/routing/offline/offline.go index 83775566c80..7e5f80275fb 100644 --- a/routing/offline/offline.go +++ b/routing/offline/offline.go @@ -6,14 +6,14 @@ import ( proto "github.com/ipfs/go-ipfs/Godeps/_workspace/src/github.com/gogo/protobuf/proto" ds "github.com/ipfs/go-ipfs/Godeps/_workspace/src/github.com/ipfs/go-datastore" - context "github.com/ipfs/go-ipfs/Godeps/_workspace/src/golang.org/x/net/context" key "github.com/ipfs/go-ipfs/blocks/key" - ci "github.com/ipfs/go-ipfs/p2p/crypto" - "github.com/ipfs/go-ipfs/p2p/peer" routing "github.com/ipfs/go-ipfs/routing" pb "github.com/ipfs/go-ipfs/routing/dht/pb" record "github.com/ipfs/go-ipfs/routing/record" - logging "github.com/ipfs/go-ipfs/vendor/QmQg1J6vikuXF9oDvm4wpdeAUvvkVEKW1EYDw9HhTMnP2b/go-log" + ci "gx/ipfs/QmUBogf4nUefBjmYjn6jfsfPJRkmDGSeMhNj4usRKq69f4/go-libp2p/p2p/crypto" + "gx/ipfs/QmUBogf4nUefBjmYjn6jfsfPJRkmDGSeMhNj4usRKq69f4/go-libp2p/p2p/peer" + context "gx/ipfs/QmZy2y8t9zQH2a1b8q2ZSLKp17ATuJoCNxxyMFG5qFExpt/go-net/context" + logging "gx/ipfs/Qmazh5oNUVsDZTs2g59rq8aYQqwpss8tcUWQzor5sCCEuH/go-log" ) var log = logging.Logger("offlinerouting") diff --git a/routing/record/record.go b/routing/record/record.go index 944f615d0a7..2adcc21bc05 100644 --- a/routing/record/record.go +++ b/routing/record/record.go @@ -6,9 +6,9 @@ import ( proto "github.com/ipfs/go-ipfs/Godeps/_workspace/src/github.com/gogo/protobuf/proto" key "github.com/ipfs/go-ipfs/blocks/key" - ci "github.com/ipfs/go-ipfs/p2p/crypto" pb "github.com/ipfs/go-ipfs/routing/dht/pb" - logging "github.com/ipfs/go-ipfs/vendor/QmQg1J6vikuXF9oDvm4wpdeAUvvkVEKW1EYDw9HhTMnP2b/go-log" + ci "gx/ipfs/QmUBogf4nUefBjmYjn6jfsfPJRkmDGSeMhNj4usRKq69f4/go-libp2p/p2p/crypto" + logging "gx/ipfs/Qmazh5oNUVsDZTs2g59rq8aYQqwpss8tcUWQzor5sCCEuH/go-log" ) var log = logging.Logger("routing/record") diff --git a/routing/record/validation.go b/routing/record/validation.go index a2afc0dfab7..32c33e966d0 100644 --- a/routing/record/validation.go +++ b/routing/record/validation.go @@ -5,10 +5,10 @@ import ( "errors" key "github.com/ipfs/go-ipfs/blocks/key" - ci "github.com/ipfs/go-ipfs/p2p/crypto" path "github.com/ipfs/go-ipfs/path" pb "github.com/ipfs/go-ipfs/routing/dht/pb" u "github.com/ipfs/go-ipfs/util" + ci "gx/ipfs/QmUBogf4nUefBjmYjn6jfsfPJRkmDGSeMhNj4usRKq69f4/go-libp2p/p2p/crypto" ) // ValidatorFunc is a function that is called to validate a given diff --git a/routing/routing.go b/routing/routing.go index 1c799b9843f..5acce6f54fb 100644 --- a/routing/routing.go +++ b/routing/routing.go @@ -4,10 +4,10 @@ package routing import ( "errors" - context "github.com/ipfs/go-ipfs/Godeps/_workspace/src/golang.org/x/net/context" key "github.com/ipfs/go-ipfs/blocks/key" - ci "github.com/ipfs/go-ipfs/p2p/crypto" - peer "github.com/ipfs/go-ipfs/p2p/peer" + ci "gx/ipfs/QmUBogf4nUefBjmYjn6jfsfPJRkmDGSeMhNj4usRKq69f4/go-libp2p/p2p/crypto" + peer "gx/ipfs/QmUBogf4nUefBjmYjn6jfsfPJRkmDGSeMhNj4usRKq69f4/go-libp2p/p2p/peer" + context "gx/ipfs/QmZy2y8t9zQH2a1b8q2ZSLKp17ATuJoCNxxyMFG5qFExpt/go-net/context" ) // ErrNotFound is returned when a search fails to find anything diff --git a/routing/supernode/client.go b/routing/supernode/client.go index 5b7c4a30636..8838b7aeb32 100644 --- a/routing/supernode/client.go +++ b/routing/supernode/client.go @@ -6,15 +6,15 @@ import ( "time" proto "github.com/ipfs/go-ipfs/Godeps/_workspace/src/github.com/gogo/protobuf/proto" - context "github.com/ipfs/go-ipfs/Godeps/_workspace/src/golang.org/x/net/context" + context "gx/ipfs/QmZy2y8t9zQH2a1b8q2ZSLKp17ATuJoCNxxyMFG5qFExpt/go-net/context" key "github.com/ipfs/go-ipfs/blocks/key" - "github.com/ipfs/go-ipfs/p2p/host" - peer "github.com/ipfs/go-ipfs/p2p/peer" routing "github.com/ipfs/go-ipfs/routing" pb "github.com/ipfs/go-ipfs/routing/dht/pb" proxy "github.com/ipfs/go-ipfs/routing/supernode/proxy" - logging "github.com/ipfs/go-ipfs/vendor/QmQg1J6vikuXF9oDvm4wpdeAUvvkVEKW1EYDw9HhTMnP2b/go-log" + "gx/ipfs/QmUBogf4nUefBjmYjn6jfsfPJRkmDGSeMhNj4usRKq69f4/go-libp2p/p2p/host" + peer "gx/ipfs/QmUBogf4nUefBjmYjn6jfsfPJRkmDGSeMhNj4usRKq69f4/go-libp2p/p2p/peer" + logging "gx/ipfs/Qmazh5oNUVsDZTs2g59rq8aYQqwpss8tcUWQzor5sCCEuH/go-log" ) var log = logging.Logger("supernode") diff --git a/routing/supernode/proxy/loopback.go b/routing/supernode/proxy/loopback.go index 1437b574a2e..c067f634b3a 100644 --- a/routing/supernode/proxy/loopback.go +++ b/routing/supernode/proxy/loopback.go @@ -2,11 +2,11 @@ package proxy import ( ggio "github.com/ipfs/go-ipfs/Godeps/_workspace/src/github.com/gogo/protobuf/io" - context "github.com/ipfs/go-ipfs/Godeps/_workspace/src/golang.org/x/net/context" + context "gx/ipfs/QmZy2y8t9zQH2a1b8q2ZSLKp17ATuJoCNxxyMFG5qFExpt/go-net/context" - inet "github.com/ipfs/go-ipfs/p2p/net" - peer "github.com/ipfs/go-ipfs/p2p/peer" dhtpb "github.com/ipfs/go-ipfs/routing/dht/pb" + inet "gx/ipfs/QmUBogf4nUefBjmYjn6jfsfPJRkmDGSeMhNj4usRKq69f4/go-libp2p/p2p/net" + peer "gx/ipfs/QmUBogf4nUefBjmYjn6jfsfPJRkmDGSeMhNj4usRKq69f4/go-libp2p/p2p/peer" ) // RequestHandler handles routing requests locally diff --git a/routing/supernode/proxy/standard.go b/routing/supernode/proxy/standard.go index 279cbe7dec0..00892de88ba 100644 --- a/routing/supernode/proxy/standard.go +++ b/routing/supernode/proxy/standard.go @@ -4,15 +4,15 @@ import ( "errors" ggio "github.com/ipfs/go-ipfs/Godeps/_workspace/src/github.com/gogo/protobuf/io" - context "github.com/ipfs/go-ipfs/Godeps/_workspace/src/golang.org/x/net/context" + context "gx/ipfs/QmZy2y8t9zQH2a1b8q2ZSLKp17ATuJoCNxxyMFG5qFExpt/go-net/context" key "github.com/ipfs/go-ipfs/blocks/key" - host "github.com/ipfs/go-ipfs/p2p/host" - inet "github.com/ipfs/go-ipfs/p2p/net" - peer "github.com/ipfs/go-ipfs/p2p/peer" dhtpb "github.com/ipfs/go-ipfs/routing/dht/pb" kbucket "github.com/ipfs/go-ipfs/routing/kbucket" - logging "github.com/ipfs/go-ipfs/vendor/QmQg1J6vikuXF9oDvm4wpdeAUvvkVEKW1EYDw9HhTMnP2b/go-log" + host "gx/ipfs/QmUBogf4nUefBjmYjn6jfsfPJRkmDGSeMhNj4usRKq69f4/go-libp2p/p2p/host" + inet "gx/ipfs/QmUBogf4nUefBjmYjn6jfsfPJRkmDGSeMhNj4usRKq69f4/go-libp2p/p2p/net" + peer "gx/ipfs/QmUBogf4nUefBjmYjn6jfsfPJRkmDGSeMhNj4usRKq69f4/go-libp2p/p2p/peer" + logging "gx/ipfs/Qmazh5oNUVsDZTs2g59rq8aYQqwpss8tcUWQzor5sCCEuH/go-log" ) const ProtocolSNR = "/ipfs/supernoderouting" @@ -98,7 +98,7 @@ func (px *standard) sendMessage(ctx context.Context, m *dhtpb.Message, remote pe if err = px.Host.Connect(ctx, peer.PeerInfo{ID: remote}); err != nil { return err } - s, err := px.Host.NewStream(ProtocolSNR, remote) + s, err := px.Host.NewStream(ctx, ProtocolSNR, remote) if err != nil { return err } @@ -133,7 +133,7 @@ func (px *standard) sendRequest(ctx context.Context, m *dhtpb.Message, remote pe e.SetError(err) return nil, err } - s, err := px.Host.NewStream(ProtocolSNR, remote) + s, err := px.Host.NewStream(ctx, ProtocolSNR, remote) if err != nil { e.SetError(err) return nil, err diff --git a/routing/supernode/server.go b/routing/supernode/server.go index 32a69ead556..46caf03eac3 100644 --- a/routing/supernode/server.go +++ b/routing/supernode/server.go @@ -6,13 +6,13 @@ import ( proto "github.com/ipfs/go-ipfs/Godeps/_workspace/src/github.com/gogo/protobuf/proto" datastore "github.com/ipfs/go-ipfs/Godeps/_workspace/src/github.com/ipfs/go-datastore" - context "github.com/ipfs/go-ipfs/Godeps/_workspace/src/golang.org/x/net/context" + context "gx/ipfs/QmZy2y8t9zQH2a1b8q2ZSLKp17ATuJoCNxxyMFG5qFExpt/go-net/context" key "github.com/ipfs/go-ipfs/blocks/key" - peer "github.com/ipfs/go-ipfs/p2p/peer" dhtpb "github.com/ipfs/go-ipfs/routing/dht/pb" record "github.com/ipfs/go-ipfs/routing/record" proxy "github.com/ipfs/go-ipfs/routing/supernode/proxy" + peer "gx/ipfs/QmUBogf4nUefBjmYjn6jfsfPJRkmDGSeMhNj4usRKq69f4/go-libp2p/p2p/peer" ) // Server handles routing queries using a database backend diff --git a/tar/format.go b/tar/format.go index 3fab02b6e9d..26ddb3a8810 100644 --- a/tar/format.go +++ b/tar/format.go @@ -14,9 +14,9 @@ import ( dagutil "github.com/ipfs/go-ipfs/merkledag/utils" path "github.com/ipfs/go-ipfs/path" uio "github.com/ipfs/go-ipfs/unixfs/io" - logging "github.com/ipfs/go-ipfs/vendor/QmQg1J6vikuXF9oDvm4wpdeAUvvkVEKW1EYDw9HhTMnP2b/go-log" + logging "gx/ipfs/Qmazh5oNUVsDZTs2g59rq8aYQqwpss8tcUWQzor5sCCEuH/go-log" - context "github.com/ipfs/go-ipfs/Godeps/_workspace/src/golang.org/x/net/context" + context "gx/ipfs/QmZy2y8t9zQH2a1b8q2ZSLKp17ATuJoCNxxyMFG5qFExpt/go-net/context" ) var log = logging.Logger("tarfmt") diff --git a/test/3nodetest/Makefile b/test/3nodetest/Makefile index 1c20a68377b..b769a2ee579 100644 --- a/test/3nodetest/Makefile +++ b/test/3nodetest/Makefile @@ -25,7 +25,7 @@ bin/random: $(RANDOMSRC)/**/*.go # just build it every time... this part isn't # even the lengthy part, and it decreases pain. docker_ipfs_image: - cd $(IPFS_ROOT) && docker build -t $(IMAGE_NAME) . + docker build -t $(IMAGE_NAME) -f test/Dockerfile . docker images | grep $(IMAGE_NAME) clean: diff --git a/test/Dockerfile b/test/Dockerfile new file mode 100644 index 00000000000..61a4a2c1f90 --- /dev/null +++ b/test/Dockerfile @@ -0,0 +1,58 @@ +FROM alpine:3.3 +MAINTAINER Lars Gierth + +# This is a copy of the root Dockerfile, +# except that we optimize for build time, instead of image size. +# +# Please keep these two Dockerfiles in sync. +# +# Only sections different from the root Dockerfile are commented. + + +EXPOSE 4001 +EXPOSE 4002/udp +EXPOSE 5001 +EXPOSE 8080 + +ENV GX_IPFS "" +ENV IPFS_PATH /data/ipfs +ENV GO_VERSION 1.5.3-r0 +ENV GOPATH /go +ENV PATH /go/bin:$PATH +ENV SRC_PATH /go/src/github.com/ipfs/go-ipfs + +# This is an optimization which avoids rebuilding +# of the gx dependencies every time anything changes. +# gx will only be invoked if the dependencies have changed. +# +# Put differently: if package.json has changed, +# the image-id after this COPY command will change, +# and trigger a re-run of all following commands. +COPY ./package.json $SRC_PATH/package.json + +RUN apk add --update musl go=$GO_VERSION git bash wget ca-certificates \ + && mkdir -p $IPFS_PATH \ + && adduser -D -h $IPFS_PATH -u 1000 ipfs \ + && chown ipfs:ipfs $IPFS_PATH && chmod 755 $IPFS_PATH \ + && go get -u github.com/whyrusleeping/gx \ + && go get -u github.com/whyrusleeping/gx-go \ + && ([ -z "$GX_IPFS" ] || echo $GX_IPFS > $IPFS_PATH/api) \ + && cd $SRC_PATH \ + && gx --verbose install --global + +COPY . $SRC_PATH + +RUN cd $SRC_PATH \ + && ref="$(cat .git/HEAD | cut -d' ' -f2)" \ + && commit="$(cat .git/$ref | head -c 7)" \ + && echo "ldflags=-X github.com/ipfs/go-ipfs/repo/config.CurrentCommit=$commit" \ + && cd $SRC_PATH/cmd/ipfs \ + && go build -ldflags "-X github.com/ipfs/go-ipfs/repo/config.CurrentCommit=$commit" \ + && cp ipfs /usr/local/bin/ipfs \ + && cp $SRC_PATH/bin/container_daemon /usr/local/bin/start_ipfs \ + && chmod 755 /usr/local/bin/start_ipfs \ + && apk del --purge musl go git && rm -rf $GOPATH && rm -vf $IPFS_PATH/api + +USER ipfs +VOLUME $IPFS_PATH +ENTRYPOINT ["/usr/local/bin/start_ipfs"] diff --git a/test/dependencies/iptb/main.go b/test/dependencies/iptb/main.go index d9eb96ed5cf..de4e2648287 100644 --- a/test/dependencies/iptb/main.go +++ b/test/dependencies/iptb/main.go @@ -19,8 +19,8 @@ import ( kingpin "github.com/ipfs/go-ipfs/Godeps/_workspace/src/github.com/alecthomas/kingpin" serial "github.com/ipfs/go-ipfs/repo/fsrepo/serialize" - ma "github.com/ipfs/go-ipfs/Godeps/_workspace/src/github.com/jbenet/go-multiaddr" - manet "github.com/ipfs/go-ipfs/Godeps/_workspace/src/github.com/jbenet/go-multiaddr-net" + ma "gx/ipfs/QmR3JkmZBKYXgNMNsNZawm914455Qof3PEopwuVSeXG7aV/go-multiaddr" + manet "gx/ipfs/QmYtzQmUwPFGxjCXctJ8e6GXS8sYfoXy2pdeMbS5SFWqRi/go-multiaddr-net" ) var setupOpt = func(cmd *exec.Cmd) {} diff --git a/test/integration/addcat_test.go b/test/integration/addcat_test.go index 848dbf4dd16..b59fb463795 100644 --- a/test/integration/addcat_test.go +++ b/test/integration/addcat_test.go @@ -11,16 +11,16 @@ import ( "time" random "github.com/ipfs/go-ipfs/Godeps/_workspace/src/github.com/jbenet/go-random" - context "github.com/ipfs/go-ipfs/Godeps/_workspace/src/golang.org/x/net/context" + context "gx/ipfs/QmZy2y8t9zQH2a1b8q2ZSLKp17ATuJoCNxxyMFG5qFExpt/go-net/context" "github.com/ipfs/go-ipfs/core" coreunix "github.com/ipfs/go-ipfs/core/coreunix" mock "github.com/ipfs/go-ipfs/core/mock" - mocknet "github.com/ipfs/go-ipfs/p2p/net/mock" - "github.com/ipfs/go-ipfs/p2p/peer" "github.com/ipfs/go-ipfs/thirdparty/unit" testutil "github.com/ipfs/go-ipfs/util/testutil" - logging "github.com/ipfs/go-ipfs/vendor/QmQg1J6vikuXF9oDvm4wpdeAUvvkVEKW1EYDw9HhTMnP2b/go-log" + mocknet "gx/ipfs/QmUBogf4nUefBjmYjn6jfsfPJRkmDGSeMhNj4usRKq69f4/go-libp2p/p2p/net/mock" + "gx/ipfs/QmUBogf4nUefBjmYjn6jfsfPJRkmDGSeMhNj4usRKq69f4/go-libp2p/p2p/peer" + logging "gx/ipfs/Qmazh5oNUVsDZTs2g59rq8aYQqwpss8tcUWQzor5sCCEuH/go-log" ) var log = logging.Logger("epictest") diff --git a/test/integration/bench_cat_test.go b/test/integration/bench_cat_test.go index 7237a78ea11..a54b8d957ae 100644 --- a/test/integration/bench_cat_test.go +++ b/test/integration/bench_cat_test.go @@ -7,14 +7,14 @@ import ( "math" "testing" - context "github.com/ipfs/go-ipfs/Godeps/_workspace/src/golang.org/x/net/context" "github.com/ipfs/go-ipfs/core" coreunix "github.com/ipfs/go-ipfs/core/coreunix" mock "github.com/ipfs/go-ipfs/core/mock" - mocknet "github.com/ipfs/go-ipfs/p2p/net/mock" - "github.com/ipfs/go-ipfs/p2p/peer" "github.com/ipfs/go-ipfs/thirdparty/unit" testutil "github.com/ipfs/go-ipfs/util/testutil" + mocknet "gx/ipfs/QmUBogf4nUefBjmYjn6jfsfPJRkmDGSeMhNj4usRKq69f4/go-libp2p/p2p/net/mock" + "gx/ipfs/QmUBogf4nUefBjmYjn6jfsfPJRkmDGSeMhNj4usRKq69f4/go-libp2p/p2p/peer" + context "gx/ipfs/QmZy2y8t9zQH2a1b8q2ZSLKp17ATuJoCNxxyMFG5qFExpt/go-net/context" ) func BenchmarkCat1MB(b *testing.B) { benchmarkVarCat(b, unit.MB*1) } diff --git a/test/integration/bitswap_wo_routing_test.go b/test/integration/bitswap_wo_routing_test.go index f764b29872e..2db0551c330 100644 --- a/test/integration/bitswap_wo_routing_test.go +++ b/test/integration/bitswap_wo_routing_test.go @@ -4,11 +4,11 @@ import ( "bytes" "testing" - context "github.com/ipfs/go-ipfs/Godeps/_workspace/src/golang.org/x/net/context" "github.com/ipfs/go-ipfs/blocks" "github.com/ipfs/go-ipfs/core" "github.com/ipfs/go-ipfs/core/mock" - mocknet "github.com/ipfs/go-ipfs/p2p/net/mock" + mocknet "gx/ipfs/QmUBogf4nUefBjmYjn6jfsfPJRkmDGSeMhNj4usRKq69f4/go-libp2p/p2p/net/mock" + context "gx/ipfs/QmZy2y8t9zQH2a1b8q2ZSLKp17ATuJoCNxxyMFG5qFExpt/go-net/context" ) func TestBitswapWithoutRouting(t *testing.T) { diff --git a/test/integration/grandcentral_test.go b/test/integration/grandcentral_test.go index b190babd173..873e95ffda1 100644 --- a/test/integration/grandcentral_test.go +++ b/test/integration/grandcentral_test.go @@ -10,18 +10,18 @@ import ( "github.com/ipfs/go-ipfs/Godeps/_workspace/src/github.com/ipfs/go-datastore" syncds "github.com/ipfs/go-ipfs/Godeps/_workspace/src/github.com/ipfs/go-datastore/sync" - context "github.com/ipfs/go-ipfs/Godeps/_workspace/src/golang.org/x/net/context" + context "gx/ipfs/QmZy2y8t9zQH2a1b8q2ZSLKp17ATuJoCNxxyMFG5qFExpt/go-net/context" key "github.com/ipfs/go-ipfs/blocks/key" core "github.com/ipfs/go-ipfs/core" "github.com/ipfs/go-ipfs/core/corerouting" "github.com/ipfs/go-ipfs/core/coreunix" mock "github.com/ipfs/go-ipfs/core/mock" - mocknet "github.com/ipfs/go-ipfs/p2p/net/mock" - "github.com/ipfs/go-ipfs/p2p/peer" "github.com/ipfs/go-ipfs/thirdparty/unit" ds2 "github.com/ipfs/go-ipfs/util/datastore2" testutil "github.com/ipfs/go-ipfs/util/testutil" + mocknet "gx/ipfs/QmUBogf4nUefBjmYjn6jfsfPJRkmDGSeMhNj4usRKq69f4/go-libp2p/p2p/net/mock" + "gx/ipfs/QmUBogf4nUefBjmYjn6jfsfPJRkmDGSeMhNj4usRKq69f4/go-libp2p/p2p/peer" ) func TestSupernodeBootstrappedAddCat(t *testing.T) { diff --git a/test/integration/three_legged_cat_test.go b/test/integration/three_legged_cat_test.go index 278e3d1e498..5d48affdd29 100644 --- a/test/integration/three_legged_cat_test.go +++ b/test/integration/three_legged_cat_test.go @@ -8,15 +8,15 @@ import ( "testing" "time" - context "github.com/ipfs/go-ipfs/Godeps/_workspace/src/golang.org/x/net/context" + context "gx/ipfs/QmZy2y8t9zQH2a1b8q2ZSLKp17ATuJoCNxxyMFG5qFExpt/go-net/context" core "github.com/ipfs/go-ipfs/core" coreunix "github.com/ipfs/go-ipfs/core/coreunix" mock "github.com/ipfs/go-ipfs/core/mock" - mocknet "github.com/ipfs/go-ipfs/p2p/net/mock" - "github.com/ipfs/go-ipfs/p2p/peer" "github.com/ipfs/go-ipfs/thirdparty/unit" testutil "github.com/ipfs/go-ipfs/util/testutil" + mocknet "gx/ipfs/QmUBogf4nUefBjmYjn6jfsfPJRkmDGSeMhNj4usRKq69f4/go-libp2p/p2p/net/mock" + "gx/ipfs/QmUBogf4nUefBjmYjn6jfsfPJRkmDGSeMhNj4usRKq69f4/go-libp2p/p2p/peer" ) func TestThreeLeggedCatTransfer(t *testing.T) { diff --git a/test/ipfs-test-lib.sh b/test/ipfs-test-lib.sh index d1897f3869a..50770080f80 100644 --- a/test/ipfs-test-lib.sh +++ b/test/ipfs-test-lib.sh @@ -38,14 +38,14 @@ shellquote() { # Docker -# This takes a directory, that should contain a Dockerfile, as argument +# This takes a Dockerfile, and a build context directory docker_build() { - docker build --rm "$1" + docker build --rm -f "$1" "$2" } # This takes an image as argument and writes a docker ID on stdout docker_run() { - docker run -it -d -p 8080:8080 -p 4001:4001 -p 5001:5001 "$1" + docker run -d "$1" } # This takes a docker ID and a command as arguments @@ -54,7 +54,7 @@ docker_exec() { then sudo lxc-attach -n "$(docker inspect --format '{{.Id}}' $1)" -- /bin/bash -c "$2" else - docker exec -i "$1" /bin/bash -c "$2" + docker exec -t "$1" /bin/bash -c "$2" fi } diff --git a/test/sharness/lib/test-lib.sh b/test/sharness/lib/test-lib.sh index 9d2f405446c..771471861a4 100644 --- a/test/sharness/lib/test-lib.sh +++ b/test/sharness/lib/test-lib.sh @@ -42,7 +42,7 @@ SHARNESS_LIB="lib/sharness/sharness.sh" # grab + output options test "$TEST_NO_FUSE" != 1 && test_set_prereq FUSE test "$TEST_EXPENSIVE" = 1 && test_set_prereq EXPENSIVE -type docker && test_set_prereq DOCKER +test "$TEST_NO_DOCKER" != 1 && type docker && test_set_prereq DOCKER if test "$TEST_VERBOSE" = 1; then echo '# TEST_VERBOSE='"$TEST_VERBOSE" diff --git a/test/sharness/t0300-docker-image.sh b/test/sharness/t0300-docker-image.sh index 1d0759e777d..478b2434450 100755 --- a/test/sharness/t0300-docker-image.sh +++ b/test/sharness/t0300-docker-image.sh @@ -33,7 +33,7 @@ TEST_TESTS_DIR=$(dirname "$TEST_SCRIPTS_DIR") APP_ROOT_DIR=$(dirname "$TEST_TESTS_DIR") test_expect_success "docker image build succeeds" ' - docker_build "$APP_ROOT_DIR" >actual + docker_build "$TEST_TESTS_DIR/Dockerfile" "$APP_ROOT_DIR" >actual ' test_expect_success "docker image build output looks good" ' @@ -46,12 +46,20 @@ test_expect_success "docker image runs" ' DOC_ID=$(docker_run "$IMAGE_ID") ' -test_expect_success "simple command can be run in docker container" ' - docker_exec "$DOC_ID" "echo Hello Worlds" >actual +test_expect_success "docker image gateway is up" ' + docker_exec "$DOC_ID" "wget --retry-connrefused --waitretry=1 --timeout=30 -t 30 \ + -q -O - http://localhost:8080/version >/dev/null" ' -test_expect_success "simple command output looks good" ' - echo "Hello Worlds" >expected && +test_expect_success "docker image API is up" ' + docker_exec "$DOC_ID" "wget --retry-connrefused --waitretry=1 --timeout=30 -t 30 \ + -q -O - http://localhost:5001/api/v0/version >/dev/null" +' + +test_expect_success "simple ipfs add/cat can be run in docker container" ' + expected="Hello Worlds" && + HASH=$(docker_exec "$DOC_ID" "echo $(cat expected) | ipfs add | cut -d' ' -f2") && + docker_exec "$DOC_ID" "ipfs cat $HASH" >actual && test_cmp expected actual ' diff --git a/test/supernode_client/main.go b/test/supernode_client/main.go index ce80dbd2247..4643dcc5cec 100644 --- a/test/supernode_client/main.go +++ b/test/supernode_client/main.go @@ -12,10 +12,10 @@ import ( gopath "path" "time" - ma "github.com/ipfs/go-ipfs/Godeps/_workspace/src/github.com/jbenet/go-multiaddr" random "github.com/ipfs/go-ipfs/Godeps/_workspace/src/github.com/jbenet/go-random" - context "github.com/ipfs/go-ipfs/Godeps/_workspace/src/golang.org/x/net/context" "github.com/ipfs/go-ipfs/util/ipfsaddr" + ma "gx/ipfs/QmR3JkmZBKYXgNMNsNZawm914455Qof3PEopwuVSeXG7aV/go-multiaddr" + context "gx/ipfs/QmZy2y8t9zQH2a1b8q2ZSLKp17ATuJoCNxxyMFG5qFExpt/go-net/context" "github.com/ipfs/go-ipfs/Godeps/_workspace/src/github.com/ipfs/go-datastore" syncds "github.com/ipfs/go-ipfs/Godeps/_workspace/src/github.com/ipfs/go-datastore/sync" @@ -24,13 +24,13 @@ import ( corehttp "github.com/ipfs/go-ipfs/core/corehttp" corerouting "github.com/ipfs/go-ipfs/core/corerouting" "github.com/ipfs/go-ipfs/core/coreunix" - peer "github.com/ipfs/go-ipfs/p2p/peer" "github.com/ipfs/go-ipfs/repo" config "github.com/ipfs/go-ipfs/repo/config" fsrepo "github.com/ipfs/go-ipfs/repo/fsrepo" unit "github.com/ipfs/go-ipfs/thirdparty/unit" ds2 "github.com/ipfs/go-ipfs/util/datastore2" - logging "github.com/ipfs/go-ipfs/vendor/QmQg1J6vikuXF9oDvm4wpdeAUvvkVEKW1EYDw9HhTMnP2b/go-log" + peer "gx/ipfs/QmUBogf4nUefBjmYjn6jfsfPJRkmDGSeMhNj4usRKq69f4/go-libp2p/p2p/peer" + logging "gx/ipfs/Qmazh5oNUVsDZTs2g59rq8aYQqwpss8tcUWQzor5sCCEuH/go-log" ) var elog = logging.Logger("gc-client") diff --git a/thirdparty/pollEndpoint/main.go b/thirdparty/pollEndpoint/main.go index 6f6e11d5c1a..b3d12f18083 100644 --- a/thirdparty/pollEndpoint/main.go +++ b/thirdparty/pollEndpoint/main.go @@ -10,9 +10,9 @@ import ( "os" "time" - ma "github.com/ipfs/go-ipfs/Godeps/_workspace/src/github.com/jbenet/go-multiaddr" - manet "github.com/ipfs/go-ipfs/Godeps/_workspace/src/github.com/jbenet/go-multiaddr-net" - logging "github.com/ipfs/go-ipfs/vendor/QmQg1J6vikuXF9oDvm4wpdeAUvvkVEKW1EYDw9HhTMnP2b/go-log" + ma "gx/ipfs/QmR3JkmZBKYXgNMNsNZawm914455Qof3PEopwuVSeXG7aV/go-multiaddr" + manet "gx/ipfs/QmYtzQmUwPFGxjCXctJ8e6GXS8sYfoXy2pdeMbS5SFWqRi/go-multiaddr-net" + logging "gx/ipfs/Qmazh5oNUVsDZTs2g59rq8aYQqwpss8tcUWQzor5sCCEuH/go-log" ) var ( diff --git a/tour/tour.go b/tour/tour.go index 3b81273bd62..c6452e292b6 100644 --- a/tour/tour.go +++ b/tour/tour.go @@ -4,7 +4,7 @@ import ( "strconv" "strings" - logging "github.com/ipfs/go-ipfs/vendor/QmQg1J6vikuXF9oDvm4wpdeAUvvkVEKW1EYDw9HhTMnP2b/go-log" + logging "gx/ipfs/Qmazh5oNUVsDZTs2g59rq8aYQqwpss8tcUWQzor5sCCEuH/go-log" ) var log = logging.Logger("tour") diff --git a/unixfs/archive/archive.go b/unixfs/archive/archive.go index 1fbd5ccd972..1ec1760f018 100644 --- a/unixfs/archive/archive.go +++ b/unixfs/archive/archive.go @@ -6,7 +6,7 @@ import ( "io" "path" - cxt "github.com/ipfs/go-ipfs/Godeps/_workspace/src/golang.org/x/net/context" + cxt "gx/ipfs/QmZy2y8t9zQH2a1b8q2ZSLKp17ATuJoCNxxyMFG5qFExpt/go-net/context" mdag "github.com/ipfs/go-ipfs/merkledag" tar "github.com/ipfs/go-ipfs/unixfs/archive/tar" diff --git a/unixfs/archive/tar/writer.go b/unixfs/archive/tar/writer.go index 6536e443e8a..2d470b66753 100644 --- a/unixfs/archive/tar/writer.go +++ b/unixfs/archive/tar/writer.go @@ -7,7 +7,7 @@ import ( "time" proto "github.com/ipfs/go-ipfs/Godeps/_workspace/src/github.com/gogo/protobuf/proto" - cxt "github.com/ipfs/go-ipfs/Godeps/_workspace/src/golang.org/x/net/context" + cxt "gx/ipfs/QmZy2y8t9zQH2a1b8q2ZSLKp17ATuJoCNxxyMFG5qFExpt/go-net/context" mdag "github.com/ipfs/go-ipfs/merkledag" ft "github.com/ipfs/go-ipfs/unixfs" diff --git a/unixfs/io/dagreader.go b/unixfs/io/dagreader.go index 4cc52202508..a1a104e4421 100644 --- a/unixfs/io/dagreader.go +++ b/unixfs/io/dagreader.go @@ -8,7 +8,7 @@ import ( "os" proto "github.com/ipfs/go-ipfs/Godeps/_workspace/src/github.com/gogo/protobuf/proto" - "github.com/ipfs/go-ipfs/Godeps/_workspace/src/golang.org/x/net/context" + "gx/ipfs/QmZy2y8t9zQH2a1b8q2ZSLKp17ATuJoCNxxyMFG5qFExpt/go-net/context" mdag "github.com/ipfs/go-ipfs/merkledag" ft "github.com/ipfs/go-ipfs/unixfs" diff --git a/unixfs/io/dirbuilder.go b/unixfs/io/dirbuilder.go index 6fdef9ffb0e..8dad9a16ddc 100644 --- a/unixfs/io/dirbuilder.go +++ b/unixfs/io/dirbuilder.go @@ -1,7 +1,7 @@ package io import ( - "github.com/ipfs/go-ipfs/Godeps/_workspace/src/golang.org/x/net/context" + "gx/ipfs/QmZy2y8t9zQH2a1b8q2ZSLKp17ATuJoCNxxyMFG5qFExpt/go-net/context" key "github.com/ipfs/go-ipfs/blocks/key" mdag "github.com/ipfs/go-ipfs/merkledag" diff --git a/unixfs/mod/dagmodifier.go b/unixfs/mod/dagmodifier.go index 197e330a9c5..e9dbe40a012 100644 --- a/unixfs/mod/dagmodifier.go +++ b/unixfs/mod/dagmodifier.go @@ -8,7 +8,7 @@ import ( proto "github.com/ipfs/go-ipfs/Godeps/_workspace/src/github.com/gogo/protobuf/proto" mh "github.com/ipfs/go-ipfs/Godeps/_workspace/src/github.com/jbenet/go-multihash" - context "github.com/ipfs/go-ipfs/Godeps/_workspace/src/golang.org/x/net/context" + context "gx/ipfs/QmZy2y8t9zQH2a1b8q2ZSLKp17ATuJoCNxxyMFG5qFExpt/go-net/context" key "github.com/ipfs/go-ipfs/blocks/key" chunk "github.com/ipfs/go-ipfs/importer/chunk" @@ -17,7 +17,7 @@ import ( mdag "github.com/ipfs/go-ipfs/merkledag" ft "github.com/ipfs/go-ipfs/unixfs" uio "github.com/ipfs/go-ipfs/unixfs/io" - logging "github.com/ipfs/go-ipfs/vendor/QmQg1J6vikuXF9oDvm4wpdeAUvvkVEKW1EYDw9HhTMnP2b/go-log" + logging "gx/ipfs/Qmazh5oNUVsDZTs2g59rq8aYQqwpss8tcUWQzor5sCCEuH/go-log" ) var ErrSeekFail = errors.New("failed to seek properly") diff --git a/unixfs/mod/dagmodifier_test.go b/unixfs/mod/dagmodifier_test.go index 16f7dca337d..0cd4a2f10ae 100644 --- a/unixfs/mod/dagmodifier_test.go +++ b/unixfs/mod/dagmodifier_test.go @@ -21,7 +21,7 @@ import ( u "github.com/ipfs/go-ipfs/util" ds "github.com/ipfs/go-ipfs/Godeps/_workspace/src/github.com/ipfs/go-datastore" - context "github.com/ipfs/go-ipfs/Godeps/_workspace/src/golang.org/x/net/context" + context "gx/ipfs/QmZy2y8t9zQH2a1b8q2ZSLKp17ATuJoCNxxyMFG5qFExpt/go-net/context" ) func getMockDagServ(t testing.TB) mdag.DAGService { diff --git a/util/context.go b/util/context.go index af3f6030113..77504b16dbf 100644 --- a/util/context.go +++ b/util/context.go @@ -1,7 +1,7 @@ package util import ( - context "github.com/ipfs/go-ipfs/Godeps/_workspace/src/golang.org/x/net/context" + context "gx/ipfs/QmZy2y8t9zQH2a1b8q2ZSLKp17ATuJoCNxxyMFG5qFExpt/go-net/context" ) // privateChanType protects the channel. Since this is a package-private type, diff --git a/util/context_test.go b/util/context_test.go index 6f78995f117..d9428d6b56b 100644 --- a/util/context_test.go +++ b/util/context_test.go @@ -4,7 +4,7 @@ import ( "errors" "testing" - context "github.com/ipfs/go-ipfs/Godeps/_workspace/src/golang.org/x/net/context" + context "gx/ipfs/QmZy2y8t9zQH2a1b8q2ZSLKp17ATuJoCNxxyMFG5qFExpt/go-net/context" ) func TestLogErrorDoesNotBlockWhenCtxIsNotSetUpForLogging(t *testing.T) { diff --git a/util/do.go b/util/do.go index 97121c25a50..84384d7096e 100644 --- a/util/do.go +++ b/util/do.go @@ -1,6 +1,6 @@ package util -import "github.com/ipfs/go-ipfs/Godeps/_workspace/src/golang.org/x/net/context" +import "gx/ipfs/QmZy2y8t9zQH2a1b8q2ZSLKp17ATuJoCNxxyMFG5qFExpt/go-net/context" func ContextDo(ctx context.Context, f func() error) error { diff --git a/util/do_test.go b/util/do_test.go index 48d3e2fb36a..7b77a48bb22 100644 --- a/util/do_test.go +++ b/util/do_test.go @@ -4,7 +4,7 @@ import ( "errors" "testing" - "github.com/ipfs/go-ipfs/Godeps/_workspace/src/golang.org/x/net/context" + "gx/ipfs/QmZy2y8t9zQH2a1b8q2ZSLKp17ATuJoCNxxyMFG5qFExpt/go-net/context" ) func TestDoReturnsContextErr(t *testing.T) { diff --git a/util/eventlog/loggables/loggables.go b/util/eventlog/loggables/loggables.go index 4d5ab474b10..06b027f61af 100644 --- a/util/eventlog/loggables/loggables.go +++ b/util/eventlog/loggables/loggables.go @@ -9,11 +9,11 @@ package loggables import ( "net" - ma "github.com/ipfs/go-ipfs/Godeps/_workspace/src/github.com/jbenet/go-multiaddr" + ma "gx/ipfs/QmR3JkmZBKYXgNMNsNZawm914455Qof3PEopwuVSeXG7aV/go-multiaddr" - logging "github.com/ipfs/go-ipfs/vendor/QmQg1J6vikuXF9oDvm4wpdeAUvvkVEKW1EYDw9HhTMnP2b/go-log" + logging "gx/ipfs/Qmazh5oNUVsDZTs2g59rq8aYQqwpss8tcUWQzor5sCCEuH/go-log" - peer "github.com/ipfs/go-ipfs/p2p/peer" + peer "gx/ipfs/QmUBogf4nUefBjmYjn6jfsfPJRkmDGSeMhNj4usRKq69f4/go-libp2p/p2p/peer" ) // NetConn returns an eventlog.Metadata with the conn addresses diff --git a/util/ipfsaddr/ipfsaddr.go b/util/ipfsaddr/ipfsaddr.go index 1a911d4e88d..f93b8ac2a18 100644 --- a/util/ipfsaddr/ipfsaddr.go +++ b/util/ipfsaddr/ipfsaddr.go @@ -3,11 +3,11 @@ package ipfsaddr import ( "errors" - ma "github.com/ipfs/go-ipfs/Godeps/_workspace/src/github.com/jbenet/go-multiaddr" + ma "gx/ipfs/QmR3JkmZBKYXgNMNsNZawm914455Qof3PEopwuVSeXG7aV/go-multiaddr" - peer "github.com/ipfs/go-ipfs/p2p/peer" path "github.com/ipfs/go-ipfs/path" - logging "github.com/ipfs/go-ipfs/vendor/QmQg1J6vikuXF9oDvm4wpdeAUvvkVEKW1EYDw9HhTMnP2b/go-log" + peer "gx/ipfs/QmUBogf4nUefBjmYjn6jfsfPJRkmDGSeMhNj4usRKq69f4/go-libp2p/p2p/peer" + logging "gx/ipfs/Qmazh5oNUVsDZTs2g59rq8aYQqwpss8tcUWQzor5sCCEuH/go-log" ) var log = logging.Logger("ipfsaddr") diff --git a/util/ipfsaddr/ipfsaddr_test.go b/util/ipfsaddr/ipfsaddr_test.go index aca4ae2386a..07e87f57678 100644 --- a/util/ipfsaddr/ipfsaddr_test.go +++ b/util/ipfsaddr/ipfsaddr_test.go @@ -3,9 +3,9 @@ package ipfsaddr import ( "testing" - ma "github.com/ipfs/go-ipfs/Godeps/_workspace/src/github.com/jbenet/go-multiaddr" - peer "github.com/ipfs/go-ipfs/p2p/peer" path "github.com/ipfs/go-ipfs/path" + ma "gx/ipfs/QmR3JkmZBKYXgNMNsNZawm914455Qof3PEopwuVSeXG7aV/go-multiaddr" + peer "gx/ipfs/QmUBogf4nUefBjmYjn6jfsfPJRkmDGSeMhNj4usRKq69f4/go-libp2p/p2p/peer" ) var good = []string{ diff --git a/util/peerset/peerset.go b/util/peerset/peerset.go index 6997b52f8bb..1eceaa9ab41 100644 --- a/util/peerset/peerset.go +++ b/util/peerset/peerset.go @@ -1,7 +1,7 @@ package peerset import ( - peer "github.com/ipfs/go-ipfs/p2p/peer" + peer "gx/ipfs/QmUBogf4nUefBjmYjn6jfsfPJRkmDGSeMhNj4usRKq69f4/go-libp2p/p2p/peer" "sync" ) diff --git a/util/testutil/gen.go b/util/testutil/gen.go index 1d5d359d3ba..4ac55a0f47f 100644 --- a/util/testutil/gen.go +++ b/util/testutil/gen.go @@ -8,11 +8,11 @@ import ( "sync" "testing" - ci "github.com/ipfs/go-ipfs/p2p/crypto" - peer "github.com/ipfs/go-ipfs/p2p/peer" u "github.com/ipfs/go-ipfs/util" + ci "gx/ipfs/QmUBogf4nUefBjmYjn6jfsfPJRkmDGSeMhNj4usRKq69f4/go-libp2p/p2p/crypto" + peer "gx/ipfs/QmUBogf4nUefBjmYjn6jfsfPJRkmDGSeMhNj4usRKq69f4/go-libp2p/p2p/peer" - ma "github.com/ipfs/go-ipfs/Godeps/_workspace/src/github.com/jbenet/go-multiaddr" + ma "gx/ipfs/QmR3JkmZBKYXgNMNsNZawm914455Qof3PEopwuVSeXG7aV/go-multiaddr" ) // ZeroLocalTCPAddress is the "zero" tcp local multiaddr. This means: diff --git a/util/testutil/identity.go b/util/testutil/identity.go index bd31c1314c4..7b25b12ad16 100644 --- a/util/testutil/identity.go +++ b/util/testutil/identity.go @@ -3,9 +3,9 @@ package testutil import ( "testing" - ma "github.com/ipfs/go-ipfs/Godeps/_workspace/src/github.com/jbenet/go-multiaddr" - ci "github.com/ipfs/go-ipfs/p2p/crypto" - peer "github.com/ipfs/go-ipfs/p2p/peer" + ma "gx/ipfs/QmR3JkmZBKYXgNMNsNZawm914455Qof3PEopwuVSeXG7aV/go-multiaddr" + ci "gx/ipfs/QmUBogf4nUefBjmYjn6jfsfPJRkmDGSeMhNj4usRKq69f4/go-libp2p/p2p/crypto" + peer "gx/ipfs/QmUBogf4nUefBjmYjn6jfsfPJRkmDGSeMhNj4usRKq69f4/go-libp2p/p2p/peer" ) type Identity interface { diff --git a/vendor/QmQg1J6vikuXF9oDvm4wpdeAUvvkVEKW1EYDw9HhTMnP2b/go-log/.gxlastpubver b/vendor/QmQg1J6vikuXF9oDvm4wpdeAUvvkVEKW1EYDw9HhTMnP2b/go-log/.gxlastpubver deleted file mode 100644 index d0ec3ea17cb..00000000000 --- a/vendor/QmQg1J6vikuXF9oDvm4wpdeAUvvkVEKW1EYDw9HhTMnP2b/go-log/.gxlastpubver +++ /dev/null @@ -1 +0,0 @@ -1.0.0: QmXQEqXS3TDyhAFGBFeMadaBYJ2ismXXyQSn5i7HubcQUH diff --git a/vendor/QmQg1J6vikuXF9oDvm4wpdeAUvvkVEKW1EYDw9HhTMnP2b/go-log/context.go b/vendor/QmQg1J6vikuXF9oDvm4wpdeAUvvkVEKW1EYDw9HhTMnP2b/go-log/context.go deleted file mode 100644 index 0468047e461..00000000000 --- a/vendor/QmQg1J6vikuXF9oDvm4wpdeAUvvkVEKW1EYDw9HhTMnP2b/go-log/context.go +++ /dev/null @@ -1,38 +0,0 @@ -package log - -import ( - "errors" - - "github.com/ipfs/go-ipfs/Godeps/_workspace/src/golang.org/x/net/context" -) - -type key int - -const metadataKey key = 0 - -// ContextWithLoggable returns a derived context which contains the provided -// Loggable. Any Events logged with the derived context will include the -// provided Loggable. -func ContextWithLoggable(ctx context.Context, l Loggable) context.Context { - existing, err := MetadataFromContext(ctx) - if err != nil { - // context does not contain meta. just set the new metadata - child := context.WithValue(ctx, metadataKey, Metadata(l.Loggable())) - return child - } - - merged := DeepMerge(existing, l.Loggable()) - child := context.WithValue(ctx, metadataKey, merged) - return child -} - -func MetadataFromContext(ctx context.Context) (Metadata, error) { - value := ctx.Value(metadataKey) - if value != nil { - metadata, ok := value.(Metadata) - if ok { - return metadata, nil - } - } - return nil, errors.New("context contains no metadata") -} diff --git a/vendor/QmQg1J6vikuXF9oDvm4wpdeAUvvkVEKW1EYDw9HhTMnP2b/go-log/context_test.go b/vendor/QmQg1J6vikuXF9oDvm4wpdeAUvvkVEKW1EYDw9HhTMnP2b/go-log/context_test.go deleted file mode 100644 index 699a2edc210..00000000000 --- a/vendor/QmQg1J6vikuXF9oDvm4wpdeAUvvkVEKW1EYDw9HhTMnP2b/go-log/context_test.go +++ /dev/null @@ -1,44 +0,0 @@ -package log - -import ( - "testing" - - "github.com/ipfs/go-ipfs/Godeps/_workspace/src/golang.org/x/net/context" -) - -func TestContextContainsMetadata(t *testing.T) { - t.Parallel() - - m := Metadata{"foo": "bar"} - ctx := ContextWithLoggable(context.Background(), m) - got, err := MetadataFromContext(ctx) - if err != nil { - t.Fatal(err) - } - - _, exists := got["foo"] - if !exists { - t.Fail() - } -} - -func TestContextWithPreexistingMetadata(t *testing.T) { - t.Parallel() - - ctx := ContextWithLoggable(context.Background(), Metadata{"hello": "world"}) - ctx = ContextWithLoggable(ctx, Metadata{"goodbye": "earth"}) - - got, err := MetadataFromContext(ctx) - if err != nil { - t.Fatal(err) - } - - _, exists := got["hello"] - if !exists { - t.Fatal("original key not present") - } - _, exists = got["goodbye"] - if !exists { - t.Fatal("new key not present") - } -} diff --git a/vendor/QmQg1J6vikuXF9oDvm4wpdeAUvvkVEKW1EYDw9HhTMnP2b/go-log/entry.go b/vendor/QmQg1J6vikuXF9oDvm4wpdeAUvvkVEKW1EYDw9HhTMnP2b/go-log/entry.go deleted file mode 100644 index 63c02135c8b..00000000000 --- a/vendor/QmQg1J6vikuXF9oDvm4wpdeAUvvkVEKW1EYDw9HhTMnP2b/go-log/entry.go +++ /dev/null @@ -1,7 +0,0 @@ -package log - -type entry struct { - loggables []Loggable - system string - event string -} diff --git a/vendor/QmQg1J6vikuXF9oDvm4wpdeAUvvkVEKW1EYDw9HhTMnP2b/go-log/example_test.go b/vendor/QmQg1J6vikuXF9oDvm4wpdeAUvvkVEKW1EYDw9HhTMnP2b/go-log/example_test.go deleted file mode 100644 index f28e90b9643..00000000000 --- a/vendor/QmQg1J6vikuXF9oDvm4wpdeAUvvkVEKW1EYDw9HhTMnP2b/go-log/example_test.go +++ /dev/null @@ -1,16 +0,0 @@ -package log - -import "github.com/ipfs/go-ipfs/Godeps/_workspace/src/golang.org/x/net/context" - -func ExampleEventLogger() { - { - log := EventLogger(nil) - e := log.EventBegin(context.Background(), "dial") - e.Done() - } - { - log := EventLogger(nil) - e := log.EventBegin(context.Background(), "dial") - _ = e.Close() // implements io.Closer for convenience - } -} diff --git a/vendor/QmQg1J6vikuXF9oDvm4wpdeAUvvkVEKW1EYDw9HhTMnP2b/go-log/log.go b/vendor/QmQg1J6vikuXF9oDvm4wpdeAUvvkVEKW1EYDw9HhTMnP2b/go-log/log.go deleted file mode 100644 index d631a219f6a..00000000000 --- a/vendor/QmQg1J6vikuXF9oDvm4wpdeAUvvkVEKW1EYDw9HhTMnP2b/go-log/log.go +++ /dev/null @@ -1,170 +0,0 @@ -package log - -import ( - "encoding/json" - "fmt" - "time" - - context "github.com/ipfs/go-ipfs/Godeps/_workspace/src/golang.org/x/net/context" -) - -// StandardLogger provides API compatibility with standard printf loggers -// eg. go-logging -type StandardLogger interface { - Debug(args ...interface{}) - Debugf(format string, args ...interface{}) - Error(args ...interface{}) - Errorf(format string, args ...interface{}) - Fatal(args ...interface{}) - Fatalf(format string, args ...interface{}) - Info(args ...interface{}) - Infof(format string, args ...interface{}) - Panic(args ...interface{}) - Panicf(format string, args ...interface{}) - Warning(args ...interface{}) - Warningf(format string, args ...interface{}) -} - -// EventLogger extends the StandardLogger interface to allow for log items -// containing structured metadata -type EventLogger interface { - StandardLogger - - // Event merges structured data from the provided inputs into a single - // machine-readable log event. - // - // If the context contains metadata, a copy of this is used as the base - // metadata accumulator. - // - // If one or more loggable objects are provided, these are deep-merged into base blob. - // - // Next, the event name is added to the blob under the key "event". If - // the key "event" already exists, it will be over-written. - // - // Finally the timestamp and package name are added to the accumulator and - // the metadata is logged. - Event(ctx context.Context, event string, m ...Loggable) - - EventBegin(ctx context.Context, event string, m ...Loggable) *EventInProgress -} - -// Logger retrieves an event logger by name -func Logger(system string) EventLogger { - - // TODO if we would like to adjust log levels at run-time. Store this event - // logger in a map (just like the util.Logger impl) - if len(system) == 0 { - setuplog := getLogger("setup-logger") - setuplog.Warning("Missing name parameter") - system = "undefined" - } - - logger := getLogger(system) - - return &eventLogger{system: system, StandardLogger: logger} -} - -// eventLogger implements the EventLogger and wraps a go-logging Logger -type eventLogger struct { - StandardLogger - - system string - // TODO add log-level -} - -func (el *eventLogger) EventBegin(ctx context.Context, event string, metadata ...Loggable) *EventInProgress { - start := time.Now() - el.Event(ctx, fmt.Sprintf("%sBegin", event), metadata...) - - eip := &EventInProgress{} - eip.doneFunc = func(additional []Loggable) { - - metadata = append(metadata, additional...) // anything added during the operation - metadata = append(metadata, LoggableMap(map[string]interface{}{ // finally, duration of event - "duration": time.Now().Sub(start), - })) - - el.Event(ctx, event, metadata...) - } - return eip -} - -func (el *eventLogger) Event(ctx context.Context, event string, metadata ...Loggable) { - - // short circuit if theres nothing to write to - if !WriterGroup.Active() { - return - } - - // Collect loggables for later logging - var loggables []Loggable - - // get any existing metadata from the context - existing, err := MetadataFromContext(ctx) - if err != nil { - existing = Metadata{} - } - loggables = append(loggables, existing) - - for _, datum := range metadata { - loggables = append(loggables, datum) - } - - e := entry{ - loggables: loggables, - system: el.system, - event: event, - } - - accum := Metadata{} - for _, loggable := range e.loggables { - accum = DeepMerge(accum, loggable.Loggable()) - } - - // apply final attributes to reserved keys - // TODO accum["level"] = level - accum["event"] = e.event - accum["system"] = e.system - accum["time"] = FormatRFC3339(time.Now()) - - out, err := json.Marshal(accum) - if err != nil { - el.Errorf("ERROR FORMATTING EVENT ENTRY: %s", err) - return - } - - WriterGroup.Write(append(out, '\n')) -} - -type EventInProgress struct { - loggables []Loggable - doneFunc func([]Loggable) -} - -// Append adds loggables to be included in the call to Done -func (eip *EventInProgress) Append(l Loggable) { - eip.loggables = append(eip.loggables, l) -} - -// SetError includes the provided error -func (eip *EventInProgress) SetError(err error) { - eip.loggables = append(eip.loggables, LoggableMap{ - "error": err.Error(), - }) -} - -// Done creates a new Event entry that includes the duration and appended -// loggables. -func (eip *EventInProgress) Done() { - eip.doneFunc(eip.loggables) // create final event with extra data -} - -// Close is an alias for done -func (eip *EventInProgress) Close() error { - eip.Done() - return nil -} - -func FormatRFC3339(t time.Time) string { - return t.UTC().Format(time.RFC3339Nano) -} diff --git a/vendor/QmQg1J6vikuXF9oDvm4wpdeAUvvkVEKW1EYDw9HhTMnP2b/go-log/loggable.go b/vendor/QmQg1J6vikuXF9oDvm4wpdeAUvvkVEKW1EYDw9HhTMnP2b/go-log/loggable.go deleted file mode 100644 index d770ebaf0b2..00000000000 --- a/vendor/QmQg1J6vikuXF9oDvm4wpdeAUvvkVEKW1EYDw9HhTMnP2b/go-log/loggable.go +++ /dev/null @@ -1,34 +0,0 @@ -package log - -// Loggable describes objects that can be marshalled into Metadata for logging -type Loggable interface { - Loggable() map[string]interface{} -} - -type LoggableMap map[string]interface{} - -func (l LoggableMap) Loggable() map[string]interface{} { - return l -} - -// LoggableF converts a func into a Loggable -type LoggableF func() map[string]interface{} - -func (l LoggableF) Loggable() map[string]interface{} { - return l() -} - -func Deferred(key string, f func() string) Loggable { - function := func() map[string]interface{} { - return map[string]interface{}{ - key: f(), - } - } - return LoggableF(function) -} - -func Pair(key string, l Loggable) Loggable { - return LoggableMap{ - key: l, - } -} diff --git a/vendor/QmQg1J6vikuXF9oDvm4wpdeAUvvkVEKW1EYDw9HhTMnP2b/go-log/metadata.go b/vendor/QmQg1J6vikuXF9oDvm4wpdeAUvvkVEKW1EYDw9HhTMnP2b/go-log/metadata.go deleted file mode 100644 index 26164f7efef..00000000000 --- a/vendor/QmQg1J6vikuXF9oDvm4wpdeAUvvkVEKW1EYDw9HhTMnP2b/go-log/metadata.go +++ /dev/null @@ -1,82 +0,0 @@ -package log - -import ( - "encoding/json" - "errors" - "reflect" - - "github.com/ipfs/go-ipfs/Godeps/_workspace/src/github.com/satori/go.uuid" -) - -// Metadata is a convenience type for generic maps -type Metadata map[string]interface{} - -// Uuid returns a Metadata with the string key and UUID value -func Uuid(key string) Metadata { - return Metadata{ - key: uuid.NewV4().String(), - } -} - -// DeepMerge merges the second Metadata parameter into the first. -// Nested Metadata are merged recursively. Primitives are over-written. -func DeepMerge(b, a Metadata) Metadata { - out := Metadata{} - for k, v := range b { - out[k] = v - } - for k, v := range a { - - maybe, err := Metadatify(v) - if err != nil { - // if the new value is not meta. just overwrite the dest vaue - out[k] = v - continue - } - - // it is meta. What about dest? - outv, exists := out[k] - if !exists { - // the new value is meta, but there's no dest value. just write it - out[k] = v - continue - } - - outMetadataValue, err := Metadatify(outv) - if err != nil { - // the new value is meta and there's a dest value, but the dest - // value isn't meta. just overwrite - out[k] = v - continue - } - - // both are meta. merge them. - out[k] = DeepMerge(outMetadataValue, maybe) - } - return out -} - -// Loggable implements the Loggable interface -func (m Metadata) Loggable() map[string]interface{} { - // NB: method defined on value to avoid de-referencing nil Metadata - return m -} - -func (m Metadata) JsonString() (string, error) { - // NB: method defined on value - b, err := json.Marshal(m) - return string(b), err -} - -// Metadatify converts maps into Metadata -func Metadatify(i interface{}) (Metadata, error) { - value := reflect.ValueOf(i) - if value.Kind() == reflect.Map { - m := map[string]interface{}{} - for _, k := range value.MapKeys() { - m[k.String()] = value.MapIndex(k).Interface() - } - return Metadata(m), nil - } - return nil, errors.New("is not a map") -} diff --git a/vendor/QmQg1J6vikuXF9oDvm4wpdeAUvvkVEKW1EYDw9HhTMnP2b/go-log/metadata_test.go b/vendor/QmQg1J6vikuXF9oDvm4wpdeAUvvkVEKW1EYDw9HhTMnP2b/go-log/metadata_test.go deleted file mode 100644 index c1814511c43..00000000000 --- a/vendor/QmQg1J6vikuXF9oDvm4wpdeAUvvkVEKW1EYDw9HhTMnP2b/go-log/metadata_test.go +++ /dev/null @@ -1,50 +0,0 @@ -package log - -import "testing" - -func TestOverwrite(t *testing.T) { - t.Parallel() - - under := Metadata{ - "a": Metadata{ - "b": Metadata{ - "c": Metadata{ - "d": "the original value", - "other": "SURVIVE", - }, - }, - }, - } - over := Metadata{ - "a": Metadata{ - "b": Metadata{ - "c": Metadata{ - "d": "a new value", - }, - }, - }, - } - - out := DeepMerge(under, over) - - dval := out["a"].(Metadata)["b"].(Metadata)["c"].(Metadata)["d"].(string) - if dval != "a new value" { - t.Fatal(dval) - } - surv := out["a"].(Metadata)["b"].(Metadata)["c"].(Metadata)["other"].(string) - if surv != "SURVIVE" { - t.Fatal(surv) - } -} - -func TestMarshalJSON(t *testing.T) { - t.Parallel() - bs, _ := Metadata{"a": "b"}.JsonString() - t.Log(bs) -} - -func TestMetadataIsLoggable(t *testing.T) { - t.Parallel() - func(l Loggable) { - }(Metadata{}) -} diff --git a/vendor/QmQg1J6vikuXF9oDvm4wpdeAUvvkVEKW1EYDw9HhTMnP2b/go-log/oldlog.go b/vendor/QmQg1J6vikuXF9oDvm4wpdeAUvvkVEKW1EYDw9HhTMnP2b/go-log/oldlog.go deleted file mode 100644 index b20b6c7fbfc..00000000000 --- a/vendor/QmQg1J6vikuXF9oDvm4wpdeAUvvkVEKW1EYDw9HhTMnP2b/go-log/oldlog.go +++ /dev/null @@ -1,105 +0,0 @@ -package log - -import ( - "errors" - "fmt" - "os" - - logging "github.com/ipfs/go-ipfs/Godeps/_workspace/src/github.com/whyrusleeping/go-logging" -) - -func init() { - SetupLogging() -} - -var ansiGray = "\033[0;37m" -var ansiBlue = "\033[0;34m" - -var LogFormats = map[string]string{ - "nocolor": "%{time:2006-01-02 15:04:05.000000} %{level} %{module} %{shortfile}: %{message}", - "color": ansiGray + "%{time:15:04:05.000} %{color}%{level:5.5s} " + ansiBlue + - "%{module:10.10s}: %{color:reset}%{message} " + ansiGray + "%{shortfile}%{color:reset}", -} - -var defaultLogFormat = "color" - -// Logging environment variables -const ( - envLogging = "IPFS_LOGGING" - envLoggingFmt = "IPFS_LOGGING_FMT" -) - -// ErrNoSuchLogger is returned when the util pkg is asked for a non existant logger -var ErrNoSuchLogger = errors.New("Error: No such logger") - -// loggers is the set of loggers in the system -var loggers = map[string]*logging.Logger{} - -// SetupLogging will initialize the logger backend and set the flags. -func SetupLogging() { - - lfmt := LogFormats[os.Getenv(envLoggingFmt)] - if lfmt == "" { - lfmt = LogFormats[defaultLogFormat] - } - - backend := logging.NewLogBackend(os.Stderr, "", 0) - logging.SetBackend(backend) - logging.SetFormatter(logging.MustStringFormatter(lfmt)) - - lvl := logging.ERROR - - if logenv := os.Getenv(envLogging); logenv != "" { - var err error - lvl, err = logging.LogLevel(logenv) - if err != nil { - fmt.Println("error setting log levels", err) - } - } - - SetAllLoggers(lvl) -} - -// SetDebugLogging calls SetAllLoggers with logging.DEBUG -func SetDebugLogging() { - SetAllLoggers(logging.DEBUG) -} - -// SetAllLoggers changes the logging.Level of all loggers to lvl -func SetAllLoggers(lvl logging.Level) { - logging.SetLevel(lvl, "") - for n := range loggers { - logging.SetLevel(lvl, n) - } -} - -// SetLogLevel changes the log level of a specific subsystem -// name=="*" changes all subsystems -func SetLogLevel(name, level string) error { - lvl, err := logging.LogLevel(level) - if err != nil { - return err - } - - // wildcard, change all - if name == "*" { - SetAllLoggers(lvl) - return nil - } - - // Check if we have a logger by that name - if _, ok := loggers[name]; !ok { - return ErrNoSuchLogger - } - - logging.SetLevel(lvl, name) - - return nil -} - -func getLogger(name string) *logging.Logger { - log := logging.MustGetLogger(name) - log.ExtraCalldepth = 1 - loggers[name] = log - return log -} diff --git a/vendor/QmQg1J6vikuXF9oDvm4wpdeAUvvkVEKW1EYDw9HhTMnP2b/go-log/option.go b/vendor/QmQg1J6vikuXF9oDvm4wpdeAUvvkVEKW1EYDw9HhTMnP2b/go-log/option.go deleted file mode 100644 index 461cb748036..00000000000 --- a/vendor/QmQg1J6vikuXF9oDvm4wpdeAUvvkVEKW1EYDw9HhTMnP2b/go-log/option.go +++ /dev/null @@ -1,52 +0,0 @@ -package log - -import ( - "io" - - logging "github.com/ipfs/go-ipfs/Godeps/_workspace/src/github.com/whyrusleeping/go-logging" -) - -// Global writer group for logs to output to -var WriterGroup = NewMirrorWriter() - -type Option func() - -// Configure applies the provided options sequentially from left to right -func Configure(options ...Option) { - for _, f := range options { - f() - } -} - -// LdJSONFormatter Option formats the event log as line-delimited JSON -var LdJSONFormatter = func() { - logging.SetFormatter(&PoliteJSONFormatter{}) -} - -// TextFormatter Option formats the event log as human-readable plain-text -var TextFormatter = func() { - logging.SetFormatter(logging.DefaultFormatter) -} - -func Output(w io.Writer) Option { - return func() { - backend := logging.NewLogBackend(w, "", 0) - logging.SetBackend(backend) - // TODO return previous Output option - } -} - -// LevelDebug Option sets the log level to debug -var LevelDebug = func() { - logging.SetLevel(logging.DEBUG, "") -} - -// LevelError Option sets the log level to error -var LevelError = func() { - logging.SetLevel(logging.ERROR, "") -} - -// LevelInfo Option sets the log level to info -var LevelInfo = func() { - logging.SetLevel(logging.INFO, "") -} diff --git a/vendor/QmQg1J6vikuXF9oDvm4wpdeAUvvkVEKW1EYDw9HhTMnP2b/go-log/package.json b/vendor/QmQg1J6vikuXF9oDvm4wpdeAUvvkVEKW1EYDw9HhTMnP2b/go-log/package.json deleted file mode 100644 index 85643f96788..00000000000 --- a/vendor/QmQg1J6vikuXF9oDvm4wpdeAUvvkVEKW1EYDw9HhTMnP2b/go-log/package.json +++ /dev/null @@ -1,8 +0,0 @@ -{ - "name": "go-log", - "version": "1.0.0", - "language": "go", - "go":{ - "dvcsimport":"github.com/ipfs/go-log" - } -} diff --git a/vendor/QmQg1J6vikuXF9oDvm4wpdeAUvvkVEKW1EYDw9HhTMnP2b/go-log/polite_json_formatter.go b/vendor/QmQg1J6vikuXF9oDvm4wpdeAUvvkVEKW1EYDw9HhTMnP2b/go-log/polite_json_formatter.go deleted file mode 100644 index 0814716938d..00000000000 --- a/vendor/QmQg1J6vikuXF9oDvm4wpdeAUvvkVEKW1EYDw9HhTMnP2b/go-log/polite_json_formatter.go +++ /dev/null @@ -1,28 +0,0 @@ -package log - -import ( - "encoding/json" - "io" - - logging "github.com/ipfs/go-ipfs/Godeps/_workspace/src/github.com/whyrusleeping/go-logging" -) - -// PoliteJSONFormatter marshals entries into JSON encoded slices (without -// overwriting user-provided keys). How polite of it! -type PoliteJSONFormatter struct{} - -func (f *PoliteJSONFormatter) Format(calldepth int, r *logging.Record, w io.Writer) error { - entry := make(map[string]interface{}) - entry["id"] = r.Id - entry["level"] = r.Level - entry["time"] = r.Time - entry["module"] = r.Module - entry["message"] = r.Message() - err := json.NewEncoder(w).Encode(entry) - if err != nil { - return err - } - - w.Write([]byte{'\n'}) - return nil -} diff --git a/vendor/QmQg1J6vikuXF9oDvm4wpdeAUvvkVEKW1EYDw9HhTMnP2b/go-log/writer.go b/vendor/QmQg1J6vikuXF9oDvm4wpdeAUvvkVEKW1EYDw9HhTMnP2b/go-log/writer.go deleted file mode 100644 index 50cdf76ad8f..00000000000 --- a/vendor/QmQg1J6vikuXF9oDvm4wpdeAUvvkVEKW1EYDw9HhTMnP2b/go-log/writer.go +++ /dev/null @@ -1,251 +0,0 @@ -package log - -import ( - "fmt" - "io" - "sync" -) - -var MaxWriterBuffer = 512 * 1024 - -var log = Logger("eventlog") - -type MirrorWriter struct { - active bool - activelk sync.Mutex - - // channel for incoming writers - writerAdd chan *writerAdd - - // slices of writer/sync-channel pairs - writers []*bufWriter - - // synchronization channel for incoming writes - msgSync chan []byte -} - -type writerSync struct { - w io.WriteCloser - br chan []byte -} - -func NewMirrorWriter() *MirrorWriter { - mw := &MirrorWriter{ - msgSync: make(chan []byte, 64), // sufficiently large buffer to avoid callers waiting - writerAdd: make(chan *writerAdd), - } - - go mw.logRoutine() - - return mw -} - -func (mw *MirrorWriter) Write(b []byte) (int, error) { - mycopy := make([]byte, len(b)) - copy(mycopy, b) - mw.msgSync <- mycopy - return len(b), nil -} - -func (mw *MirrorWriter) Close() error { - // it is up to the caller to ensure that write is not called during or - // after close is called. - close(mw.msgSync) - return nil -} - -func (mw *MirrorWriter) doClose() { - for _, w := range mw.writers { - w.writer.Close() - } -} - -func (mw *MirrorWriter) logRoutine() { - // rebind to avoid races on nilling out struct fields - msgSync := mw.msgSync - writerAdd := mw.writerAdd - - defer mw.doClose() - - for { - select { - case b, ok := <-msgSync: - if !ok { - return - } - - // write to all writers - dropped := mw.broadcastMessage(b) - - // consolidate the slice - if dropped { - mw.clearDeadWriters() - } - case wa := <-writerAdd: - mw.writers = append(mw.writers, newBufWriter(wa.w)) - - mw.activelk.Lock() - mw.active = true - mw.activelk.Unlock() - close(wa.done) - } - } -} - -// broadcastMessage sends the given message to every writer -// if any writer is killed during the send, 'true' is returned -func (mw *MirrorWriter) broadcastMessage(b []byte) bool { - var dropped bool - for i, w := range mw.writers { - _, err := w.Write(b) - if err != nil { - mw.writers[i] = nil - dropped = true - } - } - return dropped -} - -func (mw *MirrorWriter) clearDeadWriters() { - writers := mw.writers - mw.writers = nil - for _, w := range writers { - if w != nil { - mw.writers = append(mw.writers, w) - } - } - if len(mw.writers) == 0 { - mw.activelk.Lock() - mw.active = false - mw.activelk.Unlock() - } -} - -type writerAdd struct { - w io.WriteCloser - done chan struct{} -} - -func (mw *MirrorWriter) AddWriter(w io.WriteCloser) { - wa := &writerAdd{ - w: w, - done: make(chan struct{}), - } - mw.writerAdd <- wa - <-wa.done -} - -func (mw *MirrorWriter) Active() (active bool) { - mw.activelk.Lock() - active = mw.active - mw.activelk.Unlock() - return -} - -func newBufWriter(w io.WriteCloser) *bufWriter { - bw := &bufWriter{ - writer: w, - incoming: make(chan []byte, 1), - } - - go bw.loop() - return bw -} - -type bufWriter struct { - writer io.WriteCloser - - incoming chan []byte - - deathLock sync.Mutex - dead bool -} - -var errDeadWriter = fmt.Errorf("writer is dead") - -func (bw *bufWriter) Write(b []byte) (int, error) { - bw.deathLock.Lock() - dead := bw.dead - bw.deathLock.Unlock() - if dead { - if bw.incoming != nil { - close(bw.incoming) - bw.incoming = nil - } - return 0, errDeadWriter - } - - bw.incoming <- b - return len(b), nil -} - -func (bw *bufWriter) die() { - bw.deathLock.Lock() - bw.dead = true - bw.writer.Close() - bw.deathLock.Unlock() -} - -func (bw *bufWriter) loop() { - bufsize := 0 - bufBase := make([][]byte, 0, 16) // some initial memory - buffered := bufBase - nextCh := make(chan []byte) - - var nextMsg []byte - - go func() { - for b := range nextCh { - _, err := bw.writer.Write(b) - if err != nil { - log.Info("eventlog write error: %s", err) - bw.die() - return - } - } - }() - - // collect and buffer messages - incoming := bw.incoming - for { - if nextMsg == nil || nextCh == nil { - // nextCh == nil implies we are 'dead' and draining the incoming channel - // until the caller notices and closes it for us - select { - case b, ok := <-incoming: - if !ok { - return - } - nextMsg = b - } - } - - select { - case b, ok := <-incoming: - if !ok { - return - } - bufsize += len(b) - buffered = append(buffered, b) - if bufsize > MaxWriterBuffer { - // if we have too many messages buffered, kill the writer - bw.die() - close(nextCh) - nextCh = nil - // explicity keep going here to drain incoming - } - case nextCh <- nextMsg: - nextMsg = nil - if len(buffered) > 0 { - nextMsg = buffered[0] - buffered = buffered[1:] - bufsize -= len(nextMsg) - } - - if len(buffered) == 0 { - // reset slice position - buffered = bufBase[:0] - } - } - } -} diff --git a/vendor/QmQg1J6vikuXF9oDvm4wpdeAUvvkVEKW1EYDw9HhTMnP2b/go-log/writer_test.go b/vendor/QmQg1J6vikuXF9oDvm4wpdeAUvvkVEKW1EYDw9HhTMnP2b/go-log/writer_test.go deleted file mode 100644 index a6b281006b6..00000000000 --- a/vendor/QmQg1J6vikuXF9oDvm4wpdeAUvvkVEKW1EYDw9HhTMnP2b/go-log/writer_test.go +++ /dev/null @@ -1,160 +0,0 @@ -package log - -import ( - "fmt" - "hash/fnv" - "io" - "sync" - "testing" - "time" - - randbo "github.com/ipfs/go-ipfs/Godeps/_workspace/src/github.com/dustin/randbo" -) - -type hangwriter struct { - c chan struct{} -} - -func newHangWriter() *hangwriter { - return &hangwriter{make(chan struct{})} -} - -func (hw *hangwriter) Write([]byte) (int, error) { - <-make(chan struct{}) - return 0, fmt.Errorf("write on closed writer") -} - -func (hw *hangwriter) Close() error { - close(hw.c) - return nil -} - -func TestMirrorWriterHang(t *testing.T) { - mw := NewMirrorWriter() - - hw := newHangWriter() - pr, pw := io.Pipe() - - mw.AddWriter(hw) - mw.AddWriter(pw) - - msg := "Hello!" - mw.Write([]byte(msg)) - - // make sure writes through can happen even with one writer hanging - done := make(chan struct{}) - go func() { - buf := make([]byte, 10) - n, err := pr.Read(buf) - if err != nil { - t.Fatal(err) - } - - if n != len(msg) { - t.Fatal("read wrong amount") - } - - if string(buf[:n]) != msg { - t.Fatal("didnt read right content") - } - - done <- struct{}{} - }() - - select { - case <-time.After(time.Second * 5): - t.Fatal("write to mirrorwriter hung") - case <-done: - } - - if !mw.Active() { - t.Fatal("writer should still be active") - } - - pw.Close() - - if !mw.Active() { - t.Fatal("writer should still be active") - } - - // now we just have the hangwriter - - // write a bunch to it - buf := make([]byte, 8192) - for i := 0; i < 128; i++ { - mw.Write(buf) - } - - // wait for goroutines to sync up - time.Sleep(time.Millisecond * 500) - - // the hangwriter should have been killed, causing the mirrorwriter to be inactive now - if mw.Active() { - t.Fatal("should be inactive now") - } -} - -func TestStress(t *testing.T) { - mw := NewMirrorWriter() - - nreaders := 20 - - var readers []io.Reader - for i := 0; i < nreaders; i++ { - pr, pw := io.Pipe() - mw.AddWriter(pw) - readers = append(readers, pr) - } - - hashout := make(chan []byte) - - numwriters := 20 - writesize := 1024 - writecount := 300 - - f := func(r io.Reader) { - h := fnv.New64a() - sum, err := io.Copy(h, r) - if err != nil { - t.Fatal(err) - } - - if sum != int64(numwriters*writesize*writecount) { - t.Fatal("read wrong number of bytes") - } - - hashout <- h.Sum(nil) - } - - for _, r := range readers { - go f(r) - } - - work := sync.WaitGroup{} - for i := 0; i < numwriters; i++ { - work.Add(1) - go func() { - defer work.Done() - r := randbo.New() - buf := make([]byte, writesize) - for j := 0; j < writecount; j++ { - r.Read(buf) - mw.Write(buf) - time.Sleep(time.Millisecond * 5) - } - }() - } - - work.Wait() - mw.Close() - - check := make(map[string]bool) - for i := 0; i < nreaders; i++ { - h := <-hashout - check[string(h)] = true - } - - if len(check) > 1 { - t.Fatal("writers received different data!") - } -} diff --git a/vendor/QmdDfkqDWheE4gsCXNrhixwTwSHnZMPT2cGLcNbiBNcMyU/dir-index-html/.gxlastpubver b/vendor/QmdDfkqDWheE4gsCXNrhixwTwSHnZMPT2cGLcNbiBNcMyU/dir-index-html/.gxlastpubver deleted file mode 100644 index 8e66c770e65..00000000000 --- a/vendor/QmdDfkqDWheE4gsCXNrhixwTwSHnZMPT2cGLcNbiBNcMyU/dir-index-html/.gxlastpubver +++ /dev/null @@ -1 +0,0 @@ -QmeZ95gjQtxEbMbnttTiViadqjVb2JDZqQDsYQA4BBZpE4 \ No newline at end of file diff --git a/vendor/QmdDfkqDWheE4gsCXNrhixwTwSHnZMPT2cGLcNbiBNcMyU/dir-index-html/README.md b/vendor/QmdDfkqDWheE4gsCXNrhixwTwSHnZMPT2cGLcNbiBNcMyU/dir-index-html/README.md deleted file mode 100644 index 52bbb47b5ea..00000000000 --- a/vendor/QmdDfkqDWheE4gsCXNrhixwTwSHnZMPT2cGLcNbiBNcMyU/dir-index-html/README.md +++ /dev/null @@ -1,6 +0,0 @@ -# dir-index-html - -directory listing html for go-ipfs gateways. - -![](http://gateway.ipfs.io/ipfs/Qmf82jUC9ZuoSTCNY55hyx3HmiDed3WnhFD5PC7CTSPmC2/cap.png) - diff --git a/vendor/QmdDfkqDWheE4gsCXNrhixwTwSHnZMPT2cGLcNbiBNcMyU/dir-index-html/dir-index-uncat.html b/vendor/QmdDfkqDWheE4gsCXNrhixwTwSHnZMPT2cGLcNbiBNcMyU/dir-index-html/dir-index-uncat.html deleted file mode 100644 index 0f233a11dfe..00000000000 --- a/vendor/QmdDfkqDWheE4gsCXNrhixwTwSHnZMPT2cGLcNbiBNcMyU/dir-index-html/dir-index-uncat.html +++ /dev/null @@ -1,62 +0,0 @@ - - - - - - - - - - {{ .Path }} - - - -
-
-
-
- Index of {{ .Path }} -
- - - - - - - {{ range .Listing }} - - - - - - {{ end }} -
-
 
-
- .. -
-
 
-
- {{ .Name }} - {{ .Size }}
-
-
- - diff --git a/vendor/QmdDfkqDWheE4gsCXNrhixwTwSHnZMPT2cGLcNbiBNcMyU/dir-index-html/dir-index.html b/vendor/QmdDfkqDWheE4gsCXNrhixwTwSHnZMPT2cGLcNbiBNcMyU/dir-index-html/dir-index.html deleted file mode 100644 index 40c28faf1bc..00000000000 --- a/vendor/QmdDfkqDWheE4gsCXNrhixwTwSHnZMPT2cGLcNbiBNcMyU/dir-index-html/dir-index.html +++ /dev/null @@ -1,60 +0,0 @@ - - - - - - - {{ .Path }} - - - -
-
-
-
- Index of {{ .Path }} -
- - - - - - - {{ range .Listing }} - - - - - - {{ end }} -
-
 
-
- .. -
-
 
-
- {{ .Name }} - {{ .Size }}
-
-
- - diff --git a/vendor/QmdDfkqDWheE4gsCXNrhixwTwSHnZMPT2cGLcNbiBNcMyU/dir-index-html/gw-assets/bootstrap.min.css b/vendor/QmdDfkqDWheE4gsCXNrhixwTwSHnZMPT2cGLcNbiBNcMyU/dir-index-html/gw-assets/bootstrap.min.css deleted file mode 100644 index cd1c616ad86..00000000000 --- a/vendor/QmdDfkqDWheE4gsCXNrhixwTwSHnZMPT2cGLcNbiBNcMyU/dir-index-html/gw-assets/bootstrap.min.css +++ /dev/null @@ -1,5 +0,0 @@ -/*! - * Bootstrap v3.3.4 (http://getbootstrap.com) - * Copyright 2011-2015 Twitter, Inc. - * Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE) - *//*! 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 diff --git a/vendor/QmdDfkqDWheE4gsCXNrhixwTwSHnZMPT2cGLcNbiBNcMyU/dir-index-html/gw-assets/icons.css b/vendor/QmdDfkqDWheE4gsCXNrhixwTwSHnZMPT2cGLcNbiBNcMyU/dir-index-html/gw-assets/icons.css deleted file mode 100644 index d25bcdd36e5..00000000000 --- a/vendor/QmdDfkqDWheE4gsCXNrhixwTwSHnZMPT2cGLcNbiBNcMyU/dir-index-html/gw-assets/icons.css +++ /dev/null @@ -1,384 +0,0 @@ - -.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+MjU2PC9leGlmOlBpeGVsWURpbWVuc2lvbj4KICAgICAgICAgPGRjOnN1YmplY3Q+CiAgICAgICAgICAgIDxyZGY6QmFnLz4KICAgICAgICAgPC9kYzpzdWJqZWN0PgogICAgICAgICA8eG1wOk1vZGlmeURhdGU+MjAxNTowMjoxNiAwMDowMjo4ODwveG1wOk1vZGlmeURhdGU+CiAgICAgICAgIDx4bXA6Q3JlYXRvclRvb2w+UGl4ZWxtYXRvciAzLjMuMTwveG1wOkNyZWF0b3JUb29sPgogICAgICA8L3JkZjpEZXNjcmlwdGlvbj4KICAgPC9yZGY6UkRGPgo8L3g6eG1wbWV0YT4KqqO/2AAAQABJREFUeAHtnQecXFXZ/+/W2dmd7Uk2mx469sJfQJHXKKCiiA2UEl+KRiyI8NrA8oIVeVVQEAERUQRRwAIIhmIihBAg1JhGetmS7X1nZ2d2/7/f3b2whE323LlT7sz8Dp+Hu5m559xzv/fO3N+c85znybNUcpLAWauePqpr544HRqLRorzR0ZP+fsYnHspJEDppERABERABEchBAnk5eM45fcpL1q2r3/3E6uuLSoIfiEaG8gmjoDgwOtCy57G6N7z2tFsXLdqd04B08iIgAiIgAiKQAwQkAHPgIvMUl6xeXdqyZdvFI9GRr+QV5JdEw2FrdGTEPvu8/HyrsKTEGhmORsNdHTcuPPrI/7nhiCMGcgSNTlMEREAEREAEco6ABGAOXPJP3P2Pk/vaO64vKiuto/DDtO+kZ51fWGgLwXBXV/fo4MCFSy84/7eT7qgXRUAEREAEREAEMpqABGBGX779d/6c5zcc2vTUqlsDlRVvgfDLGxke3n+F8Xfzi4qswkDA6mtu3lw6ve7Uu0/7+LNGFbWTCIiACIiACIhARhCQAMyIy+Suk+euXVvT8NiqnxaVlS3Oy8sriA0NWaOjo64aQT2rACIQ08Qjvbt33z9v0bH//fsjj2x31Yh2FgEREAEREAER8CUBCUBfXpb4OgU/v6LmDVu+NBIbvrSgpCQUGxy0oN/ia2y8Vj78AwuCQWu4r28o3Nl15UHvOuY78A80G0r0dGRVFgEREAEREAERSBYBCcBkkU1xu6c9tPz4ru1bfxOoqJwbxYif6XSvaTedaeGB1pZ2a9T64gNf/NztpnW1nwiIgAiIgAiIgL8ISAD663q47s2StWvn7Vz5xB8ClZXHjEQieTH6+bmc7jU+KKeF4R9IMdjb2PCf0LSaj9+9ePFG4/raUQREQAREQAREwBcEJAB9cRncd+KMVasq2tdu+GFRcfGSvMLCItvPz+N0r2kvGDbG9g+MDsf6W1r/XP+Oo8679aijekzraz8REAEREAEREIH0EpAATC//uI7+kdvvOCMSDl9dWFpabfv5xWJxteO1Un5Bge0fGOnp6Y90tH/z4a995ede21R9ERABERABERCB5BOQAEw+44Qd4VMrn3rznv+8cGtJZeXhsUgk4X5+8XaUU8IFxcUMG7O7qDiw+J+f+8zyeNtSPREQAREQAREQgeQTkABMPmPPR/j0mjV1u1c99euSUOgDsZGRfPj6uQ7r4rkTUzTAsDH5EIFYNTza07D78eqF8z/xl499TGnlpuCmt0VABERABEQgHQQkANNB3fCYZ23bVtL80CNfLygq+EZhSeAV6dsMm0j5bk5aueH+wWhvY+OvDzzzExfdvHBhOOUd0QFFQAREQAREQAT2SUACcJ9o0vvGR+74y8nhru7ri8vL62IRhHXZR/q2VPTSHt1Dmjh7hbHhAZlWrqA4YA12dHRHerv/Z/nXv/obw6raTQREQAREQAREIMkEJACTDNht82c9u+7gpiceu72kpubNI0NDeTEKP8OwLhRcpbU1tlCD8GIWD7eHf9X+hQgCHZpZbwXKy63Bzk6rf0+zRf9Do8KwMRCCnBru3d2wpShUfurSz57zjFFd7SQCIiACIiACIpA0AhKASUPrruHPvfBC9eZHHvt5oLLq9PyC/AKKLFMBl19QaAWn1VpldTPt8Cw8cqSv1xpoabGGenrcLxaBcCuC8AvWTkO70yyO5jmFo5H9zc3WYFu7NRKDODUodtgYiMCRaGyke8f2B+a86fWL/3jSSW0GVbWLCIiACIiACIhAEghIACYBqpsm37VsWWFw244v51l5lyJ3b1ksHIawMgzrAqFWUlVthWbNsopKSyc9bBTtDXV3WQjVYkUHwxgdxOgdRxRRd2LJY0gXrOZFH6yS6hqrOBSy+Nq+yvDAgNXX2GiFuzqNRyjtsDElJexLpG9P8y8K3nH0xcsXLTJTkfvqiF4XAREQAREQARFwTeCVKsB1dVXwQuCUfyw9vmfXrt+UVFfNdRvWhYIvVD8LYq36VWJuX31iejja6CRTyhzlo+1P9L2qXbQTxrRwX1OjRUFoWpywMf179rSPRqNffPiiC5RWzhSe9hMBERABERCBBBCQAEwARLdNnPfcxtnbVi6/vaS29h0QZK7St1E8lc2YYZXOqHvF1KzbPiRyfy5QGWjZY/Vjytk4BzH9A3EuFJ09O3euDZaWf/S+Ly55MZH9UlsiIAIiIAIiIAKTE5AAnJxLUl49Z8WG8oYXll9RWBY6t6CouIj+dKZ+fvSjK4U/XmldnVVYEkxK/7w2Gg0PWgN79lgDbW2uzouLV2JD4ZHeXTv/PveI48669USllfN6LVRfBERABERABPZHQAJwf3QS917eib+7ZcnIcOzHxaGySqzuNffzQx8CFRX2dG8xtplQ6G/IaWEuQDEt9A/MDwTgU9gzONje8qNHv3nx91EXzooqIiACIiACIiACiSYgAZhoonu1d9pDy4/u3LLpFqzuPZBx9IynSNFOIRZM2H5+NTUWRwAzqXBkM4xQNBSCXIhiWmz/QEwNI9zMntFo7NMP/8+X7zWtq/1EQAREQAREQATMCEgAmnFyvddZT66d2bBq2c3B6TNOgBjKs2PnTbL4YrKG6RdXBh+/Uvj6URBlcqHgZTiafvgIGgezpn8gwsZA9I52b9n8dKBy+qkPnP+ZbZnMQX0XAREQAREQAT8RkABM8NVYsnp16c7VT19aECy9AH5+xW7i+THjBkOwhOrrrcJ9hHVJcHdT1lyUYWOamrBqGAGqDYWwEz8wOhSO9e3aeethJ77/czcccYT5cuOUnZ0OJAIiIAIiIAKZRUACMIHX66SbbzktGo1ejRh6tXZYFxfp24pD5Yjnh4wblVUJ7JH/mmJMwr7GJjtQtWnvOCLKEcFwR2f/QEvztx699DtXmdbVfiIgAiIgAiIgAq8mIAH4aiauX1n8+OOHNz25+k9Yofv6keFoHH5+9VZJTW3G+fm5BjVeYcw/sN0eEXTrH5hfhLAx27bvyCuwzlj2ta89Fm8fVE8EREAEREAEcpmABKCHq79k48Zp25Y+dC3y9n4MmTXy6e9mGtaFo1qM5VeGsC78OxcLfQIRDNqOIWjqH8hpYfpFYhqZ/oGPVB9y0Ol3n3ZaYy7y0zmLgAiIgAiIQLwEJADjIHf+ffcFXtzV8LXCQMnFsCB81IyFH1OwBZG9g6t7s83PLw6UdpUx/8BGaxBZRew0dQYNUQiCvRUZ6B9G/MBfv/ltR1x09YknDhlU1S4iIAIiIAIikPMEJABd3gIn3/ank4Z6em8IVFfNjA1FsLJ12LiF4rKQVVY/087fu3cuXuNGsnVHppVDXuH+pmYr0t9nfJb5hUVWQaCYK427w+1tX4F/4I3GlbWjCIiACIiACOQoAQlAwwv/6ec3LNz56LI7g9Onv3kkgvRtFH6Gq1m5gKFs5kxk8pjuLteuYd+yabfRWAyZRFqt/uZmyw6dY3JyDBsDIWj7B+7YsTUvr+CUf33twmdMqmofERABERABEchFAhKAU1z1Jau3VG57fOnPiysrzoTIKHAT1oXZLYIQfRR/FIEq5gTImSJwEGJwBKLQpDhhY2LDkZHubdsfqK4/cPE9nz29zaSu9hEBERABERCBXCIgAbiPq33ppaP5T9Tf+CUrP/97xeUVoZjL9G0lVVW2n19RKLSPI+hlEwLDfX12NpFwV5fJ7vY+FN4FSCs31NU51NfYeNVx+f97yaWX5o0YN6AdRUAEREAERCDLCUgATnKBT7rttmPCHd1/wJTtfIwmuQrrUlRWZoUw4seAzvLzmwRuPC/RPxABpPswIjjc32/cwlhauWKrt2F3W39r83lPXH75XcaVtaMIiIAIiIAIZDEBCcAJF3fJunX1m5Y+dFvZ9On/BTB5zN3rys+vDn5+0+XnNwFpQv+0/QNb4R+4x6V/4FjYGKtr29Y1RYGiU5Z9/esbE9oxNSYCIiACIiACGUZAAhAXjOnbtqxcdUWgvGIJQosUxSJDxmFd6HcWRBBnpm8rKCnJsMufmd2NhcN2EOnBjnZX16mgOGBFBwdGunZs/+u0+XPPvvvcc3szk4B6LQIiIAIiIALeCBR4q575tY//+TWLe/e0PlhaO+1YjPbZizxMR/0CFRVW5fwF9iKPXA3mnI47gKxLEEsRKfcwPR+x6J85ZcE0MoNNY1o4L1RX/5pwd+8Fta95TbTh8ZXKJjIlPO0gAiIgAiKQbQRydgTwlAcffH3H2o13lM2YfihXmTKLh2kpxEgfV/YGa6flTPo2Uzap3o+ZVwbb2+wVw67TymGxSPeOnU2Rwd7Fj3/3uw+nuu86ngiIgAiIgAiki0DOCcDFzz8/o/Hh5TeVTp/xfis/jvRt02eMpW+DX5mKfwhQwNtp5Vpb7JE+k569lFZuZHS0c9OLq/OCxZ9ccfHFW03qah8REAEREAERyGQCOSMA4edXtO2xVZcVlZdfhBG8QCzCvL2G8eUQaBj5frG6t17p23x+t9tp5ZqbrHBHB2byR416m5ePsDHFRdbwwECsa8uWP7z+Yx/+zA1HHGE+JGx0FO0kAiIgAiIgAv4hkBMC8H3X/OojsdHR6xCUeQZHilylb4OfWWjWbCtQWemfq6aeTElgqLvb6mtssCKII2hamFaOoWNQr7d/186Ln7jqZ780rav9REAEREAERCCTCGS1ADzz6acPavj3o3eUz6x/0wh8xWw/P8NRIdvPb0adhdRv8vPLpDt6Ql9t/0CGjWnZYxn7B2K0lyIwH6u7O7du2R6NRs54/NJLV05oVn+KgAiIgAiIQMYTyEoBeO7atTXb7n/gV2XTZ3w8r6gw3136tkKrdAbStyGmH4WASuYTGPMPbLYGWphWLmp0Qk5auZHh6GjHpo2PlNRUnfGviy5qMKqsnURABERABETA5wSyLAzMaN67r6r9eri17e5gbe2bsLrXOJhzHkZ+gvDzq1ywAPl7sboXK0RVsoMAr2WgohJWYTGYNOMITlnGw8bk5eflIcbjAux/fs1hh09vWLnin5Z12ZTVtYMIiIAIiIAI+JlA1owAvu9XN7w3OjT0m9K6utmM92ZP9xqSZzy5MizwKKmuQo2sQWJ49rm2G9PKdSFsTJM7/0BOCyP+YO+unV3IL3zhU1f97OZcI6fzFQEREAERyB4CGa92zl6zZu72pQ/+OVQ/60hcljxO95oGci4oLrbj+SHnr0b8sueeNjoTO61cG/wDkV/YvmdMamGUmPcM76/OzZtehFfpJ1ZeeulzJlW1jwiIgAiIgAj4iUDGCsBTVq4Mtjy68qpQXd05SPFV6CZ9Wz6mBDnNSz+/gkDAT9dDfUkxAWYRYW7hwbY2+AcahgXCAhGmlYuFB0da16+/LzIcXvzcVVd1pbjrOpwIiIAIiIAIxE0gIx3d3vXTqz4ba29fCgH3dozG2Is8TEf9SqqqrIoFCy0Egran9OImp4pZQYDTuoHKKqu4HP6B0WGz1cLj/oGom1c+e84hxSUlX64+9LBA06rHl2UFFJ2ECIiACIhA1hPIqBHAD/7ud0eHu7pvDU6rW8ggzm78/AqDQQvTxPZCDwtTeSoi8CoCEHaDCCDd19RoRQcHX/X2vl7ganEGk+7dvaNtoLlpyZNXXvnXfe2r10VABERABETADwQyQgl9es2auq1LH7qtrK5uEQK05Y0wi8foiBE/288PU72c8uVoj4oITEWAi4g4JcypYVP/wLy8fCsf2UQsTCN3bt68ZnRk+JTHvv/9jVMdS++LgAiIgAiIQDoI+HoK+JS1a4tnzFlwOUb9bi+pqT0IU3R5fDjDC39KVozjVgrRV4npXk778t8qImBCgPcKV4YHcN8gX+DYtDBGB/dfRu0QM/xFVVo3s64oWPq56gMOPrz+/e+9v2n5cqWV2z88vSsCIiACIpBiAr4VgO/5yZVnDO1qeDg0a9Z7MGVbwJEY09yuAfhzVSyYPxbMWaN+Kb6lsudwHDEuqaq2ikJlFkedudBoqsJ7lD9SMPKcXzFv3usKorELaw8+ONr45BOPTVVX74uACIiACIhAqgj4bgr45D//7TW9u7beFZo567ARPkyRu9d0gQfTt4UYz6+2ViN+qbqDcuQ4TCsXbm+3+hA/0HVaOficdm3b0tTX3HrmM9dc9a8cQabTFAEREAER8DEB3wjAL6xfX7vmrr/8unz23JPzMXpC4ceHrkkpgBN+KXL2liJ3r9K3mRDTPvES4H05gNzCA8gxHOOPE4PCKWXelxjFHm1du2ZVdHTktGd/+tMdBlW1iwiIgAiIgAgkhUDaBeApf/5zQeumbT8orZv+5cLSsgAfsG7isZVUV9ure7nKV0UEUkWAq4S5Wjjc2Wn8Q4XxJykEw50d0faNG2+2wgOff/qGG8xUZKpOTMcRAREQARHICQJp9QF8z49//PGBgcFl5XPmnmDlFyCYs7mfX3Go3KqcvwDir16jfjlxq/rrJCnkSqprrKKyMis2FDFaLez4BxaWluZXzp//FtzzF9YcsHCw6emnV/nr7NQbERABERCBbCeQlhHAT/zjH4c0Pf+fOyvnzXs9AdtTaVOushy7FMzcEZrJsC5I36aVvdl+f2bE+dFVYRBp5fqYVg6ZRYwK/ALpusDSvmHjrkhX26dWX3PNcvsF/U8EREAEREAEkkwgpQLwrGefrdp239Jfl82q/yhSabny8xtL3zbdFn/wEUwyFjUvAu4JjGAEmyKQYtCNGwNHE6ORodGOtWtXRoeHTn/65z/f6f7oqiECIiACIiAC5gRSNgV8zPd/+I1IR9fdZfX1b7RGRvPcrO6lnx+ne7nQIw9+VCoi4EcCvDcDlZUWwxCNxKJmq4Ux8j2K4NEFBQV55XPnzisOlp1fPn9BffPqp+7z4zmqTyIgAiIgAtlBIOkjgMf9389OjlmjvwrNml3PqTJb+Bmyo38VffwYi03p2wyhaTd/EICwC3d1YqFIkzXc32/cJ44G0rWhe9vWnv7dDd94+rpf/sq4snYUAREQAREQAUMCSROAn/z3v+c2Pb7qbxVz4OyOo3B6zDSQM/38ypC+jZk8NOJneCW1my8JcHRvwEkrZ+gfmAf/QNvNAclH2jeu2963p/mTL9xwwxO+PEF1SgREQAREICMJJFwALlm9unT9/UuvR0Dm0zCCN5bBwzCeHwkWIZxL9cEHWwWBkowEqk6LwGQEuMK9H6OBA60txj+EOBLIXNaRvr7RtvVrl0faWj/5wi23tEzWvl4TAREQgWwjgEEjrpQLwSgICmH0AeOWr/Nv5oZlKC1uY+NbrsTrww9phdgCiP2VhArAd/7gRxeWVFR+L1hbW8Z0WGN5e/d3+Fe/F6ypsaoOPOjVb+gVEcgCAgO7d1ndEIJuClPS0QZaWiJtGzdc+9yvfnmhm/raVwREQAT8SAACj+JuOqweNhd2IGwWbNq4wf/LqoCVwij48seNf1O/MFvERKMQDMO6YR2wVlgbrB22FcYFdo2wVgjELmxzuiREAB500klvmX30MX+pXLBgPlc/uvHz25u+BODeRPTvbCIwiAwiXdu3xXVK9A/kavj2jRs6Nt/z97P2PPPMPXE1pEoiIAIikGICEHsUb/Nhh8DeMm6vxZYCsBwWgCW7UCD2wCgOd8H+A3sGtha2FaKQQjFnCodSPZfaw17zVMW8+fmMgWbq5+f5oGpABDKQgJfPB39YjWJkvebgQ2sWvPu4v0MA8ot0cwZiyJgu43oxxdC3YHNgHGnwa2HfIuPGKTA+6HphdBngCAhHO/jQ2wNrx4OO02UqIpBUAvj8UNi9AfZu2HtgFHwc3UtXoeapGTdONS4a78ggts3o73psGZh/JewFfE44gpi1JSECsOaQQ/Pp42RZ8Fr3XBIyKOm5F2pABJJCwDDg+b6OTQHJz1rNoYfxg1K2r/38/DrOgX3nQ6EC5kZUcQSBX9TP44s5Vf499DU6FcaHRSYXCsIBGKfGGnENOB22CfYMbANsB5hy6iwjCvo/Dx3laJKb+ycjzs1DJ/n52IPr+KKHNjxXxbXh9OzbYPzcnADjZ6cY5ufCH3oLx+1EbPkDaTfO5TFsH4Q9Aq78zGRVSYgAZHiXvIJEiD98mqOp+l7Pquuok8kAApG+XjtItPeuInbg2MKqxHzovHfIbQsUVQxvcwTMzTlQOPJL+FhYKhfDGKZ3Qa/8W/hdT8FNo6/VkTCndOKPnXjYcaX5Q7An8LDb6bzp0+3Z6Nc3YW7uH5+eSsK6xc/HzbAlCWvRRUO4f+qw+4dhn4AdDcvklZwUsfPH7XRs23B+j2L7V9iD+Hw0Y5vxJSECMJEUIr29iIG2zULAaKuwJJPvn0RSUVuZTICuEf3NWAGMcDDjwi2TTydRfed3D4Wg25IKPyG3fcr0/eloT3sjjOKhZVwM/g1//xMPu0Zs/Vb4gI7n/vHbeSS6PykfxR0XfotxIrx3Dk70CfmkPU5bf2Tc+GPpbvz9B9iT+Hxk7I8Q3wlAgMWDstUKd3dZZTNmWKUz6uwVkACtIgIZRcCOAYhFH/17kCPYdpHIqO4nu7Pxfmlqyi/ZV8ayZuAQJ43bLnwnc7HRrXjQrUz+oY2PEO/9Y3yADN2Rfp8pKbgvuIL307DPw7JV+E3Gch5e/CLsXNiD4MDZjIfw+aCbRUYV+gz4stDhvbehwWrfsN4abNfIiS8vkjo1OQFmAenssDpe3Gj17Nop8Tc5Jb2aGQQ4XcwH/MN40N0J+6/M6HbO9rIvFWeO+4BuGP+AXQnLJfE3ES/9Bj8Eu5cGJidMfDMT/vatAHTgRQcHra6tW63OTS9akW76L6uIgH8JMO1b5+ZNsM0M4OzfjqpnIuCOAP1xPgZ7YFwIvtVdde2dIgL9yTwOrn0l7Aoc458wikCVsfiE7wWIf4DNn2CvyxQovpsC3he4oZ4ei/6BCDIN/8BZ8g/cFyi9nhYCdqYP+PkNws+PsTBVRCBLCRTjvCgEj8OD7ufYXo2pL4aZUfEHgaQJQFzvg3CK18He449T9V0vqKe48nkd7D++690kHfL9CODEPuMGtB3pOzAtTKd6+lipiEA6CfAe7N+zx3ZV4FbiL51XQ8dOIYFKHOs7sKX4Xn5nCo+rQ+2fwOD+347vXVzjd6MmR/0k/vaPcABvc2o8I4pvBCB+RRoDi8E/sGfXLtvHKtzZiXryBzaGpx0TRmAILgm2n9/OHRZX+poW3utu7nfTdrWfCKSBADM63A2B8FmY+Zd4GjqaI4dMuADEdT0R7O6AHZgjDL2c5mpUfsFLA6ms65spYD4QC5DmagTxzWgmhT5WkS2brZKqKiuEaeGisoyMi2tyqtrHRwSiAwNWH/L5cqEHvhyNe+YIP9ZxU8/4ANpRBNJDoAqH5UrIw3Fffw33ObMCqKSeAL+MEjoFjOvJEb+bYcyeka7C+4kjazSutOXUH43nWwSjjuGWVgpLZ/y4v2bS/e8bAUjRx4ciRWB+fr4Vw9Sa0UMSdTgKGIGPYHDadKusrs4qCChUGD4EKgkmwJXpDOkygNAuI0jJZloc4cf9TX/cmLat/UTAJwQ4+ncBrADf2xfhnldE/9RfGIqihAlAXMcj0d4fYNNTcCo9OMZO2BbYtvG/d2PL1IVMY8jzcgQgR4icUSLOYk4UgBwFYn9njm9nYMuRywWw2bA6GP1Yk1E4HXl/MhpOVpu+EYA8QQq+KB6sFIAUgvy3IwynAkDfKz6cOSpTVjfTKp0+HdlJCqaqpvdFYEoCDN4c7mi3R/2i4fCU+0/cwRF/vJdpKiKQ5QQYHy2Ce/3ruPfNfyVlOZQUnR4F4GAijoXrV4t2roVRSCWjUMytgT0Oe3T8b6axoxBMeMH5cFSQfqv1sMNgb4FxJfuhsFmwRLgvrEA7m2AZU3wlAB1qFH20iUKQI4ImhasxGXuNQjA0a5YVqOTshIoIxEeAoYf6mhqtIaxAd1MmCj+N+rkhl3X77sAZcfQiEQ+YqeDwFy+/02kcCQnB0jEdchGOy/P+BUwltQQ8j7xCLPE++hGMIinRhbmn74b9HbYB35PuflHH2Zvx4/BYHFF8Dnb7+HlytPBw2FGwd8LeBKNIjKf8BcdxRibjqZ/yOr4UgA4FRwhyNLCwsNAWhaYPU/oHdm7aNBY2ZibSygUZs1FFBMwIcKSvH8JvsL3d1cidhJ8Z3xzZiw+Dz8Eeg6VCAPIYnBLjA5y+UMz7Ow22YNw42sGH3QEwisNklsvwgH0Gn4cVyTxInG1zlIbTdWSVTaUHJ0PzWk5BA5/22she9Zfh3xxRvB/3BH8Qpb2gHxxVah63ZbhfL8ffHA1kHuPjYf8FOwRm8tltwn4PwzKqpFwA8gFZXF5u8QFrmh6Lo3+s59Y/EBfUDhsT7uqyU8oxtVx+Ef1EVURgcgL07Rto2WP1t7RY9PkzLbw/aSymP1KctvPg8lBaU2PHtuTiEtPRbqe+tr4mMID7IhEP5YScJL4Ty9HQbNjbYcxc8A7YHFiiC6dersHxjsf5tya6cY/tfQ31l3psw2/V+eVDHxNPI2q4Xrxul8BMRA92m7Ksxx7fhd2F+8D8C3XKZhO/A/pHfg2wO2njLI7E3yfD+Fk5ELavsgz1d+3rTb++nlIBWBgoscrnzLZKqmusKMJm2CMsHVhJieneqQouRvz+gXio9zU2jE0LYzSwBA9bPnRVROAlAri/uJiI073DWOXrpuCDb4s/3qM0NyWAH0OhWbOt4goO1sA7OVRu9ezeZUWQUcRtW26Oq31TRsBXXzS4V+nLsGHcbsI9xumuD8DOhB0LS9SDH01Zb4R9GfZN/sNHZRgcEuIr56NzSlRXzkFDr09AY/wi/DXsW2Dttx8ARqeHfndhR/5QYKzLWmw5KngGbBGMLhZOoYC5y/lHJm1T8uXEVbnls2dbtYcdBvEFjnhgFpaUWJULD7BqDj7ECow//EzAcXSFC0VYnBFBk3rcx04rt208rVyvb36Um3Zf+yWJgO0uwPRtWza7En/4grD9VNkt3pduBFtRSdCqXrjQqjn0sJfEH9sphCDka5Xz5ln5cHtQEYFkEsA93AS7Ecfgw+3DsOWwRBbGB3xtIhtMQFuJFLkJ6I4/mhj/MXB+AnrDX9Bfgp2Heysjxd/eDHAe7bDb8fqHYPyh9AsYp49ZdsIesf/KsP8l/QlTBN+7mkMOtfKLiydFw5GPajz0wkih1YfsHqarLJ1pYS4UcesfqLRyk16KnHsxNhTGPddsp28zGYV2AOGLIO7p3kL8GCpDOsMgVqrn7Uvg4Z4Ozqiz3Rci4z92nGNrKwLJIIB7mtNzDOj8T2w5CsRRu0RMDXPk5Kto9xwcY+qpHuyskjYCnOpc4PHoFH+fx7X+ncd2fFkd58WRzWdouKeZCvECWB9eb8M240rSBWABRvr2Jf4cWoBnBRG2JVBViVAuLYizBv8rgwcfLoDtL8X6zmgghSFfn6pwnwGIzjBWeYbwMObxNeIyFbXseJ/31mBbK9IJNlvMKuOm8F6j8f4xuc+ctnlvMTRRGYRdAX4MTXWHjo5iRNGprK0IpIgA7u0IDnUd7u1/Y3st7F0wr+XjaOBq2NNeG1L95BDA9eYIzSc9tk6Bz/A/WSn+9maD89yK1y4Au6TrqL2Pnah/+6rj+UXF8BGcAx/B6rHQG1i8YfKQ5T57xw80daSnoz99rgYR5y1UD/9A+CdyilolOwkwPFBfozc/PzeLPCgWA3tlqpGwy857K5vOCvftenyvfgTn9EvY6R7Pjf5SZ8MkAD2CTGL1t6JtLnjwUm5GZd4vOVXwWRnzScvAs/aVAHT4MaVb9UEHW0NdnVYvH9ZwiDcpfDDT4gkbQ8f/zi1bkFau3SpDWrniULKjJJickfZJFAHeQ1zgwRXh+FVh3CwFHI0/MtwIPx6A93E5Y1FWVRsfTzuKgF8I4L7vwn3/WfSHo0McxfNSPoS2vo82Hb8pL22pbuIJMN9viYdmORr2TVxf8y9XDwdT1cQQ8KUAdE6ND87i8gpM1WK6bs8eK4aVwybFi38gBQJ9BIPTptlTw5zCVslcArEIVps377HvoVHDYOI8W4o+Gotb4cdFT0xJWIrUhMpGYyPU/zKUAD4DfRBun0f3D4C9xcNpzEXdd8Nu89CGqiaBAK4vdcAxHpv+Ce4ViXuPEFNd3dcCkDD4AGVqN04L80FO3y2mfZuq4KZ+hX8gH+Z8kPP1qQoXBAwgDtwQwoLw2PIPnIqY/97nNeS9wkUepj8cnLPgwiIW3ism98tL9XCv2vmoZ9LPL+C8rK0IZDQBfHe24nPAcC73wbxMjXCUSQLQf3cDF/swQHi8ZSMq3h5vZdVLHwHfC0AHDR+oFQiNEaytwVRekx2zzXlvf1s+wOP1D+QCgZf8AzGVZ/sH7u9ges8XBOg60NfUbEX6el31hz8SaG6FHw/CHyj0IS0q8/J8dNVd7SwCKSOAz8Wj+Fz8HgfkaGC85Ui0UYu22uNtQPWSQuANaLXOQ8t34pp2eqivqmkikDEC0OHDByz9A8MIIO0maC9H/2hx+wdu3mwLQPp0FZaWOt3R1kcEovDjtP38MHJLEWdaKPporON2urcI90IIPqMMLq4iAllOgLHPPgFjaJd4yjxUOgT2eDyVVSdpBF7voWX6Zd3job6qppFAxglAhxUfuIFKhI3BVC1TdyU7rRyPyxWkEfoHTp82Fs4Dvl4q6SfAldycsu/HfWASPsjpsSP8+G+KPzeikaFcShHShekF5efnENU2mwng87IRnxFmRoh3VTAXkzA7iASgv24U+nfGW7agIjPLqGQggYwVgGTNBy+n3YIQgxz5GWxvT35auVjUjh8X7oB/IHy95Oifvruefn72SDADiA+6y+zkiD+3wo8pBIMI5MxRPy72UBGBHCPwZ5wv48WNOcq6P/nXua+iGskigO8/Xsf5Htp/Ad+l3R7qq2oaCWS0AHS48UFcuWAhhGCtLQS5itekONPCdPrn1DDFgGn8QK4u7dm50xYgIeQXDsAHTCV1BDgSS9Fveq2dnk0Ufm6ne5mykMLPydvrtKmtCOQQAcby42rPWXGe88H4nsXHUOFC4uSX6GoVaHC2h0Y3eairqmkmkBUC0GHIB3MN0soNjgf7NR0VcoRgPP6Bdh5Z5JAtQciakPwDnUuRtC2vaT9G/OzR3hT5+RUinSGvbVBBwpN2XdVwxhBoQk/XwuIVgDNRl07UZsFdsaNKUgmUo3UvK9cY/08lQwlklQC0rwGc+TkSGKhgWrlm2zfM1C/MiR9IIchRQf6bo4JTFe5D0TnU22P7BpbCLyy/qGiqanrfBQFeQ/p6Mh6k6fV0mo87rAvTt+FaMhSQ0gQ6NLXNZQIYuYvh+24dGBwfJ4cq1KuESQDGCTDB1eiXSYu3ILK+SqYSyD4BOH4l+MAunz3HHrXpw4gRfcVMxVy8YWMoTHobG8bTyo2tDKXPmIoXAqO4dgzr4i19m8m1d3rJaWIuMuLUvlZ8O1S0FYGXCNDxP97CtHA0FX8QoPiL15mZoyMS8v64jnH1ImsFoEODD/CqAw60hmqn2SIi0msWG87LtHA0HLa6tm21Am1t9tShfMacq+Fu+1L6NoR1cVMo4GgUfW79/IrhQkA/P64wVxEBEZiUAKeB4y1BVKSp+IOAlxFACsBhf5yGehEPgawXgA4UPtD5cB+EKOPUMEWaSXGmhTmNWIhRRUcYmtTllHDkxV571WgZR5PgS6YyNQFm7rCn71tbjVZ1Oy16EX6FSPlnZ31BCkCN2jpEtRWBSQl4GfUpQIs0FX8QoAaId5qK9ZQr1R/XMa5e5IwAJB0+2OnTZaeVo38gBIaJPxlHkhwhGI9/4ABEJ3MM2/lhETtO/mST36vM1ctrYud9xiprN8WTn9/06WN+fvLbdINc++YugQGcOvNxxiPkmGA7p547Pr9NOIIXhcU7DazwFz6/wPvrXk5+ELlAo3zOXPh5IWwMfPbChlOMFIKe/AMbxo5lZ45g2BhMU6qMEeA16IefX6Tf3eDCxFE/N35+PKqdvm3WbIvZPFREQASMCVD8Tb06bvLmWG9k8rf0ahoIOAIw3kMviLei6qWfQE4KQAc7H/xpSSvHsDHKHWtfhmGmb3Mhwp1rN1H4ufXzU/o2h6K2IhAXAY78xfvrleKPAlLFHwQ4mkuL1+n5Tf44DfUiHgI5LQAdYE5auYFWpBNDmBG3aeUc/0DTsDE8Lke8hrq7rdLx6cdcyyoxEonYrAfazKbhnWvlCD/+263wY/o2exp+utK3OTy1FYE4CDDGVbx+YxKAcQBPYhWusKPVx3mMt2DmpQbfyx1x1le1NBKQAByHz7RyXKhRgmC/TqDhEfikTVX29g/kvylMTKYjmcqMgpNisGzmzJxIK8dzHuxox3Qv0rcZLsRxroEj/sjWhK9TLx/XlunbeH1zTWg7DLQVgQQS4Gq2eEcAI6irlaMJvBgem+pD/RbYa+Js5wDUezvs3jjrq1oaCUgA7gWfAqFi/gKrhGFjMDXJUTqTQkESr38gRxzttHLIZVyG3MYUodlYhrq7EIqnyTINxeMwmCj83I76cfV3CH5+xSEvwe6dnmgrAiIAAl4+TJxudOfoK+RJI4Dv1hE8uzbiAO+K8yAcCT4HbdzHtuJsQ9XSREACcB/gKRhqDj7EHp1zE4SYAoUWV1o5LICIbB73D8yixQlM30bhx5E/DN3tg/irX/Yi/F7y89Nim1eD1Ssi4I0A88fGWyj+KAJV/ENgNbryWQ/deR/qLoI97KENVU0DAQnA/UEfzwjBQM5MQzbQ0mLFhs1mL+ING8PucEqYo2Sl0xieBGFj4LuWiWUErMisH+xMwu045+gIP/7b7YhfAVZ4M9RPqcLtODi1FYFEE6jz0CAFoEYAPQBMQtXn0SYD48Yb048uAd/HKOBqfHebTZkl4STUpHsCEoAGzBi3j9OInJrlSFYYI1mc8p2qcB9OC1PQcESQ/6agMalLwWSnsEOOYfqu0YeNfoqZUOjnx9R7HDlNlZ8fGTOsTwhT6Aq4nQl3ifqYwQTmeuh7M+q6C/Lp4WCqakRgHfZaD3uz0d6T73QUXr4cz7Yv4rt4auf5ydvQqykmIAHoAjiFRdUBByCtXK29UGSop8eotiMEuVqYQtCZJjapHEVWjO4d2+3p03L6smE00s+FI5cUfqa+k865UMDRHJHsvG6yDYAJRbLSt5nQ0j4iED8BfD75K/Sg+FuwduFzPvWvZw8HUFV3BHA9+nFdH0ItLwKQBz0P1oa2/hdtyh+QRHxeJADjuEAUGhQdg1i04WaUyxF+cfkHQlh1vLhxPH7gLIs5jv1UONLX39yMVHtI32YwOur0naKPxjpup3uZvo1BtTk6qqDaDlFtRSCpBGag9QM9HGGbh7qqmjwCf0XT58PinQZ2evYt/FGJ7/NL8L3OFcYqPiYgARjvxYFoCSJvLMUgfdwGkcIs2f6BFEmDmFrlyGMZfNzo68asJsaFIgtTy1x1bPvkOUIN58JpbsbJs9PU4d+mhe0wfdsAUuuZnr/Tdrzp2+jnF2T8RPr5uTl/58DaioAIxEvgjag4O97KqMcVpyr+I/AUuvRv2HsT0DUKycPwvLoIIvA/CWhPTSSJgASgR7B2WrnZc6wg08ph6pO+bxRqUxXus3fYGDf+gb0IUcNVtXZauZoaO8/xvo45jNXFnJKN9PZYXJHL+Ib005tYmCeZ8fI4zV1cXmEL26Kysom7vPJv9D8M/8Q+jPqxfTdl4qifCSunbdZj0G6es/z8HCraikBKCZyIo8UbBLoXdV9MaW91MCMC+G6N4rv4eux8HCwRzubHo51laPP/sP012mewaRWfEZAATNAFGfMPPNAasvMLM6et2ei3My0cl38gpl27tm21AuNCsLi8/OWzgUAb6um2V+FyxHBvwffyjmN/8f0YDSt3uT/FLKe5OcoYqKh8xRTrcF/fWPo2wxiJzrEmCj+3073FZSEsxJllBaqqnOa0FQERSCEBPMyn4XAUgPGW3ahIU/EngX+gWw/C3peg7vF++THsdNw7V2P7VzwDlDEkQXAT0YwEYCIoTmiDAoVCbLC9zfaJ4yIOk+KM/jlp5RxhaFLXHt2DaAsibEwIGUWQJ8Pqa+AIYfyfNXslb1eXFYYFOeqGUU4KOGYuYcq8qQTlxH57EX6FCMzNLClBBObOlFXQE89df4tAFhH4AM7Fi//fc/guUJgQn94QuDYRCLUfoHvHwhLpZE63gRthX0H7f8D2b7B1ON7UU2XYUSV5BCQAk8CWQoVx6AJV1WPxA+EjZ/vcTXEsfDisifEDKZwcYThFVXvamcKM07IsJsebqk3nfcfvkAstGNvPTYnXz4++iMyTTI70TVQRARFIHwF8N3FxwGc89kCBgj0CTHZ1PHNW4FpfheNckoRjHYY2vw/7Bmw5jnMvto/ANuG4UWxVUkxAAjCJwClcyufMHYsfCJ+9MKdMIfKmKhSCe/sHUhialEQKv4nHc9suxSuN50IzLqhTMp6+bb8+iMYNakcREIEEEPgw2jjaQzsc+XvcQ31VTR0BTtseA+NIYDIKUwl+cNzoK/UcnhErsF0JWwPbLUEICikoEoApgEwhU420ckOYTuXiDdNFE840cDxhY1JwWpMeYqLwY//dFHJirEP5+bmhpn1FILkE8HBmcnKOCMW7+IMdfAKmBSAk4fOC7/AeXPMl6OZ9sAOS3F2KQYpNGgsXi/wHx38S21WwF2A70CczXyrsrGJOQALQnJXnPR3/QCc9GsOxmBRnWtjxD+S/8QExqZqyfRzhxwO6FX4cKXXC2sjPL2WXTAcSAVMCl2HH15vuvI/9/oTvCE3z7QOO317GtdqIZ8zZ6NedsOkp7F81jvXOceNhuXJ8wwRB+Dz+vQX9Uz5p0vFYJAA9AnRbnQKnDOnKSqqr7VRvDCZtsqCCgs8Rgm7Tyrnto9v9HfHHPtJMC0PPMIhzCFk8ChDUWUUERMBfBPB55kjQeR57tQv1/+mxDVVPMQF8rz+C638GDnsLzEv+Zy89Z2iL/zduX8B2ELYZ/eIIIV0KnoXRh5BCUcUlAQlAl8AStTsFT+WChbYAYn5h09RpFFiOfyBHBE19AxPV773bYR/YJ7ejfgygzby9jDmoIgIi4D8C4w//n6FnXp8Tf8ADutF/Z6geTUUA1+1B3AefxH6/hS2Yav8UvB/EMTgaTTsXxqnh7ejjU9hyyvgZ2Ab0m1PJKlMQ8PrBnqJ5vT0VAQqgGoSNCXd02rH3hgfMRrbdCq6p+hHv+277UYQUdmPBqznSnxfvYVVPBEQgSQTwMOVz4cuw78G8Ds23oI3fwFQylADE1HLcEyei+9fDOD3rpxJAZw4dtzOxZZiKBvR3Nbb0O+V2HawV52E+PYUKuVAkAH1xlccyXBQj8PIA0srRR9BtWjVfnMZ+OsH0bQwqzbAudrq5/eyrt0RABNJDAA/O1+LI34V9NEE9+C0evFsS1JaaSRMBXMP1uDdOxuG/D2M4oKI0dWWqw7JfC8bt49jGYHtgz6D/HCG0VxrjfNrwd84XCUAf3QIURiGsgi0ZzyYSRoYP3LQ+6qH7ruCDZp8Ps3gUys/PPUDVEIEUEMD3zCE4DKfUzoExg0MiyiY0cmUiGkpwG5n9pZpgGKbN4buc06pfwL3yILY/gL3GtG4a9yvAsWeN2wexpSDkCCHF4MOw5bDNODd3IStQKRuKBKAPryKFUtUBB1hDtTVIuYa0cki9lomlODSevq2yKhO7rz6LQFYTwEMwhBM8CkYfL47uJEr4oSmkI8JoER6sHH3xWykbP3eKg0wv9KMZBOeUhUnBsf4Gfo/huBfAPgtL5H2D5pJaeM3njdup2PbAHsf53IvtfTi3rdjmTJEA9PGlDkA40UdwsI1p5Zos07Ry6T6lsfRt9UhNh/RtWCSiIgIikH4CeMjx4ceQHm+CHQc7HvY6WDI+pLej3T/C/Fh+gU79EJaM8071+fKa/gTGXLspKxBKrTjYt3BP/QlbCkG6DNCxO9MKVyG+d9z+F+dzP/7mfbsc58gVx1ldJAB9fnkpoOg7V4Icw/3wDWS6N7dZOVJ1imPp22Ygpt8MKx+x/VREQARsp/SUYsBDjN/rAVgtbDZsLoyi7y2wN8IY0iOZK7DWo/2v4AFKh3w/Fp4/LVtK2oQXrvEaQPw07rkrsV0CoxCcA8vEwpHMxTAuJuGo4HXY3oNz7MI2K4sEYIZcVgqq8jlzbCHYvXWLNTyUshF/I0JFgYBVecCBVhGmfVVEQARsAhRZ38CDZOc4D/oZ0eiHNHHrvL73ltOozmv8e6KxbUfo8dcWBR99LSgGaBQ49H0qg9ExPlWlAwf6PB6ajak6oI5j3yNpxYDrvRYduAD3+o+x/TCMbgWM3+d1FTmaSHnhZ+vt4/bCuLj9M87RLERHyrsb/wElAONnl5aaFFjFCBvjNwHIPkn8peWW0EH9S4APkg/4t3sJ71kfWlyCB+XyhLesBjOCwLjwvxai6QZ0+K0w3v/vhTFuXxCWaeUN6PBvYRzl/BHO7x+ZdgL76282+EDs7/yy8r0RH64M9mOfsvLi66REwJ8EKP6+gAfkXf7snnqVSgK4D6KwJ2DfwXHfOW4XYXs3bBcs09ICvgN9/jtE4K9h8/F3VhSNAGbFZdRJiIAIiEDaCOzGkT+Dh/0/09YDHdi3BHBfRNC5p8ftSggo+qYeDuMUMada3wabBfO7HuGCm0/DjsM5XILz+iP+zujid+AZDVedFwEREIEsJ/AUzu+zeBg+m+XnqdNLEAHcK+1oasW4OYKQMQUpBI+GURj6WRAuQP9+DxHIhVWX4Xwy1jdQAhBXMNMK8+/6rfixT35jpP6IQBYR4BTeNTDG+uMDXUUE4iIwfv88iso0Jj/gCCEF4ZEwRxDW428/6RX25WuwQ9HfczP1M+AnoGCpYkKgACtu/Vb82Ce/MVJ/RCBLCDCLAoVfVjnEZ8m1yfjTmEQQMjzLZIKQU7LpLiejA+UQgf+Nfu9Od2fcHl8C0C0xH+xfFCq3cLP5Jk0c+8I+qYiACGQ1gQ04u5/BbsNnvj+rz1Qn5xsCuNfa0JlHxo3Pven4e29BOBOvpUsQvhvHvg39+hj62oq/M6ZIAGbMpXq5o4XBoB1oOeaTWICMUcg+qYiACGQdAcYhXAm7CcaguHwYq4hA2giMi6x/owM0CsIZ2EwUhEfg36kWhFzpfAP6shj944r4jCgSgBlxmV7ZSWbcCFRUICuIP35ssC/sk4oIiEDWENiGM1kKuwv2KB5qQ1lzZtl3IqkM9O07erg3W9Ap2nIIMMbe5Ajha2FcYXwsjIKwBpbswgDYl8K+kuwDJap9PbUTRTLF7ZRU1/hGALIvKiIgAhlNIIzeb4I9BrsPthIP1mxd3PE3nN9mWLqmDHHohBWew4qEtZbhDeGeZbYcRxAugyC8HP+eC2Mcvw/A3gPjiGGyyhdwTOYRvjdZB0hkuxKAiaSZwraKkRGkqKzMGu5PrysO+8C+qIiACGQMAaai64Ftgf0H9jjsSdgmPLjS+4WCTqSg/Arn+UAKjqNDpJkArjPv9e3jdivEGYM4vw92OuwYWKJDajD13RU4zpM4NoWor4sEoK8vz747l1dQYIVm1ltdyAuMm23fOybxHdzgdh/YFxUREIFXEaD/3G9gHEljbl7m6OVwOcNcVMHoOMsl/fwe5oeIxiksr4UhWmgRWBdsF2w3rAHGkS8u5qD424PPcC5O7TJ3skoOEsD9vgOnfT2emb/F9r9gn4N9CJbIhxiDXLPdy2C+LhKAvr48++9coLraClRVWeHOzv3vmKR3eWz2QUUERGCfBG7GQ4eLKOyCBw+/cylAOFJQBuPy+dLxv7l1jO9xHxr3p00UiBR3wzBnSyFHsUfrhfXBOMpH8dmHPnBfFREQARDA54GfmwfxeXwI2+NhF8PeBUtUOQ9t/wHH4Q8t3xYJQN9emqk7hpvLqpg7z4oODlrRMF14UlcKS0rsY7MPKiIgAvsk8Iqgnfi8OKNzA6jRsc9aekMERCDpBPB55PTZAxBrK7D9POxbsEqY18JVyGfD2J5vS6Lnv317otnaMQZgrly40MovSt1CMB6Lx1Tw52y9q3ReIiACIpA7BCAEB2A/wRlzOnhjgs78FAhLX6+QlABM0JVOZzPFCMJcdcABKRGBFH88Fo+pIgIiIAIiIALZQgAi8BGcC7N7rEnAOR2CNk5IQDtJa0ICMGloU9twoKLSqj7gwKSOynHEj8fgsVREQAREQAREINsIQARyBPB0GBdPeS0Uk74tEoC+vTTuO1aMgMw1Bx9iBcoTPzrHNtk2j6EiAiIgAiIgAtlKACKQ4ZHOh3FxlZdyJKaBkxl30EvfEh4Dx1NnVNk7AaZkq4ZQq5g3zyoofoX/eVyNsw22xTaV7i0uhKokAiIgAiKQYQQgAv+OLv/OY7fnof6bPbaRtOoaAUwa2vQ1zLh8ZXUzrdrDD7dKpzErTnyldNo0uw22pVh/8TFULREQAREQgYwlcAV63uKh9wzddISH+kmtKgGYVLzpbbyguNgqnT6dMY9cd4R1gqjLNlREQAREQAREINcI4DnIOH63ejzvN3isn7TqEoBJQ+v/hvPz8y2aigiIgAiIgAiIwKQEbserjNsZbzkUfoAM7O67oqe/7y5JYjuUniRxiT0HtSYCIiACIiACaSLwHI77godjcxFI/L5YHg48VVUJwKkI6X0REAEREAEREIGcJIBpYKaNe8TDyTNumi9jp0kAeriqqioCIiACIiACIpD1BJ7ycIbM5z3HQ/2kVZUATBpaNSwCIiACIiACIpAFBDbjHOL1A6TOkgDMgptApyACIiACIiACIpBbBNpxup0eTjnkoW7SqmoEMGlo1bAIiIAIiIAIiEAWEOjBOdDiLbXxVkxmPQnAZNJV2yIgAiIgAiIgAplOgAtBaPGWafFWTGY9CcBk0lXbIiACIiACIiACmU5gBCcQ83ASrO+7IgHou0uiDomACIiACIiACPiIALUS07rFW/bEWzGZ9SQAk0lXbYuACIiACIiACGQ6gSKcAC3ewkUkvisSgL67JOqQCIiACIiACIiAjwgE0JdiD/2JN4SMh0NOXVUCcGpG2kMEREAEREAERCB3CVTg1L1k8/Cygjhp1CUAk4ZWDYuACIiACIiACGQBgSqcA0VgPIWrh3fFUzHZdSQAk01Y7YuACIiACIiACGQygdnoPKeB4yldqNQST8Vk15EATDZhtS8CIiACIiACIpDJBF7vofPMINLhoX7SqkoAJg2tGhYBERABERABEcgCAm/2cA6tqNvroX7SqkoAJg2tGhYBERABERABEchkAqOjo0zj9gYP57AxLy8v6qF+0qpKACYNrRoWAREQAREQARHIcAJvQf8P8HAOT3qom9SqEoBJxavGRUAEREAEREAEMpjAieh7vFlAhlD3Ob+euwSgX6+M+iUCIiACIiACIpA2Apj+nYmDf8RDBxj+ZbOH+kmtKgGYVLxqXAREQAREQAREIEMJfAz9nu+h70/B/8+XK4B5ThKAHq6sqoqACIiACIiACGQfAYz+TcdZne/xzP7msX5Sq0sAJhWvGhcBERABERCBzCAA0ZMHky4Yu1xfxuZQD1duJ+o+4qF+0qvqQicdsQ4gAiIgAiIgAhlB4BD08u8QgYth5RnR4yR0Euf+HjTrdfRvGaZ/m5PQvYQ1KQGYMJRqSAREQAREQAQymsD70fsPwn4PexRC6AJYXUafkcvO43znoco1MC8CmKt/b4b5ukgA+vryqHO5SiDP4n8qIiACIpAaAhA+xTjSRycc7Y34+yrY43jvCthbYfGGQ5nQrH//xPnVo3e3wg7z2MuHUH+FxzaSXj3pAjA2NGSNDA8n/UR0ABHIJgKxobA1Eotl0ynpXBmX9xkAAByGSURBVERABPxNgILviEm6uBCvfRX2KOyfEEnnwBgeJasKzulAnNCfYMd4PDF+cV/j1+wfE8+tcOI/kvH38MCA1b5xgxWaOdMK1k6zrDyNaySDs9rMDgKj0WFrYM8eq7+11Yrph1N2XFSdhQhkBoEPo5vB/XSV7x03bjsgmDjK9Q/YCogd5rvN2IJz4XldCzs4ASdxP9r4VwLaSXoTSReAPIPo4KDVtW2bFe7stMrnzLUKg/u7x5J+zjqACPiSQKSnx+rZtdPijyYVERABEUgVAQgg+rud5OJ4jI137rhtR32ODlIMctsEQTiKre8L+j0DnfwK7HOwUAI6zJh/38b5RxLQVtKbSIkAdM4i3NVlP9zK58wZGw103tBWBHKcwGBjo9XT3KRp3xy/D3T6IpAmAkfjuIfHeewFqEdbDGuCrYGwegzbFbAXIIbasPVVQf8Y4+80GIWfV3+/ief2E5zvcxNf8PPfKRWABBGLRKzu7dut0diIVTqD4ltFBHKYwOio1bd7l9WHaV98KeUwCJ26CIhAGgkw40Ui9AAXUdBOgPELjVPFL2D7PIzb/8A4QtiNbUoL+sGpxzfBmNqNdhAskWUZGrs6kQ0mu61EXHDXfRwdGbGnunATWMHpFOIqIpB7BOgN29fQIPGXe5deZywCviEAYcQwL+9NQof4Fbdg3D403n4ftrtwzE3YboTtgG0b39KPsB8WhjbwtAIO7XOBayWMo0wUfVzYcSSMC1242jnRZSsaPA/95vllTEmLACQdisDunTusgkCxVVzB66QiArlFINzWBvHXrJG/3LrsOlsR8BuBRejQ/BR1in52nGree7p5EK9xqpjWBQHXhW07jKKQ2zBsCEbfOm5pFIlFsBJYAFYF44gSVyjPhTGe3ywYj5nM0onGz4X4ezGZB0lG22kTgDyZsZHAXVbNoWVWfmFau5IMtmpTBPZJIBYOW92Y+h3BDyEVERABEUgHAQgtjtKdko5j73VMTs9StNEyqXDE7wsQf8szqdNOX5MeB9A50L62XPHYj1EQFRHIGQLw9ett2K0wLzlzwXWiIuBbAlwAcbxve+fvjnHF71kQf3/0dzf33bu0C0B2baClxQ4Vs+9u6h0RyB4Ckb5eOyRS9pyRzkQERCBDCXAq9YkM7Xs6u92Eg58O8XdXOjvh9di+EIAj0ag12JbRcSS9XgfVzyEC4c4u+f3l0PXWqYqAXwlAwHDxwgdhn4I949d++qxfDHHzQbBb6rN+ue6OLwQge80YgRSCKiKQzQR4jw91079ZRQREQATSTwBCZgh2C3rybthnYE+mv1e+7AEXnVwD+xB4ZYVY9o0AjMIpPtLb68urrk6JQKII8B7nva4iAiIgAn4iAFHTDbsRfaIQ/Cjs7zCGZVEZi194GvicD6PvX1YU3whA0pQAzIp7SiexHwK6x/cDR2+JgAiknQAETj/sr7APozPHwn4AWwvLxZAFFHuXwd4NHndgm1XFV7FXomGGAlIRgewloHs8e6+tzkwEso0ARA+nOp9BuJgrsD0a9iEYVw0fCPPVABL6k8jCeIR3wq4BA4rfrCy+EoBMEzcai1l5BQVZCVsnldsEeG/zHlcRAREQgUwiABHUg/5y0cNSiMEabN8KY7q398AOhiU72DIOkZKyHUe5DfY7nHPGBXZ2SyghAjAvnz8EGE+Sqf88FMRHw81lt+ShFVUVAV8S4L2NGzwBfcuzxj5zGf1RKYoTBOvxyyaVJd6+8osxm0dJUnkN9j6Wl1ECXZO9abr4N4QRp0UfpOE7jVk4mNWDadbeBaMwnA1jYOdMKQxBsgz2V9hynF/OBCZOiABs37h+tO5Nb80bGcYIXkIecJly36ifIpBaAvhysvKLiq09z62hkhxI7dETdjT2/XkYV9XRTAsf3Lthw6YVErAf+/c0jCMgbvpKkUqfKS35BoQklJ1ok9fFTegI54cDBYxKAgjg+4gr2p4dt+vw/Gde10Nhbx63N2C7EFYNC8D8ULiwZTuM8Q8fhT2C89iKbc6VhAjAtnVr3xasmXZn5YIF80cwzTUyHO/3s/P5zLnroBPOGQLx3+P5RUVWPtwj2jdu6Njx8ENnA9mmTMSGL1t+QZyNh0VcMFA/EcOoRuhwLD4sTo+nr6nsp9HJZNFOYHsDrsmv4zklXZd4qJnVAdtu7MkwMnYoGVwjjtTWw+bCFsKYeWT+uDFPL/P3crSwFJbokVn+YGNoEfrzbYGth62DPQPbgL7ys53TJa4v4H0Re+cPfnRhSUXl94K1tWWMd+Y2rl9BcbE17TWvxQhHvDMu++pZ7r4e6euzOjasn3RkNt+euscwxST5aPHhsGoOO8wqDpXnLrwEnzl/GOHHkms/QObJpiFjTqRt44Zrn/vVLy9McNfUnAiIgAiklADEIUcLOTJIEUi/wtpx42sVMPoVUhg6ApHCgIKSRrE4NG4chaRzNfPytsP2wDiN6/zdOC5M8ZLKRAIJFYBseMnq1aXr7196fWhm/WlFZWUF9sKOSQTGxE5M/Lt0+nQrNGu2RTGo4p2ABKB3hologZ+DvsYGa6DVPOMN/fz4OcA1HG1bv3Z5pK31ky/ccktLIvqjNkRABERABHKbQMIFoIPzk//+99zGFSvvKp87/4j8/Ly8GKeFDf0DCwIBKzRzphWcNt1xdnea1dYlAQlAl8ASvPsofvwwzWFfc7MVG+IPVoOC0dcCjIKPxEYwertu60Bn+2nPX3edPaViUFu7iIAIiIAIiMCUBJImAJ0jL/rB5R/ILwncVFY/a4Zb/8DiUMgK1c+yAlUcKU56V50uZ9VWAjBdl3PUGurqtvqaGjmCZ9wJx8+vZ+eO3s4NG772/M03XWdcWTuKgAiIgAiIgCEBzqUntWz/10Ob/nvp0T/bcE9vLK+g8OiiUKgwDyOBmP+f8ricNgt3dljRwUGrIFCsaeEpib16BzIcbKMP7KsL/fxYJrsWfC84bRqY+2Xh1qv779dXhvv7rN5du+wpX/I3KVzckY+R76GurmjLM0/fFAg8duwTV/1Vo34m8LSPCIiACIiAawIpHVY769lnqzbfe/9vKmbP+TAEXT6d4jlFZlL4gKR/YFndTCtf/oEmyOx9NAJojMrzjiMQe/17mm0/P452mxT6+XHULzoUGW1bu2ZVNDxw2rO//OUOk7raRwREQAREQATiJZBSAeh08iO3/+Xwrt3b/lJeP/uwEYwE2mFjDEYEWb8QoyRl8g90UE65lQCcEpHnHRw/v374+UVd+PnZ070Yae3curmpb3fT4mev/+XDnjujBkRABERABETAgEBaBKDTr3f9+CdnFAZLf1E6rbZmJIr4gVGGBzMrDE8SmgX/wEr6B6rsi4AE4L7IJOb1oW74+TXSz4/hpsxKfiHi+RUWcGHIQNfmTZc9c+01V5jV1F4iIAIiIAIikBgCaRWAPAWEjSnatPTBH5TMqLsAYWOKORroZvqspLraXihSGGSoIJW9CUgA7k0kMf+mXyoXeIQ7O125MXDUL9LbG+tYv+722EDfkqdvuCFTs3kkBqRaEQEREAERSAuBtAtA56whBKe9+NCym0Oz6t+PxSKu/AMZMoP+gaUz6hRE2gE6vpUA3AuIx3/yB8pAyx7bz88ObWTQnuPnNxKLjnasX/+0BT+/x6+8crNBVe0iAiIgAiIgAkkh4BsB6JzdB2+5/Y39zQ1/Lp81+xDbP9BwFSXrF5aUIH5gvVVSW6v4geNAJQCdO8vbln5+4fZ2TNs2WdEwA8+bFS5YQhhMq3PL5ub+5pazn7n2F/80q6m9REAEREAERCB5BHwnAJ1TffePf7K4sLT05yXTplXb08JILWdaAuUVVtmseitQIf9ACUDTu2bf+w31dFv9jU3WUG/Pvnfa6x07fRtGpvubmgbh5/fdp6+95vK9dtE/RUAEREAERCBtBHwrAEnkrGXLSnY8/dxP4Oe3pCgYLGKYjcny1k5Gj9NuyEkM/8B6xBAsmWyXnHhNAjD+yxwbCsPPr8kaxMifcbgihnXBqN9wf/9Ix6ZNdxdasU89dsUV5itE4u+uaoqACIiACIiAMQFfC0DnLD69Zk3dlvv/+SdkEzk2L78gbySC+IGjZvEDmUuVYWNKp8/IyWlhCUDnLjLfUuwNtLZYDOtiGsg5L4/Cr8gajUWtzk0vroV4PGXVFVesNz+q9hQBERABERCB1BHICAHo4Hj/jTe+Y6in99ayuvr5fEjb8QOdN6fYMq0cg0hz1bA1ngFjiipZ8bYEoIvLiFiUXNXLYM7kZlq4spcjzj07t7f3Nzact/rqq+80rav9REAEREAERCAdBDJKADqAjr38ii8Eq6ouD1RVh+xpYRf+gSVVVXbYGKSkc5rL6q0EoNnlHYbgs8O6dHWZVcBetp8fRpjDbW2R1g3rf/bsNb+42LiydhQBERABERCBNBLISAFIXuesWFG+7cmnrg7W1J5RWFxSGIsMmftpIa0c89xyRLAAmUWyuUgA7v/qxpC5gyN+zJfsJv4kcyQjbdsIVvc+VDgSO/PRH/2odf9H0rsiIAIiIAIi4B8CGSsAHYRnr1kzd/v9D9xZNmv2/8uzRvPs2GyGaeVywT9QAtC5U165jcfPj64DjDnJ26tz84ubR0aipz7+ve89+8qW9S8REAEREAER8D+BjBeADuITrr32/daIdVOwdvrMGFLKufUPDM2anZVp5SQAnTvk5e1Y+rYG135+BUjh1tfU0NO9c/uFq6+66qaXW9RfIiACIiACIpBZBLJGABL7u5YtKyx8fs03ikpDlxSVh4K2f2AsZnRF8jC6U1JTY4eNQX5iozqZsJME4MtXKTo4YId1CXd0YBQPw3gGJR/uAgzrMtTVFe3etvXGkve/9/zlixaZB6U0OIZ2EQEREAEREIFUE8gqAejAO3ft2pot9y29PjRjxkfzCt2llaNjP0PGlNVlR1o5CUDLHg3u38P0bS3WiOGCoZfSt0WRvm3jxhWBytDpy7/+9d3OPaatCIiACIiACGQygawUgM4FOX3VqoObVqy8E2nl3sAA0va0sOHID9PKMX5gsHZaRscPzGUBSD+/wfY2O56fcfo2jAQzrEs+wrp0bH5xZ3Q4cvqq733vMeee0lYEREAEREAEsoFAVgtA5wKdcM2vPplXUPDLQFVVzchwFKNAw85bU26Ly8vtsDGBysxMK5erAtD282tqtCK95kk48uHjl19UaA22tvZ379j+7Sd/+n9XTnmDaAcREAEREAERyEACOSEAeV3O37QpsO7u+74bqK78cmFJsJgZHjhCZFLoH8iRQI4IFgaDJlV8s0+uCcDo4KA94seRP1M/P073ckX48EB/rPPFTbcf9v4TPn3zokVh31xEdUQEREAEREAEEkwgZwSgw23x88/P2P3Aw78rq69/L4Qd0spBCBpOCzMESOmMOtgMOwiw06aft7kiAOnbN9DSAttj2aGADC4KhT0XeOD6j3Zu3PjMaHHBJ1Z++9tbDKpqFxEQAREQARHIaAI5JwCdq3XKPfe8rXvH7ttKamsPpHhwEzamqLQUo4H1WDVcjdBw+U6TvtxmuwBkTuhwB9K3NTdhBG/A+BrYfn5Y8NPXsLsl0tdz7opLL73XuLJ2FAEREAEREIEMJ5CzAtC5bidce/0ShPq4oriisnJkOGK8SpT1AxWVVmjWLIt+gn4t2SwA6d/X19hoDfV0G+O307cVIX1bR3u4Z9fOy1dd/sPLjCtrRxEQAREQARHIEgI5LwB5HZesbizd/MgdPw1UV51bFCgpcuUfCP+x0mnTMSJYh7RyJb67LbJRAMaGwhjxQ1iXtlZzP07Hz29wYKRry9Z7qmYe+qn7v3Rmj+8umDokAiIgAiIgAikgIAE4AfKSdevqtyx98M+ldfXvQGJY92nlkFu4dPp0CyuOJ7Sa3j+zSQCOIqj3QGurnbuXIt2owM+PvpuI5WN1bdm8rqAw72PLL7lkg1Fd7SQCIiACIiACWUpAAnCSC3vyrX86brCz46bgtGlzuaDAlX9gWZkdNqakqgqiI/14s0IAYpFOuKsLWTwareH+/kmu2OQv0c+P4q+voaED2T++9NgPvnvr5HvqVREQAREQARHILQL+GaryEfeNf7lz6+K33fvzHfmP9iCA9DHFZWVcKmq0Wphicaiz0xpG2rFCTAkzvEg6C0fKBtvaJu0CV8GyTLYKmu9BAKP/gUnrpupFCr6enTusfog/01E/pm9jIO9IT0+ka/OmKxdFLz7hlu+9+4VU9VnHEQEREAEREAG/E0j/EJXPCS1ZvaVyyyP3XoPVwqdhNKnAjX8ghUiQ/oFIK1cQSI+QytQRwNjQEKZ690C8tmI23jCf87ifXzQSGe3esuWhiunzzrj/S+e0+vwWU/dEQAREQAREIOUEJAANkZ/z1AsH7Fr16F3IE/xGZBPJizGbiGn8QIwCMog0F4uk2j8w0wSg7ecH0dff3Gw84sep9gJm8SgssLp37tiWN5J3yrKLv/K04aXVbiIgAiIgAiKQcwQkAF1e8pN+e8uHI0Ph6+DjVxeLwD/QTVq5spCFANRWKv0DM0YAjvv59Tc1WZH+PuOrwvRtBcVFDALdgxRuX13xvUtvMK6sHUVABERABEQgRwn4O4qxDy/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; -} diff --git a/vendor/QmdDfkqDWheE4gsCXNrhixwTwSHnZMPT2cGLcNbiBNcMyU/dir-index-html/knownIcons.txt b/vendor/QmdDfkqDWheE4gsCXNrhixwTwSHnZMPT2cGLcNbiBNcMyU/dir-index-html/knownIcons.txt deleted file mode 100644 index 6615f9c3961..00000000000 --- a/vendor/QmdDfkqDWheE4gsCXNrhixwTwSHnZMPT2cGLcNbiBNcMyU/dir-index-html/knownIcons.txt +++ /dev/null @@ -1,61 +0,0 @@ -.aac -.aiff -.ai -.avi -.bmp -.c -.cpp -.css -.dat -.dmg -.doc -.dotx -.dwg -.dxf -.eps -.exe -.flv -.gif -.h -.hpp -.html -.ics -.iso -.java -.jpg -.js -.key -.less -.mid -.mp3 -.mp4 -.mpg -.odf -.ods -.odt -.otp -.ots -.ott -.pdf -.php -.png -.ppt -.psd -.py -.qt -.rar -.rb -.rtf -.sass -.scss -.sql -.tga -.tgz -.tiff -.txt -.wav -.xls -.xlsx -.xml -.yml -.zip diff --git a/vendor/QmdDfkqDWheE4gsCXNrhixwTwSHnZMPT2cGLcNbiBNcMyU/dir-index-html/package.json b/vendor/QmdDfkqDWheE4gsCXNrhixwTwSHnZMPT2cGLcNbiBNcMyU/dir-index-html/package.json deleted file mode 100644 index d0d6cc58346..00000000000 --- a/vendor/QmdDfkqDWheE4gsCXNrhixwTwSHnZMPT2cGLcNbiBNcMyU/dir-index-html/package.json +++ /dev/null @@ -1,4 +0,0 @@ -{ - "name": "dir-index-html", - "version": "1.0.0" -} diff --git a/vendor/dir-index-html-v1.0.0 b/vendor/dir-index-html-v1.0.0 deleted file mode 120000 index d97f32b013a..00000000000 --- a/vendor/dir-index-html-v1.0.0 +++ /dev/null @@ -1 +0,0 @@ -QmdDfkqDWheE4gsCXNrhixwTwSHnZMPT2cGLcNbiBNcMyU/dir-index-html \ No newline at end of file